diff --git a/.config/lychee.toml b/.config/lychee.toml index 733b77ec0cff9e616ecc0f851d9a3ed5e8574636..b7b5b83f35bc57a835034d15334fa7a3ed933d51 100644 --- a/.config/lychee.toml +++ b/.config/lychee.toml @@ -32,12 +32,10 @@ exclude = [ "https://github.com/paritytech/polkadot-sdk/substrate/frame/timestamp", "https://github.com/paritytech/substrate/frame/fast-unstake", "https://github.com/zkcrypto/bls12_381/blob/e224ad4ea1babfc582ccd751c2bf128611d10936/src/test-data/mod.rs", + "https://polkadot-try-runtime-node.parity-chains.parity.io/", "https://polkadot.network/the-path-of-a-parachain-block/", - "https://research.web3.foundation/en/latest/polkadot/BABE/Babe/#6-practical-results", "https://research.web3.foundation/en/latest/polkadot/NPoS/3.%20Balancing.html", "https://research.web3.foundation/en/latest/polkadot/Token%20Economics.html#inflation-model", - "https://research.web3.foundation/en/latest/polkadot/block-production/Babe.html", - "https://research.web3.foundation/en/latest/polkadot/block-production/Babe.html#-6.-practical-results", "https://research.web3.foundation/en/latest/polkadot/networking/3-avail-valid.html#topology", "https://research.web3.foundation/en/latest/polkadot/overview/2-token-economics.html", "https://research.web3.foundation/en/latest/polkadot/overview/2-token-economics.html#inflation-model", diff --git a/.forklift/config.toml b/.forklift/config.toml new file mode 100644 index 0000000000000000000000000000000000000000..ab3b2729a46d4e54dc77df1175d4ebe79eda46d0 --- /dev/null +++ b/.forklift/config.toml @@ -0,0 +1,33 @@ +[compression] +type = "zstd" + +[compression.zstd] +compressionLevel = 3 + +[general] +jobNameVariable = "CI_JOB_NAME" +jobsBlackList = [] +logLevel = "warn" +threadsCount = 6 + +[cache] +extraEnv = ["RUNTIME_METADATA_HASH"] + +[metrics] +enabled = true +pushEndpoint = "placeholder" + +[metrics.extraLabels] +environment = "production" +job_name = "$CI_JOB_NAME" +project_name = "$CI_PROJECT_PATH" + +[storage] +type = "s3" + +[storage.s3] +accessKeyId = "placeholder" +bucketName = "placeholder" +concurrency = 10 +endpointUrl = "placeholder" +secretAccessKey = "placeholder" diff --git a/.github/codecov.yml b/.github/codecov.yml new file mode 100644 index 0000000000000000000000000000000000000000..ceceb9e63654ce83c942571dea79cae29f15d851 --- /dev/null +++ b/.github/codecov.yml @@ -0,0 +1,9 @@ +coverage: + precision: 2 + round: down + range: "1...100" + status: + project: + default: + target: 1.0 + threshold: 2.0 \ No newline at end of file diff --git a/.github/env b/.github/env new file mode 100644 index 0000000000000000000000000000000000000000..162ce8af7c0ddbc1534b7d1ffb09cff4be012fc7 --- /dev/null +++ b/.github/env @@ -0,0 +1 @@ +IMAGE="docker.io/paritytech/ci-unified:bullseye-1.77.0-2024-04-10-v20240408" \ No newline at end of file diff --git a/.github/workflows/check-licenses.yml b/.github/workflows/check-licenses.yml index c32b6fcf89e06bb56cefc0517e1dcab1d1ef0f37..3bc95305f7467ebbede90526eadb156b89b1e7f9 100644 --- a/.github/workflows/check-licenses.yml +++ b/.github/workflows/check-licenses.yml @@ -10,6 +10,7 @@ permissions: jobs: check-licenses: runs-on: ubuntu-latest + timeout-minutes: 10 env: LICENSES: "'Apache-2.0' 'GPL-3.0-only' 'GPL-3.0-or-later WITH Classpath-exception-2.0'" NODE_AUTH_TOKEN: ${{ secrets.GITHUB_TOKEN }} diff --git a/.github/workflows/check-markdown.yml b/.github/workflows/check-markdown.yml deleted file mode 100644 index 2b8a66db35b3adacea4f131a881103d48e3704ae..0000000000000000000000000000000000000000 --- a/.github/workflows/check-markdown.yml +++ /dev/null @@ -1,35 +0,0 @@ -name: Check Markdown - -on: - pull_request: - types: [opened, synchronize, reopened, ready_for_review] - merge_group: - -permissions: - packages: read - -jobs: - lint-markdown: - runs-on: ubuntu-latest - - steps: - - name: Checkout sources - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 - - - uses: actions/setup-node@v4.0.1 - with: - node-version: "18.x" - registry-url: "https://npm.pkg.github.com" - scope: "@paritytech" - - - name: Install tooling - run: | - npm install -g markdownlint-cli - markdownlint --version - - - name: Check Markdown - env: - CONFIG: .github/.markdownlint.yaml - run: | - echo "Checking markdown formatting. More info: docs/contributor/markdown_linting.md" - markdownlint --config "$CONFIG" --ignore target . diff --git a/.github/workflows/check-runtime-migration.yml b/.github/workflows/check-runtime-migration.yml new file mode 100644 index 0000000000000000000000000000000000000000..984e264d0d1d1d9c8ac1730c51950194cce56276 --- /dev/null +++ b/.github/workflows/check-runtime-migration.yml @@ -0,0 +1,122 @@ +name: check-runtime-migration + +on: + push: + branches: + - master + pull_request: + types: [opened, synchronize, reopened, ready_for_review] + merge_group: +concurrency: + group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }} + cancel-in-progress: true + +env: + FORKLIFT_storage_s3_bucketName: ${{ secrets.FORKLIFT_storage_s3_bucketName }} + FORKLIFT_storage_s3_accessKeyId: ${{ secrets.FORKLIFT_storage_s3_accessKeyId }} + FORKLIFT_storage_s3_secretAccessKey: ${{ secrets.FORKLIFT_storage_s3_secretAccessKey }} + FORKLIFT_storage_s3_endpointUrl: ${{ secrets.FORKLIFT_storage_s3_endpointUrl }} + FORKLIFT_metrics_pushEndpoint: ${{ secrets.FORKLIFT_metrics_pushEndpoint }} + +jobs: + set-image: + # GitHub Actions allows using 'env' in a container context. + # However, env variables don't work for forks: https://github.com/orgs/community/discussions/44322 + # This workaround sets the container image for each job using 'set-image' job output. + runs-on: ubuntu-latest + outputs: + IMAGE: ${{ steps.set_image.outputs.IMAGE }} + steps: + - name: Checkout + uses: actions/checkout@v4 + - id: set_image + run: cat .github/env >> $GITHUB_OUTPUT + # rococo and westend are disabled for now (no access to parity-chains.parity.io) + check-runtime-migration: + runs-on: arc-runners-polkadot-sdk-beefy + timeout-minutes: 30 + needs: [set-image] + container: + image: ${{ needs.set-image.outputs.IMAGE }} + strategy: + fail-fast: false + matrix: + network: [ + # westend, + # rococo, + asset-hub-westend, + asset-hub-rococo, + bridge-hub-westend, + bridge-hub-rococo, + contracts-rococo, + collectives-westend, + coretime-rococo, + ] + include: + # - network: westend + # package: westend-runtime + # wasm: westend_runtime.compact.compressed.wasm + # uri: "wss://westend-try-runtime-node.parity-chains.parity.io:443" + # subcommand_extra_args: "--no-weight-warnings" + # command_extra_args: "" + # - network: rococo + # package: rococo-runtime + # wasm: rococo_runtime.compact.compressed.wasm + # uri: "wss://rococo-try-runtime-node.parity-chains.parity.io:443" + # subcommand_extra_args: "--no-weight-warnings" + # command_extra_args: "" + - network: asset-hub-westend + package: asset-hub-westend-runtime + wasm: asset_hub_westend_runtime.compact.compressed.wasm + uri: "wss://westend-asset-hub-rpc.polkadot.io:443" + subcommand_extra_args: "" + command_extra_args: "" + - network: "asset-hub-rococo" + package: "asset-hub-rococo-runtime" + wasm: "asset_hub_rococo_runtime.compact.compressed.wasm" + uri: "wss://rococo-asset-hub-rpc.polkadot.io:443" + subcommand_extra_args: "" + command_extra_args: "" + - network: "bridge-hub-westend" + package: "bridge-hub-westend-runtime" + wasm: "bridge_hub_westend_runtime.compact.compressed.wasm" + uri: "wss://westend-bridge-hub-rpc.polkadot.io:443" + - network: "bridge-hub-rococo" + package: "bridge-hub-rococo-runtime" + wasm: "bridge_hub_rococo_runtime.compact.compressed.wasm" + uri: "wss://rococo-bridge-hub-rpc.polkadot.io:443" + - network: "contracts-rococo" + package: "contracts-rococo-runtime" + wasm: "contracts_rococo_runtime.compact.compressed.wasm" + uri: "wss://rococo-contracts-rpc.polkadot.io:443" + - network: "collectives-westend" + package: "collectives-westend-runtime" + wasm: "collectives_westend_runtime.compact.compressed.wasm" + uri: "wss://westend-collectives-rpc.polkadot.io:443" + command_extra_args: "--disable-spec-name-check" + - network: "coretime-rococo" + package: "coretime-rococo-runtime" + wasm: "coretime_rococo_runtime.compact.compressed.wasm" + uri: "wss://rococo-coretime-rpc.polkadot.io:443" + steps: + - name: Checkout + uses: actions/checkout@v4 + - name: script + run: | + echo "Running ${{ matrix.network }} runtime migration check" + 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.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 ${{ matrix.package }} runtime ----------" + time forklift cargo build --release --locked -p ${{ matrix.package }} --features try-runtime + + echo "---------- Executing on-runtime-upgrade for ${{ matrix.network }} ----------" + time ./try-runtime ${{ matrix.command_extra_args }} \ + --runtime ./target/release/wbuild/${{ matrix.package }}/${{ matrix.wasm }} \ + on-runtime-upgrade --disable-spec-version-check --checks=all ${{ matrix.subcommand_extra_args }} live --uri ${{ matrix.uri }} + sleep 5 diff --git a/.github/workflows/check-semver.yml b/.github/workflows/check-semver.yml new file mode 100644 index 0000000000000000000000000000000000000000..f0e076e8a1683a0cb5a46aa9010ec9bd3d1bc898 --- /dev/null +++ b/.github/workflows/check-semver.yml @@ -0,0 +1,55 @@ +name: Check semver + +on: + pull_request: + types: [opened, synchronize, reopened, ready_for_review] + paths: + - prdoc/*.prdoc + +jobs: + check-semver: + runs-on: ubuntu-latest + container: + image: docker.io/paritytech/ci-unified:bullseye-1.77.0-2024-04-10-v20240408 + steps: + - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 + + - name: Rust Cache + uses: Swatinem/rust-cache@23bce251a8cd2ffc3c1075eaa2367cf899916d84 # v2.7.3 + with: + cache-on-failure: true + + - name: Rust compilation prerequisites + run: | + rustup default nightly-2024-03-01 + rustup target add wasm32-unknown-unknown --toolchain nightly-2024-03-01 + rustup component add rust-src --toolchain nightly-2024-03-01 + + - name: install parity-publish + run: cargo install parity-publish@0.5.1 + + - name: extra git setup + run: | + git config --global --add safe.directory '*' + git fetch --no-tags --no-recurse-submodules --depth=1 origin master + git branch old origin/master + + - name: check semver + run: | + export CARGO_TARGET_DIR=target + export RUSTFLAGS='-A warnings -A missing_docs' + if ! parity-publish --color always prdoc --since old --validate prdoc/pr_$PR.prdoc --toolchain nightly-2024-03-01 -v; then + cat < - python3 .github/scripts/check-workspace.py . - --exclude - "substrate/frame/contracts/fixtures/build" - "substrate/frame/contracts/fixtures/contracts/common" diff --git a/.github/workflows/checks-quick.yml b/.github/workflows/checks-quick.yml new file mode 100644 index 0000000000000000000000000000000000000000..217adf40a391966c9482a691b94ffc719d2c65ab --- /dev/null +++ b/.github/workflows/checks-quick.yml @@ -0,0 +1,118 @@ +# Checks that doesn't require heavy lifting, like formatting, linting, etc. +name: quick-checks + +on: + push: + branches: + - master + pull_request: + types: [opened, synchronize, reopened, ready_for_review] + merge_group: +concurrency: + group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }} + cancel-in-progress: true + +permissions: {} + +jobs: + set-image: + # GitHub Actions allows using 'env' in a container context. + # However, env variables don't work for forks: https://github.com/orgs/community/discussions/44322 + # This workaround sets the container image for each job using 'set-image' job output. + runs-on: ubuntu-latest + timeout-minutes: 10 + outputs: + IMAGE: ${{ steps.set_image.outputs.IMAGE }} + steps: + - name: Checkout + uses: actions/checkout@v4 + - id: set_image + run: cat .github/env >> $GITHUB_OUTPUT + fmt: + runs-on: ubuntu-latest + timeout-minutes: 10 + needs: [set-image] + container: + image: ${{ needs.set-image.outputs.IMAGE }} + steps: + - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 + - name: Cargo fmt + run: cargo +nightly fmt --all -- --check + check-dependency-rules: + runs-on: ubuntu-latest + timeout-minutes: 10 + steps: + - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 + - name: check dependency rules + run: | + cd substrate/ + ../.gitlab/ensure-deps.sh + check-rust-feature-propagation: + runs-on: ubuntu-latest + timeout-minutes: 10 + needs: [set-image] + container: + image: ${{ needs.set-image.outputs.IMAGE }} + steps: + - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 + - name: run zepter + run: zepter run check + test-rust-features: + runs-on: ubuntu-latest + timeout-minutes: 10 + needs: [set-image] + container: + image: ${{ needs.set-image.outputs.IMAGE }} + steps: + - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 + - name: run rust features + run: bash .gitlab/rust-features.sh . + check-toml-format: + runs-on: ubuntu-latest + timeout-minutes: 10 + needs: [set-image] + container: + image: ${{ needs.set-image.outputs.IMAGE }} + steps: + - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 + - name: check toml format + run: | + taplo format --check --config .config/taplo.toml + echo "Please run `taplo format --config .config/taplo.toml` to fix any toml formatting issues" + check-workspace: + runs-on: ubuntu-latest + timeout-minutes: 10 + steps: + - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.0 (22. Sep 2023) + - name: install python deps + run: | + sudo apt-get update && sudo apt-get install -y python3-pip python3 + pip3 install toml + - name: check integrity + run: > + python3 .github/scripts/check-workspace.py . + --exclude + "substrate/frame/contracts/fixtures/build" + "substrate/frame/contracts/fixtures/contracts/common" + check-markdown: + runs-on: ubuntu-latest + timeout-minutes: 10 + steps: + - name: Checkout sources + uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 + - name: Setup Node.js + uses: actions/setup-node@v4.0.1 + with: + node-version: "18.x" + registry-url: "https://npm.pkg.github.com" + scope: "@paritytech" + - name: Install tooling + run: | + npm install -g markdownlint-cli + markdownlint --version + - name: Check Markdown + env: + CONFIG: .github/.markdownlint.yaml + run: | + echo "Checking markdown formatting. More info: docs/contributor/markdown_linting.md" + markdownlint --config "$CONFIG" --ignore target . diff --git a/.github/workflows/fmt-check.yml b/.github/workflows/fmt-check.yml deleted file mode 100644 index efcf278c46e83630a54fae3de01d0c9e19304dee..0000000000000000000000000000000000000000 --- a/.github/workflows/fmt-check.yml +++ /dev/null @@ -1,23 +0,0 @@ -name: Rustfmt check - -on: - push: - branches: - - master - pull_request: - types: [opened, synchronize, reopened, ready_for_review] - merge_group: - -jobs: - quick_check: - strategy: - matrix: - os: ["ubuntu-latest"] - runs-on: ${{ matrix.os }} - container: - image: docker.io/paritytech/ci-unified:bullseye-1.75.0-2024-01-22-v20240109 - steps: - - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 - - - name: Cargo fmt - run: cargo +nightly fmt --all -- --check diff --git a/.github/workflows/auto-add-parachain-issues.yml b/.github/workflows/issues-auto-add-parachain.yml similarity index 100% rename from .github/workflows/auto-add-parachain-issues.yml rename to .github/workflows/issues-auto-add-parachain.yml diff --git a/.github/workflows/auto-label-issues.yml b/.github/workflows/issues-auto-label.yml similarity index 100% rename from .github/workflows/auto-label-issues.yml rename to .github/workflows/issues-auto-label.yml diff --git a/.github/workflows/notif-burnin-label.yml b/.github/workflows/misc-notify-burnin-label.yml similarity index 100% rename from .github/workflows/notif-burnin-label.yml rename to .github/workflows/misc-notify-burnin-label.yml diff --git a/.github/workflows/merge-queue.yml b/.github/workflows/misc-review-bot-merge-queue.yml similarity index 79% rename from .github/workflows/merge-queue.yml rename to .github/workflows/misc-review-bot-merge-queue.yml index cce326f44931bed8357fb661c8b053f60205f119..28b3bc7533c054d645c3b922e5a6e7e2f298b0be 100644 --- a/.github/workflows/merge-queue.yml +++ b/.github/workflows/misc-review-bot-merge-queue.yml @@ -1,3 +1,4 @@ +# Actions that makes review-bot green in the merge queue name: Merge-Queue on: @@ -18,7 +19,7 @@ jobs: uses: billyjbryant/create-status-check@3e6fa0ac599d10d9588cf9516ca4330ef669b858 # v2 with: authToken: ${{ steps.app_token.outputs.token }} - context: 'review-bot' - description: 'PRs for merge queue gets approved' - state: 'success' + context: "review-bot" + description: "PRs for merge queue gets approved" + state: "success" sha: ${{ github.event.merge_group.head_commit.id }} diff --git a/.github/workflows/sync-templates.yml b/.github/workflows/misc-sync-templates.yml similarity index 99% rename from .github/workflows/sync-templates.yml rename to .github/workflows/misc-sync-templates.yml index 511c9d0e8cd06f7b4b7b16126d6565cae9047a00..3617d6c34a3e342e1abd52acaffbf3a8c61ec43b 100644 --- a/.github/workflows/sync-templates.yml +++ b/.github/workflows/misc-sync-templates.yml @@ -61,7 +61,7 @@ jobs: - name: Install toml-cli run: cargo install --git https://github.com/gnprice/toml-cli --rev ea69e9d2ca4f0f858110dc7a5ae28bcb918c07fb # v0.2.3 - name: Install Polkadot SDK Version Manager - run: cargo install --git https://github.com/paritytech/psvm --rev c41261ffb52ab0c115adbbdb17e2cb7900d2bdfd psvm # master + run: cargo install --git https://github.com/paritytech/psvm psvm - name: Rust compilation prerequisites run: | sudo apt update diff --git a/.github/workflows/check-publish.yml b/.github/workflows/publish-check-crates.yml similarity index 81% rename from .github/workflows/check-publish.yml rename to .github/workflows/publish-check-crates.yml index b16b3d4e5c5c5061741e7ae698ff0a0e9e0c5084..9b5b89e34475699ccbcaeca34cd290882ee45a9a 100644 --- a/.github/workflows/check-publish.yml +++ b/.github/workflows/publish-check-crates.yml @@ -20,7 +20,7 @@ jobs: cache-on-failure: true - name: install parity-publish - run: cargo install parity-publish@0.3.0 + run: cargo install parity-publish@0.5.1 - name: parity-publish check - run: parity-publish check --allow-unpublished + run: parity-publish --color always check --allow-unpublished diff --git a/.github/workflows/claim-crates.yml b/.github/workflows/publish-claim-crates.yml similarity index 85% rename from .github/workflows/claim-crates.yml rename to .github/workflows/publish-claim-crates.yml index f3df0bce72d501ed22c66b9792e032becdd4da93..9643361d9d318f84d64a212358a825a8e0b5aa20 100644 --- a/.github/workflows/claim-crates.yml +++ b/.github/workflows/publish-claim-crates.yml @@ -18,9 +18,9 @@ jobs: cache-on-failure: true - name: install parity-publish - run: cargo install parity-publish@0.3.0 + run: cargo install parity-publish@0.5.1 - name: parity-publish claim env: PARITY_PUBLISH_CRATESIO_TOKEN: ${{ secrets.CRATESIO_PUBLISH_CLAIM_TOKEN }} - run: parity-publish claim + run: parity-publish --color always claim diff --git a/.github/workflows/subsystem-benchmarks.yml b/.github/workflows/publish-subsystem-benchmarks.yml similarity index 100% rename from .github/workflows/subsystem-benchmarks.yml rename to .github/workflows/publish-subsystem-benchmarks.yml diff --git a/.github/workflows/release-30_publish_release_draft.yml b/.github/workflows/release-30_publish_release_draft.yml index 12891ef70af36b4e848c68e292f9ba2881ee20d2..a9e521051d04079a49af76c78681af8ae52ae5da 100644 --- a/.github/workflows/release-30_publish_release_draft.yml +++ b/.github/workflows/release-30_publish_release_draft.yml @@ -42,7 +42,6 @@ jobs: URL=https://github.com/chevdor/tera-cli/releases/download/v0.2.4/tera-cli_linux_amd64.deb wget $URL -O tera.deb sudo dpkg -i tera.deb - tera --version - name: Download artifacts uses: actions/download-artifact@c850b930e6ba138125429b7e5c93fc707a7f8427 # v4.1.4 @@ -70,7 +69,7 @@ jobs: export REF1=$(get_latest_release_tag) if [[ -z "${{ inputs.version }}" ]]; then - export REF2="${{ github.ref }}" + export REF2="${{ github.ref_name }}" else export REF2="${{ inputs.version }}" fi @@ -79,10 +78,6 @@ jobs: ./scripts/release/build-changelogs.sh - echo "Checking the folder state" - pwd - ls -la scripts/release - - name: Archive artifact context.json uses: actions/upload-artifact@5d5d22a31266ced268874388b861e4b58bb5c2f3 # v4.3.1 with: @@ -137,6 +132,7 @@ jobs: post_to_matrix: runs-on: ubuntu-latest needs: publish-release-draft + environment: release strategy: matrix: channel: @@ -151,5 +147,5 @@ jobs: access_token: ${{ secrets.RELEASENOTES_MATRIX_V2_ACCESS_TOKEN }} server: m.parity.io message: | - **New version of polkadot tagged**: ${{ github.ref }}
+ **New version of polkadot tagged**: ${{ github.ref_name }}
Draft release created: ${{ needs.publish-release-draft.outputs.release_url }} diff --git a/.github/workflows/release-99_notif-published.yml b/.github/workflows/release-99_notif-published.yml index 05c9d6a47f551860c51e318b01b495ca662e902e..b5b2ed38e845ea158d1c45c5da0e7d3358e77302 100644 --- a/.github/workflows/release-99_notif-published.yml +++ b/.github/workflows/release-99_notif-published.yml @@ -48,5 +48,3 @@ jobs: Release version: [${{github.event.release.tag_name}}](${{github.event.release.html_url}}) ----- - - ${{github.event.release.body}} diff --git a/.github/workflows/build-and-attach-release-runtimes.yml b/.github/workflows/release-build-and-attach-runtimes.yml similarity index 100% rename from .github/workflows/build-and-attach-release-runtimes.yml rename to .github/workflows/release-build-and-attach-runtimes.yml diff --git a/.github/workflows/check-runtimes.yml b/.github/workflows/release-check-runtimes.yml similarity index 100% rename from .github/workflows/check-runtimes.yml rename to .github/workflows/release-check-runtimes.yml diff --git a/.github/workflows/srtool.yml b/.github/workflows/release-srtool.yml similarity index 100% rename from .github/workflows/srtool.yml rename to .github/workflows/release-srtool.yml diff --git a/.github/workflows/review-bot.yml b/.github/workflows/review-bot.yml index 5b036115b2386c366b2f1e78e9ce1dc7d526eedd..f1401406ae47afd3230cc163f35df0e3bcbac7b7 100644 --- a/.github/workflows/review-bot.yml +++ b/.github/workflows/review-bot.yml @@ -5,28 +5,41 @@ on: - Review-Trigger types: - completed + workflow_dispatch: + inputs: + pr-number: + description: "Number of the PR to evaluate" + required: true + type: number jobs: review-approvals: runs-on: ubuntu-latest environment: master steps: + - name: Generate token + id: app_token + uses: actions/create-github-app-token@v1.9.3 + with: + app-id: ${{ secrets.REVIEW_APP_ID }} + private-key: ${{ secrets.REVIEW_APP_KEY }} - name: Extract content of artifact + if: ${{ !inputs.pr-number }} id: number - uses: Bullrich/extract-text-from-artifact@v1.0.0 + uses: Bullrich/extract-text-from-artifact@v1.0.1 with: artifact-name: pr_number - - name: Generate token - id: app_token - uses: tibdex/github-app-token@v1 - with: - app_id: ${{ secrets.REVIEW_APP_ID }} - private_key: ${{ secrets.REVIEW_APP_KEY }} - name: "Evaluates PR reviews and assigns reviewers" uses: paritytech/review-bot@v2.4.0 with: repo-token: ${{ steps.app_token.outputs.token }} team-token: ${{ steps.app_token.outputs.token }} checks-token: ${{ steps.app_token.outputs.token }} - pr-number: ${{ steps.number.outputs.content }} + # This is extracted from the triggering event + pr-number: ${{ inputs.pr-number || steps.number.outputs.content }} request-reviewers: true + - name: Log payload + if: ${{ failure() || runner.debug }} + run: echo "::debug::$payload" + env: + payload: ${{ toJson(github.event) }} diff --git a/.github/workflows/review-trigger.yml b/.github/workflows/review-trigger.yml index 8b23dd30bb29ad7879543c064c3eb711cc87895d..ec4a62afc0c780fcb13e7bc73228bb2e77e6a582 100644 --- a/.github/workflows/review-trigger.yml +++ b/.github/workflows/review-trigger.yml @@ -21,6 +21,43 @@ jobs: - name: Skip merge queue if: ${{ contains(github.ref, 'gh-readonly-queue') }} run: exit 0 + - name: Get PR data + id: comments + run: | + echo "bodies=$(gh pr view ${{ github.event.pull_request.number }} --repo ${{ github.repository }} --json comments --jq '[.comments[].body]')" >> "$GITHUB_OUTPUT" + echo "reviews=$(gh api repos/${{ github.repository }}/pulls/${{ github.event.pull_request.number }}/reviews --jq '[.[].state]')" >> "$GITHUB_OUTPUT" + env: + GH_TOKEN: ${{ github.token }} + - name: Fail when author pushes new code + # Require new reviews when the author is pushing and he is not a member + if: | + contains(fromJson(steps.comments.outputs.reviews), 'APPROVED') && + github.event_name == 'pull_request_target' && + github.event.action == 'synchronize' && + github.event.sender.login == github.event.pull_request.user.login && + github.event.pull_request.author_association != 'CONTRIBUTOR' && + github.event.pull_request.author_association != 'MEMBER' + run: | + echo "User's association is ${{ github.event.pull_request.author_association }}" + # We get the list of reviewers who approved the PR + REVIEWERS=$(gh api repos/${{ github.repository }}/pulls/${{ github.event.pull_request.number }}/reviews \ + --jq '{reviewers: [.[] | select(.state == "APPROVED") | .user.login]}') + + # We request them to review again + echo $REVIEWERS | gh api --method POST repos/${{ github.repository }}/pulls/${{ github.event.pull_request.number }}/requested_reviewers --input - + + echo "::error::Project needs to be reviewed again" + exit 1 + env: + GH_TOKEN: ${{ github.token }} + - name: Comment requirements + # If the previous step failed and github-actions hasn't commented yet we comment instructions + if: failure() && !contains(fromJson(steps.comments.outputs.bodies), 'Review required! Latest push from author must always be reviewed') + run: | + gh pr comment ${{ github.event.pull_request.number }} --repo ${{ github.repository }} --body "Review required! Latest push from author must always be reviewed" + env: + GH_TOKEN: ${{ github.token }} + COMMENTS: ${{ steps.comments.outputs.users }} - name: Get PR number env: PR_NUMBER: ${{ github.event.pull_request.number }} @@ -28,7 +65,7 @@ jobs: echo "Saving PR number: $PR_NUMBER" mkdir -p ./pr echo $PR_NUMBER > ./pr/pr_number - - uses: actions/upload-artifact@v3 + - uses: actions/upload-artifact@v4 name: Save PR number with: name: pr_number diff --git a/.github/workflows/tests-linux-stable.yml b/.github/workflows/tests-linux-stable.yml new file mode 100644 index 0000000000000000000000000000000000000000..8822ba6d250ac5c858e22cdd98027d6a89e0634d --- /dev/null +++ b/.github/workflows/tests-linux-stable.yml @@ -0,0 +1,69 @@ +# GHA for test-linux-stable-int, test-linux-stable, test-linux-stable-oldkernel +name: tests linux stable + +on: + push: + branches: + - master + pull_request: + types: [opened, synchronize, reopened, ready_for_review] + merge_group: +concurrency: + group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }} + cancel-in-progress: true + +env: + FORKLIFT_storage_s3_bucketName: ${{ secrets.FORKLIFT_storage_s3_bucketName }} + FORKLIFT_storage_s3_accessKeyId: ${{ secrets.FORKLIFT_storage_s3_accessKeyId }} + FORKLIFT_storage_s3_secretAccessKey: ${{ secrets.FORKLIFT_storage_s3_secretAccessKey }} + FORKLIFT_storage_s3_endpointUrl: ${{ secrets.FORKLIFT_storage_s3_endpointUrl }} + FORKLIFT_metrics_pushEndpoint: ${{ secrets.FORKLIFT_metrics_pushEndpoint }} + +jobs: + set-image: + # GitHub Actions allows using 'env' in a container context. + # However, env variables don't work for forks: https://github.com/orgs/community/discussions/44322 + # This workaround sets the container image for each job using 'set-image' job output. + runs-on: ubuntu-latest + outputs: + IMAGE: ${{ steps.set_image.outputs.IMAGE }} + steps: + - name: Checkout + uses: actions/checkout@v4 + - id: set_image + run: cat .github/env >> $GITHUB_OUTPUT + test-linux-stable-int: + runs-on: arc-runners-polkadot-sdk-beefy + timeout-minutes: 30 + needs: [set-image] + container: + image: ${{ needs.set-image.outputs.IMAGE }} + env: + RUSTFLAGS: "-C debug-assertions -D warnings" + RUST_BACKTRACE: 1 + WASM_BUILD_NO_COLOR: 1 + WASM_BUILD_RUSTFLAGS: "-C debug-assertions -D warnings" + # Ensure we run the UI tests. + RUN_UI_TESTS: 1 + steps: + - name: Checkout + uses: actions/checkout@v4 + - name: script + run: WASM_BUILD_NO_COLOR=1 time forklift cargo test -p staging-node-cli --release --locked -- --ignored + # https://github.com/paritytech/ci_cd/issues/864 + test-linux-stable-runtime-benchmarks: + runs-on: arc-runners-polkadot-sdk-beefy + timeout-minutes: 30 + needs: [set-image] + container: + image: ${{ needs.set-image.outputs.IMAGE }} + env: + RUST_TOOLCHAIN: stable + # Enable debug assertions since we are running optimized builds for testing + # but still want to have debug assertions. + RUSTFLAGS: "-Cdebug-assertions=y -Dwarnings" + steps: + - name: Checkout + uses: actions/checkout@v4 + - name: script + run: time forklift cargo nextest run --workspace --features runtime-benchmarks benchmark --locked --cargo-profile testnet diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml new file mode 100644 index 0000000000000000000000000000000000000000..76bccba86b21c136cbb2bf15f44e701cc69af4ab --- /dev/null +++ b/.github/workflows/tests.yml @@ -0,0 +1,86 @@ +name: tests + +on: + push: + branches: + - master + pull_request: + types: [opened, synchronize, reopened, ready_for_review] + merge_group: +concurrency: + group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }} + cancel-in-progress: true + +env: + FORKLIFT_storage_s3_bucketName: ${{ secrets.FORKLIFT_storage_s3_bucketName }} + FORKLIFT_storage_s3_accessKeyId: ${{ secrets.FORKLIFT_storage_s3_accessKeyId }} + FORKLIFT_storage_s3_secretAccessKey: ${{ secrets.FORKLIFT_storage_s3_secretAccessKey }} + FORKLIFT_storage_s3_endpointUrl: ${{ secrets.FORKLIFT_storage_s3_endpointUrl }} + FORKLIFT_metrics_pushEndpoint: ${{ secrets.FORKLIFT_metrics_pushEndpoint }} + +jobs: + set-image: + # GitHub Actions allows using 'env' in a container context. + # However, env variables don't work for forks: https://github.com/orgs/community/discussions/44322 + # This workaround sets the container image for each job using 'set-image' job output. + runs-on: ubuntu-latest + outputs: + IMAGE: ${{ steps.set_image.outputs.IMAGE }} + steps: + - name: Checkout + uses: actions/checkout@v4 + - id: set_image + run: cat .github/env >> $GITHUB_OUTPUT + quick-benchmarks: + runs-on: arc-runners-polkadot-sdk-beefy + timeout-minutes: 30 + needs: [set-image] + container: + image: ${{ needs.set-image.outputs.IMAGE }} + env: + RUSTFLAGS: "-C debug-assertions -D warnings" + RUST_BACKTRACE: "full" + WASM_BUILD_NO_COLOR: 1 + WASM_BUILD_RUSTFLAGS: "-C debug-assertions -D warnings" + steps: + - name: Checkout + uses: actions/checkout@v4 + - name: script + run: time forklift cargo run --locked --release -p staging-node-cli --bin substrate-node --features runtime-benchmarks -- benchmark pallet --chain dev --pallet "*" --extrinsic "*" --steps 2 --repeat 1 --quiet + # cf https://github.com/paritytech/polkadot-sdk/issues/1652 + test-syscalls: + runs-on: arc-runners-polkadot-sdk-beefy + timeout-minutes: 30 + needs: [set-image] + container: + image: ${{ needs.set-image.outputs.IMAGE }} + continue-on-error: true # this rarely triggers in practice + env: + SKIP_WASM_BUILD: 1 + steps: + - name: Checkout + uses: actions/checkout@v4 + - name: script + run: | + forklift cargo build --locked --profile production --target x86_64-unknown-linux-musl --bin polkadot-execute-worker --bin polkadot-prepare-worker + cd polkadot/scripts/list-syscalls + ./list-syscalls.rb ../../../target/x86_64-unknown-linux-musl/production/polkadot-execute-worker --only-used-syscalls | diff -u execute-worker-syscalls - + ./list-syscalls.rb ../../../target/x86_64-unknown-linux-musl/production/polkadot-prepare-worker --only-used-syscalls | diff -u prepare-worker-syscalls - + # todo: + # after_script: + # - if [[ "$CI_JOB_STATUS" == "failed" ]]; then + # printf "The x86_64 syscalls used by the worker binaries have changed. Please review if this is expected and update polkadot/scripts/list-syscalls/*-worker-syscalls as needed.\n"; + # fi + cargo-check-all-benches: + runs-on: arc-runners-polkadot-sdk-beefy + timeout-minutes: 30 + needs: [set-image] + container: + image: ${{ needs.set-image.outputs.IMAGE }} + env: + SKIP_WASM_BUILD: 1 + steps: + - name: Checkout + uses: actions/checkout@v4 + - name: script + run: time forklift cargo check --all --benches diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 5e57dd86f14166e695f1c64b6b5aee56529a4781..73a8c52c448f72d12e510d65b2f7ff38469856f0 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -120,7 +120,7 @@ default: .forklift-cache: before_script: - mkdir ~/.forklift - - cp $FL_FORKLIFT_CONFIG ~/.forklift/config.toml + - cp .forklift/config.toml ~/.forklift/config.toml - > if [ "$FORKLIFT_BYPASS" != "true" ]; then echo "FORKLIFT_BYPASS not set"; diff --git a/.gitlab/pipeline/check.yml b/.gitlab/pipeline/check.yml index 89b2c00db9b2b13187a562987e00abcb232e0e32..5c1a667a313ce391f0c790881d87f48ebd79d073 100644 --- a/.gitlab/pipeline/check.yml +++ b/.gitlab/pipeline/check.yml @@ -132,7 +132,6 @@ 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 @@ -147,96 +146,6 @@ check-runtime-migration-rococo: URI: "wss://rococo-try-runtime-node.parity-chains.parity.io:443" SUBCOMMAND_EXTRA_ARGS: "--no-weight-warnings" -# Check runtime migrations for Parity managed asset hub chains -check-runtime-migration-asset-hub-westend: - stage: check - extends: - - .docker-env - - .test-pr-refs - - .check-runtime-migration - variables: - NETWORK: "asset-hub-westend" - PACKAGE: "asset-hub-westend-runtime" - WASM: "asset_hub_westend_runtime.compact.compressed.wasm" - URI: "wss://westend-asset-hub-rpc.polkadot.io:443" - -check-runtime-migration-asset-hub-rococo: - stage: check - extends: - - .docker-env - - .test-pr-refs - - .check-runtime-migration - variables: - NETWORK: "asset-hub-rococo" - PACKAGE: "asset-hub-rococo-runtime" - WASM: "asset_hub_rococo_runtime.compact.compressed.wasm" - URI: "wss://rococo-asset-hub-rpc.polkadot.io:443" - -# Check runtime migrations for Parity managed bridge hub chains -check-runtime-migration-bridge-hub-westend: - stage: check - extends: - - .docker-env - - .test-pr-refs - - .check-runtime-migration - variables: - NETWORK: "bridge-hub-westend" - PACKAGE: "bridge-hub-westend-runtime" - WASM: "bridge_hub_westend_runtime.compact.compressed.wasm" - URI: "wss://westend-bridge-hub-rpc.polkadot.io:443" - -check-runtime-migration-bridge-hub-rococo: - stage: check - extends: - - .docker-env - - .test-pr-refs - - .check-runtime-migration - variables: - NETWORK: "bridge-hub-rococo" - PACKAGE: "bridge-hub-rococo-runtime" - WASM: "bridge_hub_rococo_runtime.compact.compressed.wasm" - URI: "wss://rococo-bridge-hub-rpc.polkadot.io:443" - -# Check runtime migrations for Parity managed contract chains -check-runtime-migration-contracts-rococo: - stage: check - extends: - - .docker-env - - .test-pr-refs - - .check-runtime-migration - variables: - NETWORK: "contracts-rococo" - PACKAGE: "contracts-rococo-runtime" - WASM: "contracts_rococo_runtime.compact.compressed.wasm" - URI: "wss://rococo-contracts-rpc.polkadot.io:443" - -# Check runtime migrations for Parity managed collectives chains -check-runtime-migration-collectives-westend: - stage: check - extends: - - .docker-env - - .test-pr-refs - - .check-runtime-migration - variables: - NETWORK: "collectives-westend" - PACKAGE: "collectives-westend-runtime" - WASM: "collectives_westend_runtime.compact.compressed.wasm" - URI: "wss://westend-collectives-rpc.polkadot.io:443" - COMMAND_EXTRA_ARGS: "--disable-spec-name-check" - -# Check runtime migrations for Parity managed coretime chain -check-runtime-migration-coretime-rococo: - stage: check - extends: - - .docker-env - - .test-pr-refs - - .check-runtime-migration - variables: - NETWORK: "coretime-rococo" - PACKAGE: "coretime-rococo-runtime" - WASM: "coretime_rococo_runtime.compact.compressed.wasm" - URI: "wss://rococo-coretime-rpc.polkadot.io:443" - find-fail-ci-phrase: stage: check variables: diff --git a/.gitlab/pipeline/publish.yml b/.gitlab/pipeline/publish.yml index d8f5d5832291f7afced292d3b0fdeb6238de26a8..8b27c7247487f0620c5214e75532025a96ec3ea4 100644 --- a/.gitlab/pipeline/publish.yml +++ b/.gitlab/pipeline/publish.yml @@ -74,6 +74,8 @@ publish-subsystem-benchmarks: artifacts: true - job: subsystem-benchmark-availability-distribution artifacts: true + - job: subsystem-benchmark-approval-voting + artifacts: true - job: publish-rustdoc artifacts: false script: @@ -115,6 +117,8 @@ trigger_workflow: artifacts: true - job: subsystem-benchmark-availability-distribution artifacts: true + - job: subsystem-benchmark-approval-voting + artifacts: true script: - echo "Triggering workflow" - > @@ -125,7 +129,7 @@ trigger_workflow: curl -q -X POST \ -H "Accept: application/vnd.github.v3+json" \ -H "Authorization: token $GITHUB_TOKEN" \ - https://api.github.com/repos/paritytech/${CI_PROJECT_NAME}/actions/workflows/subsystem-benchmarks.yml/dispatches \ + https://api.github.com/repos/paritytech/${CI_PROJECT_NAME}/actions/workflows/publish-subsystem-benchmarks.yml/dispatches \ -d "{\"ref\":\"refs/heads/master\",\"inputs\":{\"benchmark-data-dir-path\":\"$benchmark_dir\",\"output-file-path\":\"$benchmark_name\"}}"; sleep 300; done diff --git a/.gitlab/pipeline/test.yml b/.gitlab/pipeline/test.yml index 1d6efd7b9fd1a91c3c49aa26faa9263216e9cb4e..eea561ff8baa8793e8f70974ec01c428d150ea73 100644 --- a/.gitlab/pipeline/test.yml +++ b/.gitlab/pipeline/test.yml @@ -5,6 +5,113 @@ - job: job-starter artifacts: false +# +# +# +.codecov-check: + script: + - > + if command -v codecovcli -h >/dev/null 2>&1; then + codecovcli --version; + else + echo "downloading codecovcli"; + curl -s -o codecovcli https://cli.codecov.io/latest/linux/codecov; + chmod +x codecovcli; + mv codecovcli /usr/local/bin/codecovcli; + fi + # + - codecovcli --version + +# +# +# +codecov-start: + stage: test + when: manual + allow_failure: false + extends: + - .kubernetes-env + - .common-refs + - .pipeline-stopper-artifacts + - .run-immediately + script: + - !reference [.codecov-check, script] + - > + if [ "$CI_COMMIT_REF_NAME" != "master" ]; then + codecovcli -v create-commit -t ${CODECOV_TOKEN} -r paritytech/polkadot-sdk --commit-sha ${CI_COMMIT_SHA} --fail-on-error --pr ${CI_COMMIT_REF_NAME} --git-service github; + codecovcli -v create-report -t ${CODECOV_TOKEN} -r paritytech/polkadot-sdk --commit-sha ${CI_COMMIT_SHA} --fail-on-error --pr ${CI_COMMIT_REF_NAME} --git-service github; + else + codecovcli -v create-commit -t ${CODECOV_TOKEN} -r paritytech/polkadot-sdk --commit-sha ${CI_COMMIT_SHA} --fail-on-error --git-service github; + codecovcli -v create-report -t ${CODECOV_TOKEN} -r paritytech/polkadot-sdk --commit-sha ${CI_COMMIT_SHA} --fail-on-error --git-service github; + fi + +# +# +# +codecov-finish: + stage: test + extends: + - .kubernetes-env + - .common-refs + - .pipeline-stopper-artifacts + needs: + - test-linux-stable-codecov + script: + - !reference [.codecov-check, script] + - codecovcli -v create-report-results -t ${CODECOV_TOKEN} -r paritytech/polkadot-sdk --commit-sha ${CI_COMMIT_SHA} --git-service github + - codecovcli -v get-report-results -t ${CODECOV_TOKEN} -r paritytech/polkadot-sdk --commit-sha ${CI_COMMIT_SHA} --git-service github + - codecovcli -v send-notifications -t ${CODECOV_TOKEN} -r paritytech/polkadot-sdk --commit-sha ${CI_COMMIT_SHA} --git-service github + +# +# +# +test-linux-stable-codecov: + stage: test + needs: + - codecov-start + extends: + - .docker-env + - .common-refs + - .pipeline-stopper-artifacts + variables: + CI_IMAGE: europe-docker.pkg.dev/parity-build/ci-images/ci-unified:bullseye-1.77.0 + RUST_TOOLCHAIN: stable + RUSTFLAGS: "-Cdebug-assertions=y -Cinstrument-coverage" + LLVM_PROFILE_FILE: "target/coverage/cargo-test-${CI_NODE_INDEX}-%p-%m.profraw" + CARGO_INCREMENTAL: 0 + FORKLIFT_BYPASS: "true" + parallel: 2 + script: + # tools + - !reference [.codecov-check, script] + - rustup component add llvm-tools-preview + - mkdir -p target/coverage/result/ + # Place real test call here + - > + time cargo nextest run -p polkadot \ + --locked \ + --release \ + --no-fail-fast \ + --partition count:${CI_NODE_INDEX}/${CI_NODE_TOTAL} + # generate and upload reports + - > + grcov \ + target/coverage/ \ + --binary-path ./target/release/ \ + -s . \ + -t lcov \ + --branch \ + -o target/coverage/result/report-${CI_NODE_INDEX}.lcov + - ls -l target/coverage/result/ + - > + if [ "$CI_COMMIT_REF_NAME" != "master" ]; then + codecovcli -v do-upload -f target/coverage/result/report-${CI_NODE_INDEX}.lcov --disable-search -t ${CODECOV_TOKEN} -r paritytech/polkadot-sdk --commit-sha ${CI_COMMIT_SHA} --fail-on-error --pr ${CI_COMMIT_REF_NAME} --git-service github; + else + codecovcli -v do-upload -f target/coverage/result/report-${CI_NODE_INDEX}.lcov --disable-search -t ${CODECOV_TOKEN} -r paritytech/polkadot-sdk --commit-sha ${CI_COMMIT_SHA} --fail-on-error --git-service github; + fi + + # + test-linux-stable: stage: test extends: @@ -21,8 +128,6 @@ test-linux-stable: script: # Build all but only execute 'runtime' tests. - echo "Node index - ${CI_NODE_INDEX}. Total amount - ${CI_NODE_TOTAL}" - # add experimental to features after https://github.com/paritytech/substrate/pull/14502 is merged - # "upgrade_version_checks_should_work" is currently failing - > time cargo nextest run \ --workspace \ @@ -147,18 +252,6 @@ test-rustdoc: script: - time cargo doc --workspace --all-features --no-deps -cargo-check-all-benches: - stage: test - extends: - - .docker-env - - .common-refs - # DAG - needs: - - job: cargo-hfuzz - artifacts: false - script: - - time cargo check --all --benches - test-node-metrics: stage: test extends: @@ -491,27 +584,7 @@ cargo-hfuzz: - for target in $(cargo read-manifest | jq -r '.targets | .[] | .name'); do cargo hfuzz run "$target" || { printf "fuzzing failure for %s\n" "$target"; exit 1; }; done -# cf https://github.com/paritytech/polkadot-sdk/issues/1652 -test-syscalls: - stage: test - extends: - - .docker-env - - .common-refs - - .run-immediately - variables: - SKIP_WASM_BUILD: 1 - script: - - cargo build --locked --profile production --target x86_64-unknown-linux-musl --bin polkadot-execute-worker --bin polkadot-prepare-worker - - cd polkadot/scripts/list-syscalls - - ./list-syscalls.rb ../../../target/x86_64-unknown-linux-musl/production/polkadot-execute-worker --only-used-syscalls | diff -u execute-worker-syscalls - - - ./list-syscalls.rb ../../../target/x86_64-unknown-linux-musl/production/polkadot-prepare-worker --only-used-syscalls | diff -u prepare-worker-syscalls - - after_script: - - if [[ "$CI_JOB_STATUS" == "failed" ]]; then - printf "The x86_64 syscalls used by the worker binaries have changed. Please review if this is expected and update polkadot/scripts/list-syscalls/*-worker-syscalls as needed.\n"; - fi - allow_failure: false # this rarely triggers in practice - -subsystem-benchmark-availability-recovery: +.subsystem-benchmark-template: stage: test artifacts: name: "${CI_JOB_NAME}_${CI_COMMIT_REF_NAME}" @@ -523,26 +596,26 @@ subsystem-benchmark-availability-recovery: - .docker-env - .common-refs - .run-immediately - script: - - cargo bench -p polkadot-availability-recovery --bench availability-recovery-regression-bench --features subsystem-benchmarks tags: - benchmark + +subsystem-benchmark-availability-recovery: + extends: + - .subsystem-benchmark-template + script: + - cargo bench -p polkadot-availability-recovery --bench availability-recovery-regression-bench --features subsystem-benchmarks allow_failure: true subsystem-benchmark-availability-distribution: - stage: test - artifacts: - name: "${CI_JOB_NAME}_${CI_COMMIT_REF_NAME}" - when: always - expire_in: 1 hour - paths: - - charts/ extends: - - .docker-env - - .common-refs - - .run-immediately + - .subsystem-benchmark-template script: - cargo bench -p polkadot-availability-distribution --bench availability-distribution-regression-bench --features subsystem-benchmarks - tags: - - benchmark + allow_failure: true + +subsystem-benchmark-approval-voting: + extends: + - .subsystem-benchmark-template + script: + - cargo bench -p polkadot-node-core-approval-voting --bench approval-voting-regression-bench --features subsystem-benchmarks allow_failure: true diff --git a/.gitlab/pipeline/zombienet.yml b/.gitlab/pipeline/zombienet.yml index 52948e1eb719d9f8669523d9762f5662fd1b6e96..7be4ba1663e620ea34724926cf2ac52458df07d8 100644 --- a/.gitlab/pipeline/zombienet.yml +++ b/.gitlab/pipeline/zombienet.yml @@ -1,8 +1,9 @@ .zombienet-refs: extends: .build-refs variables: - ZOMBIENET_IMAGE: "docker.io/paritytech/zombienet:v1.3.99" + ZOMBIENET_IMAGE: "docker.io/paritytech/zombienet:v1.3.103" PUSHGATEWAY_URL: "http://zombienet-prometheus-pushgateway.managed-monitoring:9091/metrics/job/zombie-metrics" + DEBUG: "zombie,zombie::network-node,zombie::kube::client::logs" include: # substrate tests diff --git a/.gitlab/pipeline/zombienet/bridges.yml b/.gitlab/pipeline/zombienet/bridges.yml index 4278f59b1e9a2e33f32bf255436d6af5d31b30fb..9d7a8b9311934a148e855caf7c4315d8a281aed1 100644 --- a/.gitlab/pipeline/zombienet/bridges.yml +++ b/.gitlab/pipeline/zombienet/bridges.yml @@ -55,9 +55,9 @@ zombienet-bridges-0001-asset-transfer-works: - /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: +zombienet-bridges-0002-free-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 + - /home/nonroot/bridges-polkadot-sdk/bridges/testing/run-new-test.sh 0002-free-headers-synced-while-idle --docker - echo "Done" diff --git a/.gitlab/pipeline/zombienet/cumulus.yml b/.gitlab/pipeline/zombienet/cumulus.yml index c473f5c5fed755bfcceeeceea30a93c1d0c3403d..a7f321505bacf99df202c1469e7a75b4f0b30ba4 100644 --- a/.gitlab/pipeline/zombienet/cumulus.yml +++ b/.gitlab/pipeline/zombienet/cumulus.yml @@ -15,7 +15,6 @@ - echo "${COL_IMAGE}" - echo "${GH_DIR}" - echo "${LOCAL_DIR}" - - export DEBUG=zombie - export RELAY_IMAGE=${POLKADOT_IMAGE} - export COL_IMAGE=${COL_IMAGE} diff --git a/.gitlab/pipeline/zombienet/polkadot.yml b/.gitlab/pipeline/zombienet/polkadot.yml index 6b72075c513b73c075d1dc10c90d0461bf0e1a82..a9f0eb9303371499642e244c3b8408e42e4c78e8 100644 --- a/.gitlab/pipeline/zombienet/polkadot.yml +++ b/.gitlab/pipeline/zombienet/polkadot.yml @@ -10,7 +10,6 @@ - if [[ $CI_COMMIT_REF_NAME == *"gh-readonly-queue"* ]]; then export DOCKER_IMAGES_VERSION="${CI_COMMIT_SHORT_SHA}"; fi - export PIPELINE_IMAGE_TAG=${DOCKER_IMAGES_VERSION} - export BUILD_RELEASE_VERSION="$(cat ./artifacts/BUILD_RELEASE_VERSION)" # from build-linux-stable job - - export DEBUG=zombie,zombie::network-node - export ZOMBIENET_INTEGRATION_TEST_IMAGE="${POLKADOT_IMAGE}":${PIPELINE_IMAGE_TAG} - export COL_IMAGE="${COLANDER_IMAGE}":${PIPELINE_IMAGE_TAG} - export CUMULUS_IMAGE="docker.io/paritypr/polkadot-parachain-debug:${DOCKER_IMAGES_VERSION}" @@ -176,6 +175,14 @@ zombienet-polkadot-elastic-scaling-0002-elastic-scaling-doesnt-break-parachains: --local-dir="${LOCAL_DIR}/elastic_scaling" --test="0002-elastic-scaling-doesnt-break-parachains.zndsl" +zombienet-polkadot-functional-0012-spam-statement-distribution-requests: + extends: + - .zombienet-polkadot-common + script: + - /home/nonroot/zombie-net/scripts/ci/run-test-local-env-manager.sh + --local-dir="${LOCAL_DIR}/functional" + --test="0012-spam-statement-distribution-requests.zndsl" + zombienet-polkadot-smoke-0001-parachains-smoke-test: extends: - .zombienet-polkadot-common diff --git a/.gitlab/pipeline/zombienet/substrate.yml b/.gitlab/pipeline/zombienet/substrate.yml index 8a627c454f9f3853f04694827e1484571f5444a9..2013ffd571cf388ba154f3965c166765f40baaf6 100644 --- a/.gitlab/pipeline/zombienet/substrate.yml +++ b/.gitlab/pipeline/zombienet/substrate.yml @@ -13,7 +13,6 @@ - echo "${ZOMBIENET_IMAGE}" - echo "${GH_DIR}" - echo "${LOCAL_DIR}" - - export DEBUG=zombie,zombie::network-node - export ZOMBIENET_INTEGRATION_TEST_IMAGE="${SUBSTRATE_IMAGE}":${SUBSTRATE_IMAGE_TAG} - echo "${ZOMBIENET_INTEGRATION_TEST_IMAGE}" stage: zombienet diff --git a/Cargo.lock b/Cargo.lock index d38d973a9f03d60d01e61a0337d4af76dc740f9b..3b47bec919e3e64c7ccea335503c52a957a4c743 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -42,15 +42,6 @@ version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "aae1277d39aeec15cb388266ecc24b11c80469deae6067e17a1a7aa9e5c1f234" -[[package]] -name = "aead" -version = "0.4.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0b613b8e1e3cf911a086f53f03bf286f52fd7a7258e4fa606f0ef220d39d8877" -dependencies = [ - "generic-array 0.14.7", -] - [[package]] name = "aead" version = "0.5.2" @@ -61,18 +52,6 @@ dependencies = [ "generic-array 0.14.7", ] -[[package]] -name = "aes" -version = "0.7.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9e8b47f52ea9bae42228d07ec09eb676433d7c4ed1ebdf0f1d1c29ed446f1ab8" -dependencies = [ - "cfg-if", - "cipher 0.3.0", - "cpufeatures", - "opaque-debug 0.3.0", -] - [[package]] name = "aes" version = "0.8.3" @@ -84,31 +63,17 @@ dependencies = [ "cpufeatures", ] -[[package]] -name = "aes-gcm" -version = "0.9.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bc3be92e19a7ef47457b8e6f90707e12b6ac5d20c6f3866584fa3be0787d839f" -dependencies = [ - "aead 0.4.3", - "aes 0.7.5", - "cipher 0.3.0", - "ctr 0.7.0", - "ghash 0.4.4", - "subtle 2.5.0", -] - [[package]] name = "aes-gcm" version = "0.10.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "831010a0f742e1209b3bcea8fab6a8e149051ba6099432c8cb2cc117dec3ead1" dependencies = [ - "aead 0.5.2", - "aes 0.8.3", + "aead", + "aes", "cipher 0.4.4", - "ctr 0.9.2", - "ghash 0.5.0", + "ctr", + "ghash", "subtle 2.5.0", ] @@ -192,9 +157,9 @@ dependencies = [ "dunce", "heck 0.4.1", "proc-macro-error", - "proc-macro2 1.0.75", + "proc-macro2 1.0.82", "quote 1.0.35", - "syn 2.0.53", + "syn 2.0.61", "syn-solidity", "tiny-keccak", ] @@ -310,20 +275,6 @@ 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 1.0.75", - "quote 1.0.35", - "syn 1.0.109", -] - [[package]] name = "aquamarine" version = "0.5.0" @@ -333,9 +284,9 @@ dependencies = [ "include_dir", "itertools 0.10.5", "proc-macro-error", - "proc-macro2 1.0.75", + "proc-macro2 1.0.82", "quote 1.0.35", - "syn 2.0.53", + "syn 2.0.61", ] [[package]] @@ -564,7 +515,7 @@ checksum = "7abe79b0e4288889c4574159ab790824d0033b9fdcb2a112a3182fac2e514565" dependencies = [ "num-bigint", "num-traits", - "proc-macro2 1.0.75", + "proc-macro2 1.0.82", "quote 1.0.35", "syn 1.0.109", ] @@ -666,7 +617,7 @@ version = "0.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ae3281bc6d0fd7e549af32b52511e1302185bd688fd3359fa36423346ff682ea" dependencies = [ - "proc-macro2 1.0.75", + "proc-macro2 1.0.82", "quote 1.0.35", "syn 1.0.109", ] @@ -707,15 +658,9 @@ dependencies = [ [[package]] name = "array-bytes" -version = "4.2.0" +version = "6.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f52f63c5c1316a16a4b35eaac8b76a98248961a533f061684cb2a7cb0eafb6c6" - -[[package]] -name = "array-bytes" -version = "6.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d9b1c5a481ec30a5abd8dfbd94ab5cf1bb4e9a66be7f1b3b322f2f1170c200fd" +checksum = "6f840fb7195bcfc5e17ea40c26e5ce6d5b9ce5d584466e17703209657e459ae0" [[package]] name = "arrayref" @@ -760,7 +705,7 @@ version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "726535892e8eae7e70657b4c8ea93d26b8553afb1ce617caee529ef96d7dee6c" dependencies = [ - "proc-macro2 1.0.75", + "proc-macro2 1.0.82", "quote 1.0.35", "syn 1.0.109", "synstructure", @@ -772,7 +717,7 @@ version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2777730b2039ac0f95f093556e61b6d26cebed5393ca6f152717777cec3a42ed" dependencies = [ - "proc-macro2 1.0.75", + "proc-macro2 1.0.82", "quote 1.0.35", "syn 1.0.109", ] @@ -820,17 +765,22 @@ dependencies = [ "assert_matches", "asset-hub-rococo-runtime", "asset-test-utils", + "cumulus-pallet-parachain-system", "emulated-integration-tests-common", "frame-support", "pallet-asset-conversion", "pallet-assets", "pallet-balances", "pallet-message-queue", + "pallet-treasury", + "pallet-utility", "pallet-xcm", "parachains-common", "parity-scale-codec", "penpal-runtime", + "polkadot-runtime-common", "rococo-runtime", + "rococo-runtime-constants", "rococo-system-emulated-network", "sp-runtime", "staging-xcm", @@ -866,6 +816,7 @@ dependencies = [ "hex-literal", "log", "pallet-asset-conversion", + "pallet-asset-conversion-ops", "pallet-asset-conversion-tx-payment", "pallet-assets", "pallet-aura", @@ -879,7 +830,6 @@ dependencies = [ "pallet-nfts-runtime-api", "pallet-proxy", "pallet-session", - "pallet-state-trie-migration", "pallet-timestamp", "pallet-transaction-payment", "pallet-transaction-payment-rpc-runtime-api", @@ -916,6 +866,7 @@ dependencies = [ "staging-xcm-executor", "substrate-wasm-builder", "testnet-parachains-constants", + "xcm-fee-payment-runtime-api", ] [[package]] @@ -944,21 +895,27 @@ dependencies = [ "cumulus-pallet-xcmp-queue", "emulated-integration-tests-common", "frame-support", + "frame-system", "pallet-asset-conversion", + "pallet-asset-tx-payment", "pallet-assets", "pallet-balances", "pallet-message-queue", + "pallet-transaction-payment", "pallet-treasury", "pallet-xcm", "parachains-common", "parity-scale-codec", "penpal-runtime", "polkadot-runtime-common", + "sp-core", + "sp-keyring", "sp-runtime", "staging-xcm", "staging-xcm-executor", "westend-runtime", "westend-system-emulated-network", + "xcm-fee-payment-runtime-api", ] [[package]] @@ -990,6 +947,7 @@ dependencies = [ "hex-literal", "log", "pallet-asset-conversion", + "pallet-asset-conversion-ops", "pallet-asset-conversion-tx-payment", "pallet-assets", "pallet-aura", @@ -1003,6 +961,7 @@ dependencies = [ "pallet-nfts-runtime-api", "pallet-proxy", "pallet-session", + "pallet-state-trie-migration", "pallet-timestamp", "pallet-transaction-payment", "pallet-transaction-payment-rpc-runtime-api", @@ -1037,6 +996,7 @@ dependencies = [ "substrate-wasm-builder", "testnet-parachains-constants", "westend-runtime-constants", + "xcm-fee-payment-runtime-api", ] [[package]] @@ -1108,7 +1068,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "81953c529336010edd6d8e358f886d9581267795c61b19475b71314bffa46d35" dependencies = [ "concurrent-queue", - "event-listener 2.5.3", + "event-listener", "futures-core", ] @@ -1118,7 +1078,7 @@ version = "1.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6fa3dc5f2a8564f07759c008b9109dc0d39de92a88d5588b8a5036d286383afb" dependencies = [ - "async-lock 2.8.0", + "async-lock", "async-task", "concurrent-queue", "fastrand 1.9.0", @@ -1132,7 +1092,7 @@ version = "1.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "279cf904654eeebfa37ac9bb1598880884924aab82e290aa65c9e77a0e142e06" dependencies = [ - "async-lock 2.8.0", + "async-lock", "autocfg", "blocking", "futures-lite", @@ -1147,7 +1107,7 @@ dependencies = [ "async-channel", "async-executor", "async-io", - "async-lock 2.8.0", + "async-lock", "blocking", "futures-lite", "once_cell", @@ -1159,7 +1119,7 @@ version = "1.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0fc5b45d93ef0529756f812ca52e44c221b35341892d3dcc34132ac02f3dd2af" dependencies = [ - "async-lock 2.8.0", + "async-lock", "autocfg", "cfg-if", "concurrent-queue", @@ -1179,18 +1139,7 @@ version = "2.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "287272293e9d8c41773cec55e365490fe034813a2f172f502d6ddcf75b2f582b" dependencies = [ - "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", + "event-listener", ] [[package]] @@ -1212,11 +1161,11 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7a9d28b1d97e08915212e2e45310d47854eafa69600756fc735fb788f75199c9" dependencies = [ "async-io", - "async-lock 2.8.0", + "async-lock", "autocfg", "blocking", "cfg-if", - "event-listener 2.5.3", + "event-listener", "futures-lite", "rustix 0.37.23", "signal-hook", @@ -1233,7 +1182,7 @@ dependencies = [ "async-channel", "async-global-executor", "async-io", - "async-lock 2.8.0", + "async-lock", "crossbeam-utils", "futures-channel", "futures-core", @@ -1267,9 +1216,9 @@ version = "0.3.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "16e62a023e7c117e27523144c5d2459f4397fcc3cab0085af8e2224f643a0193" dependencies = [ - "proc-macro2 1.0.75", + "proc-macro2 1.0.82", "quote 1.0.35", - "syn 2.0.53", + "syn 2.0.61", ] [[package]] @@ -1284,9 +1233,9 @@ version = "0.1.79" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a507401cad91ec6a857ed5513a2073c82a9b9048762b885bb98655b306964681" dependencies = [ - "proc-macro2 1.0.75", + "proc-macro2 1.0.82", "quote 1.0.35", - "syn 2.0.53", + "syn 2.0.61", ] [[package]] @@ -1332,7 +1281,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fee3da8ef1276b0bee5dd1c7258010d8fffd31801447323115a25560e1327b89" dependencies = [ "proc-macro-error", - "proc-macro2 1.0.75", + "proc-macro2 1.0.82", "quote 1.0.35", "syn 1.0.109", ] @@ -1386,7 +1335,7 @@ dependencies = [ "rand_chacha 0.3.1", "rand_core 0.6.4", "ring 0.1.0", - "sha2 0.10.7", + "sha2 0.10.8", "sp-ark-bls12-381", "sp-ark-ed-on-bls12-381-bandersnatch", "zeroize", @@ -1444,7 +1393,7 @@ dependencies = [ name = "binary-merkle-tree" version = "13.0.0" dependencies = [ - "array-bytes 6.1.0", + "array-bytes", "env_logger 0.11.3", "hash-db", "log", @@ -1474,12 +1423,12 @@ dependencies = [ "lazycell", "peeking_take_while", "prettyplease 0.2.12", - "proc-macro2 1.0.75", + "proc-macro2 1.0.82", "quote 1.0.35", "regex", "rustc-hash", "shlex", - "syn 2.0.53", + "syn 2.0.61", ] [[package]] @@ -1646,7 +1595,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "77231a1c8f801696fc0123ec6150ce92cffb8e164a02afb9c8ddee0e9b65ad65" dependencies = [ "async-channel", - "async-lock 2.8.0", + "async-lock", "async-task", "atomic-waker", "fastrand 1.9.0", @@ -2146,6 +2095,7 @@ dependencies = [ "static_assertions", "substrate-wasm-builder", "testnet-parachains-constants", + "tuplex", ] [[package]] @@ -2215,7 +2165,6 @@ dependencies = [ "pallet-message-queue", "pallet-xcm", "parachains-common", - "parity-scale-codec", "rococo-westend-system-emulated-network", "sp-runtime", "staging-xcm", @@ -2305,6 +2254,7 @@ dependencies = [ "static_assertions", "substrate-wasm-builder", "testnet-parachains-constants", + "tuplex", "westend-runtime-constants", ] @@ -2343,6 +2293,7 @@ dependencies = [ "staging-xcm", "staging-xcm-builder", "static_assertions", + "tuplex", ] [[package]] @@ -2531,18 +2482,6 @@ dependencies = [ "keystream", ] -[[package]] -name = "chacha20" -version = "0.8.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5c80e5460aa66fe3b91d40bcbdab953a597b60053e34d684ac6903f863b680a6" -dependencies = [ - "cfg-if", - "cipher 0.3.0", - "cpufeatures", - "zeroize", -] - [[package]] name = "chacha20" version = "0.9.1" @@ -2556,14 +2495,14 @@ dependencies = [ [[package]] name = "chacha20poly1305" -version = "0.9.1" +version = "0.10.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a18446b09be63d457bbec447509e85f662f32952b035ce892290396bc0b0cff5" +checksum = "10cd79432192d1c0f4e1a0fef9527696cc039165d729fb41b3f4f4f354c2dc35" dependencies = [ - "aead 0.4.3", - "chacha20 0.8.2", - "cipher 0.3.0", - "poly1305 0.7.2", + "aead", + "chacha20", + "cipher 0.4.4", + "poly1305", "zeroize", ] @@ -2643,15 +2582,6 @@ dependencies = [ "generic-array 0.14.7", ] -[[package]] -name = "cipher" -version = "0.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7ee52072ec15386f770805afd189a01c8841be8696bed250fa2f13c4c0d6dfb7" -dependencies = [ - "generic-array 0.14.7", -] - [[package]] name = "cipher" version = "0.4.4" @@ -2660,6 +2590,7 @@ checksum = "773f3b9af64447d2ce9850330c473515014aa235e6a783b02db81ff39e4a3dad" dependencies = [ "crypto-common", "inout", + "zeroize", ] [[package]] @@ -2671,6 +2602,15 @@ dependencies = [ "cfg-if", ] +[[package]] +name = "ckb-merkle-mountain-range" +version = "0.6.0" +source = "git+https://github.com/paritytech/merkle-mountain-range.git?branch=master#537f0e3f67c5adf7afff0800bbb81f02f17570a1" +dependencies = [ + "cfg-if", + "itertools 0.10.5", +] + [[package]] name = "clang-sys" version = "1.6.1" @@ -2763,7 +2703,7 @@ checksum = "ae6371b8bdc8b7d3959e9cf7b22d4435ef3e79e138688421ec654acf8c81b008" dependencies = [ "heck 0.4.1", "proc-macro-error", - "proc-macro2 1.0.75", + "proc-macro2 1.0.82", "quote 1.0.35", "syn 1.0.109", ] @@ -2775,9 +2715,9 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "90239a040c80f5e14809ca132ddc4176ab33d5e17e49691793296e3fcb34d72f" dependencies = [ "heck 0.5.0", - "proc-macro2 1.0.75", + "proc-macro2 1.0.82", "quote 1.0.35", - "syn 2.0.53", + "syn 2.0.61", ] [[package]] @@ -2830,6 +2770,36 @@ dependencies = [ "testnet-parachains-constants", ] +[[package]] +name = "collectives-westend-integration-tests" +version = "1.0.0" +dependencies = [ + "assert_matches", + "asset-hub-westend-runtime", + "collectives-westend-runtime", + "cumulus-pallet-parachain-system", + "cumulus-pallet-xcmp-queue", + "emulated-integration-tests-common", + "frame-support", + "pallet-asset-rate", + "pallet-assets", + "pallet-balances", + "pallet-message-queue", + "pallet-treasury", + "pallet-utility", + "pallet-xcm", + "parachains-common", + "parity-scale-codec", + "polkadot-runtime-common", + "sp-runtime", + "staging-xcm", + "staging-xcm-executor", + "testnet-parachains-constants", + "westend-runtime", + "westend-runtime-constants", + "westend-system-emulated-network", +] + [[package]] name = "collectives-westend-runtime" version = "3.0.0" @@ -2870,6 +2840,7 @@ dependencies = [ "pallet-salary", "pallet-scheduler", "pallet-session", + "pallet-state-trie-migration", "pallet-timestamp", "pallet-transaction-payment", "pallet-transaction-payment-rpc-runtime-api", @@ -2934,7 +2905,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d51beaa537d73d2d1ff34ee70bc095f170420ab2ec5d687ecd3ec2b0d092514b" dependencies = [ "nom", - "proc-macro2 1.0.75", + "proc-macro2 1.0.82", "quote 1.0.35", "syn 1.0.109", ] @@ -3479,34 +3450,6 @@ dependencies = [ "cfg-if", ] -[[package]] -name = "criterion" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e7c76e09c1aae2bc52b3d2f29e13c6572553b30c4aa1b8a49fd70de6412654cb" -dependencies = [ - "anes", - "atty", - "cast", - "ciborium", - "clap 3.2.25", - "criterion-plot", - "futures", - "itertools 0.10.5", - "lazy_static", - "num-traits", - "oorandom", - "plotters", - "rayon", - "regex", - "serde", - "serde_derive", - "serde_json", - "tinytemplate", - "tokio", - "walkdir", -] - [[package]] name = "criterion" version = "0.5.1" @@ -3637,15 +3580,6 @@ dependencies = [ "subtle 2.5.0", ] -[[package]] -name = "ctr" -version = "0.7.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a232f92a03f37dd7d7dd2adc67166c77e9cd88de5b019b9a9eecfaeaf7bfd481" -dependencies = [ - "cipher 0.3.0", -] - [[package]] name = "ctr" version = "0.9.2" @@ -4010,6 +3944,7 @@ dependencies = [ "sp-trie", "sp-version", "staging-xcm", + "staging-xcm-builder", "trie-db", "trie-standardmap", ] @@ -4018,10 +3953,10 @@ dependencies = [ name = "cumulus-pallet-parachain-system-proc-macro" version = "0.6.0" dependencies = [ - "proc-macro-crate 3.0.0", - "proc-macro2 1.0.75", + "proc-macro-crate 3.1.0", + "proc-macro2 1.0.82", "quote 1.0.35", - "syn 2.0.53", + "syn 2.0.61", ] [[package]] @@ -4265,7 +4200,7 @@ dependencies = [ name = "cumulus-relay-chain-minimal-node" version = "0.7.0" dependencies = [ - "array-bytes 6.1.0", + "array-bytes", "async-trait", "cumulus-primitives-core", "cumulus-relay-chain-interface", @@ -4437,7 +4372,7 @@ version = "0.1.0" dependencies = [ "async-trait", "clap 4.5.3", - "criterion 0.5.1", + "criterion", "cumulus-client-cli", "cumulus-client-collator", "cumulus-client-consensus-aura", @@ -4580,9 +4515,9 @@ version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "83fdaf97f4804dcebfa5862639bc9ce4121e82140bec2a987ac5140294865b5b" dependencies = [ - "proc-macro2 1.0.75", + "proc-macro2 1.0.82", "quote 1.0.35", - "syn 2.0.53", + "syn 2.0.61", ] [[package]] @@ -4619,10 +4554,10 @@ dependencies = [ "cc", "codespan-reporting", "once_cell", - "proc-macro2 1.0.75", + "proc-macro2 1.0.82", "quote 1.0.35", "scratch", - "syn 2.0.53", + "syn 2.0.61", ] [[package]] @@ -4637,9 +4572,9 @@ version = "1.0.106" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "50c49547d73ba8dcfd4ad7325d64c6d5391ff4224d498fc39a6f3f49825a530d" dependencies = [ - "proc-macro2 1.0.75", + "proc-macro2 1.0.82", "quote 1.0.35", - "syn 2.0.53", + "syn 2.0.61", ] [[package]] @@ -4726,7 +4661,7 @@ version = "2.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fcc3dd5e9e9c0b295d6e1e4d811fb6f157d5ffd784b8d202fc62eac8035a770b" dependencies = [ - "proc-macro2 1.0.75", + "proc-macro2 1.0.82", "quote 1.0.35", "syn 1.0.109", ] @@ -4737,7 +4672,7 @@ version = "0.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e79116f119dd1dba1abf1f3405f03b9b0e79a27a3883864bfebded8a3dc768cd" dependencies = [ - "proc-macro2 1.0.75", + "proc-macro2 1.0.82", "quote 1.0.35", "syn 1.0.109", ] @@ -4748,9 +4683,9 @@ version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d65d7ce8132b7c0e54497a4d9a55a1c2a0912a0d786cf894472ba818fba45762" dependencies = [ - "proc-macro2 1.0.75", + "proc-macro2 1.0.82", "quote 1.0.35", - "syn 2.0.53", + "syn 2.0.61", ] [[package]] @@ -4760,7 +4695,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4fb810d30a7c1953f91334de7244731fc3f3c10d7fe163338a35b9f640960321" dependencies = [ "convert_case", - "proc-macro2 1.0.75", + "proc-macro2 1.0.82", "quote 1.0.35", "rustc_version 0.4.0", "syn 1.0.109", @@ -4856,9 +4791,9 @@ version = "0.2.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "487585f4d0c6655fe74905e2504d8ad6908e4db67f744eb140876906c2f3175d" dependencies = [ - "proc-macro2 1.0.75", + "proc-macro2 1.0.82", "quote 1.0.35", - "syn 2.0.53", + "syn 2.0.61", ] [[package]] @@ -4916,10 +4851,10 @@ dependencies = [ "common-path", "derive-syn-parse 0.2.0", "once_cell", - "proc-macro2 1.0.75", + "proc-macro2 1.0.82", "quote 1.0.35", "regex", - "syn 2.0.53", + "syn 2.0.61", "termcolor", "toml 0.8.8", "walkdir", @@ -4965,7 +4900,7 @@ version = "0.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "558e40ea573c374cf53507fd240b7ee2f5477df7cfebdb97323ec61c719399c5" dependencies = [ - "proc-macro2 1.0.75", + "proc-macro2 1.0.82", "quote 1.0.35", "syn 1.0.109", ] @@ -5034,25 +4969,11 @@ dependencies = [ "ed25519 2.2.2", "rand_core 0.6.4", "serde", - "sha2 0.10.7", + "sha2 0.10.8", "subtle 2.5.0", "zeroize", ] -[[package]] -name = "ed25519-zebra" -version = "3.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7c24f403d068ad0b359e577a77f92392118be3f3c927538f2bb544a5ecd828c6" -dependencies = [ - "curve25519-dalek 3.2.0", - "hashbrown 0.12.3", - "hex", - "rand_core 0.6.4", - "sha2 0.9.9", - "zeroize", -] - [[package]] name = "ed25519-zebra" version = "4.0.3" @@ -5064,7 +4985,7 @@ dependencies = [ "hashbrown 0.14.3", "hex", "rand_core 0.6.4", - "sha2 0.10.7", + "sha2 0.10.8", "zeroize", ] @@ -5148,7 +5069,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c9720bba047d567ffc8a3cba48bf19126600e249ab7f128e9233e6376976a116" dependencies = [ "heck 0.4.1", - "proc-macro2 1.0.75", + "proc-macro2 1.0.82", "quote 1.0.35", "syn 1.0.109", ] @@ -5160,9 +5081,9 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5ffccbb6966c05b32ef8fbac435df276c4ae4d3dc55a8cd0eb9745e6c12f546a" dependencies = [ "heck 0.4.1", - "proc-macro2 1.0.75", + "proc-macro2 1.0.82", "quote 1.0.35", - "syn 2.0.53", + "syn 2.0.61", ] [[package]] @@ -5180,9 +5101,9 @@ version = "0.7.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5e9a1f9f7d83e59740248a6e14ecf93929ade55027844dfcea78beafccc15745" dependencies = [ - "proc-macro2 1.0.75", + "proc-macro2 1.0.82", "quote 1.0.35", - "syn 2.0.53", + "syn 2.0.61", ] [[package]] @@ -5191,9 +5112,9 @@ version = "0.1.12" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c2ad8cef1d801a4686bfd8919f0b30eac4c8e48968c437a6405ded4fb5272d2b" dependencies = [ - "proc-macro2 1.0.75", + "proc-macro2 1.0.82", "quote 1.0.35", - "syn 2.0.53", + "syn 2.0.61", ] [[package]] @@ -5216,6 +5137,19 @@ dependencies = [ "regex", ] +[[package]] +name = "env_logger" +version = "0.9.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a12e6657c4c97ebab115a42dcee77225f7f482cdd841cf7088c657a42e9e00e7" +dependencies = [ + "atty", + "humantime", + "log", + "regex", + "termcolor", +] + [[package]] name = "env_logger" version = "0.10.1" @@ -5356,27 +5290,6 @@ 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" @@ -5386,18 +5299,6 @@ dependencies = [ "futures", ] -[[package]] -name = "expander" -version = "0.0.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a718c0675c555c5f976fff4ea9e2c150fa06cefa201cadef87cfbf9324075881" -dependencies = [ - "blake3", - "fs-err", - "proc-macro2 1.0.75", - "quote 1.0.35", -] - [[package]] name = "expander" version = "2.0.0" @@ -5406,9 +5307,9 @@ checksum = "5f86a749cf851891866c10515ef6c299b5c69661465e9c3bbe7e07a2b77fb0f7" dependencies = [ "blake2 0.10.6", "fs-err", - "proc-macro2 1.0.75", + "proc-macro2 1.0.82", "quote 1.0.35", - "syn 2.0.53", + "syn 2.0.61", ] [[package]] @@ -5461,9 +5362,9 @@ dependencies = [ [[package]] name = "fatality" -version = "0.0.6" +version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2ad875162843b0d046276327afe0136e9ed3a23d5a754210fb6f1f33610d39ab" +checksum = "ec6f82451ff7f0568c6181287189126d492b5654e30a788add08027b6363d019" dependencies = [ "fatality-proc-macro", "thiserror", @@ -5471,17 +5372,16 @@ dependencies = [ [[package]] name = "fatality-proc-macro" -version = "0.0.6" +version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f5aa1e3ae159e592ad222dc90c5acbad632b527779ba88486abe92782ab268bd" +checksum = "eb42427514b063d97ce21d5199f36c0c307d981434a6be32582bc79fe5bd2303" dependencies = [ - "expander 0.0.4", - "indexmap 1.9.3", - "proc-macro-crate 1.3.1", - "proc-macro2 1.0.75", + "expander", + "indexmap 2.2.3", + "proc-macro-crate 3.1.0", + "proc-macro2 1.0.82", "quote 1.0.35", - "syn 1.0.109", - "thiserror", + "syn 2.0.61", ] [[package]] @@ -5680,6 +5580,16 @@ dependencies = [ "percent-encoding", ] +[[package]] +name = "forwarded-header-value" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8835f84f38484cc86f110a805655697908257fb9a7af005234060891557198e9" +dependencies = [ + "nonempty", + "thiserror", +] + [[package]] name = "fraction" version = "0.13.1" @@ -5700,7 +5610,7 @@ checksum = "6c2141d6d6c8512188a7891b4b01590a45f6dac67afb4f255c4124dbb86d4eaa" name = "frame-benchmarking" version = "28.0.0" dependencies = [ - "array-bytes 6.1.0", + "array-bytes", "frame-support", "frame-support-procedural", "frame-system", @@ -5728,7 +5638,7 @@ name = "frame-benchmarking-cli" version = "32.0.0" dependencies = [ "Inflector", - "array-bytes 6.1.0", + "array-bytes", "chrono", "clap 4.5.3", "comfy-table", @@ -5737,7 +5647,7 @@ dependencies = [ "frame-system", "gethostname", "handlebars", - "itertools 0.10.5", + "itertools 0.11.0", "lazy_static", "linked-hash-map", "log", @@ -5793,12 +5703,12 @@ dependencies = [ "frame-election-provider-support", "frame-support", "parity-scale-codec", - "proc-macro-crate 3.0.0", - "proc-macro2 1.0.75", + "proc-macro-crate 3.1.0", + "proc-macro2 1.0.82", "quote 1.0.35", "scale-info", "sp-arithmetic", - "syn 2.0.53", + "syn 2.0.61", "trybuild", ] @@ -5841,8 +5751,8 @@ dependencies = [ name = "frame-executive" version = "28.0.0" dependencies = [ - "aquamarine 0.3.3", - "array-bytes 6.1.0", + "aquamarine", + "array-bytes", "frame-support", "frame-system", "frame-try-runtime", @@ -5912,8 +5822,8 @@ dependencies = [ name = "frame-support" version = "28.0.0" dependencies = [ - "aquamarine 0.5.0", - "array-bytes 6.1.0", + "aquamarine", + "array-bytes", "assert_matches", "bitflags 1.3.2", "docify", @@ -5960,16 +5870,16 @@ dependencies = [ "Inflector", "cfg-expr", "derive-syn-parse 0.2.0", - "expander 2.0.0", + "expander", "frame-support-procedural-tools", - "itertools 0.10.5", + "itertools 0.11.0", "macro_magic", "proc-macro-warning", - "proc-macro2 1.0.75", + "proc-macro2 1.0.82", "quote 1.0.35", "regex", "sp-crypto-hashing", - "syn 2.0.53", + "syn 2.0.61", ] [[package]] @@ -5977,19 +5887,19 @@ name = "frame-support-procedural-tools" version = "10.0.0" dependencies = [ "frame-support-procedural-tools-derive", - "proc-macro-crate 3.0.0", - "proc-macro2 1.0.75", + "proc-macro-crate 3.1.0", + "proc-macro2 1.0.82", "quote 1.0.35", - "syn 2.0.53", + "syn 2.0.61", ] [[package]] name = "frame-support-procedural-tools-derive" version = "11.0.0" dependencies = [ - "proc-macro2 1.0.75", + "proc-macro2 1.0.82", "quote 1.0.35", - "syn 2.0.53", + "syn 2.0.61", ] [[package]] @@ -6059,7 +5969,7 @@ name = "frame-system" version = "28.0.0" dependencies = [ "cfg-if", - "criterion 0.4.0", + "criterion", "docify", "frame-support", "log", @@ -6220,9 +6130,9 @@ version = "0.3.30" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "87750cf4b7a4c0625b1529e4c543c2182106e4dedc60a2a6455e00d212c489ac" dependencies = [ - "proc-macro2 1.0.75", + "proc-macro2 1.0.82", "quote 1.0.35", - "syn 2.0.53", + "syn 2.0.61", ] [[package]] @@ -6356,16 +6266,6 @@ dependencies = [ "rand_core 0.6.4", ] -[[package]] -name = "ghash" -version = "0.4.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1583cc1656d7839fd3732b80cf4f38850336cdb9b8ded1cd399ca62958de3c99" -dependencies = [ - "opaque-debug 0.3.0", - "polyval 0.5.3", -] - [[package]] name = "ghash" version = "0.5.0" @@ -6373,7 +6273,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d930750de5717d2dd0b8c0d42c076c0e884c81a73e6cab859bbd2339c71e3e40" dependencies = [ "opaque-debug 0.3.0", - "polyval 0.6.1", + "polyval", ] [[package]] @@ -6901,7 +6801,7 @@ version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "11d7a9f6330b71fea57921c9b61c47ee6e84f72d394754eff6163ae67e7395eb" dependencies = [ - "proc-macro2 1.0.75", + "proc-macro2 1.0.82", "quote 1.0.35", "syn 1.0.109", ] @@ -6921,7 +6821,7 @@ version = "0.7.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b139284b5cf57ecfa712bcc66950bb635b31aff41c188e8a4cfc758eca374a3f" dependencies = [ - "proc-macro2 1.0.75", + "proc-macro2 1.0.82", "quote 1.0.35", ] @@ -7071,7 +6971,7 @@ dependencies = [ "curl", "curl-sys", "encoding_rs", - "event-listener 2.5.3", + "event-listener", "futures-lite", "http", "log", @@ -7147,9 +7047,9 @@ dependencies = [ [[package]] name = "jsonrpsee" -version = "0.22.2" +version = "0.22.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "87f3ae45a64cfc0882934f963be9431b2a165d667f53140358181f262aca0702" +checksum = "cfdb12a2381ea5b2e68c3469ec604a007b367778cdb14d09612c8069ebd616ad" dependencies = [ "jsonrpsee-core", "jsonrpsee-http-client", @@ -7163,9 +7063,9 @@ dependencies = [ [[package]] name = "jsonrpsee-client-transport" -version = "0.22.2" +version = "0.22.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "455fc882e56f58228df2aee36b88a1340eafd707c76af2fa68cf94b37d461131" +checksum = "4978087a58c3ab02efc5b07c5e5e2803024536106fd5506f558db172c889b3aa" dependencies = [ "futures-util", "http", @@ -7184,12 +7084,11 @@ dependencies = [ [[package]] name = "jsonrpsee-core" -version = "0.22.2" +version = "0.22.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b75568f4f9696e3a47426e1985b548e1a9fcb13372a5e320372acaf04aca30d1" +checksum = "b4b257e1ec385e07b0255dde0b933f948b5c8b8c28d42afda9587c3a967b896d" dependencies = [ "anyhow", - "async-lock 3.3.0", "async-trait", "beef", "futures-timer", @@ -7210,9 +7109,9 @@ dependencies = [ [[package]] name = "jsonrpsee-http-client" -version = "0.22.2" +version = "0.22.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9e7a95e346f55df84fb167b7e06470e196e7d5b9488a21d69c5d9732043ba7ba" +checksum = "1ccf93fc4a0bfe05d851d37d7c32b7f370fe94336b52a2f0efc5f1981895c2e5" dependencies = [ "async-trait", "hyper", @@ -7230,22 +7129,22 @@ dependencies = [ [[package]] name = "jsonrpsee-proc-macros" -version = "0.22.2" +version = "0.22.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "30ca066e73dd70294aebc5c2675d8ffae43be944af027c857ce0d4c51785f014" +checksum = "7d0bb047e79a143b32ea03974a6bf59b62c2a4c5f5d42a381c907a8bbb3f75c0" dependencies = [ "heck 0.4.1", - "proc-macro-crate 3.0.0", - "proc-macro2 1.0.75", + "proc-macro-crate 3.1.0", + "proc-macro2 1.0.82", "quote 1.0.35", - "syn 2.0.53", + "syn 2.0.61", ] [[package]] name = "jsonrpsee-server" -version = "0.22.2" +version = "0.22.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0e29c1bd1f9bba83c864977c73404e505f74f730fa0db89dd490ec174e36d7f0" +checksum = "12d8b6a9674422a8572e0b0abb12feeb3f2aeda86528c80d0350c2bd0923ab41" dependencies = [ "futures-util", "http", @@ -7267,9 +7166,9 @@ dependencies = [ [[package]] name = "jsonrpsee-types" -version = "0.22.2" +version = "0.22.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3467fd35feeee179f71ab294516bdf3a81139e7aeebdd860e46897c12e1a3368" +checksum = "150d6168405890a7a3231a3c74843f58b8959471f6df76078db2619ddee1d07d" dependencies = [ "anyhow", "beef", @@ -7280,9 +7179,9 @@ dependencies = [ [[package]] name = "jsonrpsee-ws-client" -version = "0.22.2" +version = "0.22.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "68ca71e74983f624c0cb67828e480a981586074da8ad3a2f214c6a3f884edab9" +checksum = "58b9db2dfd5bb1194b0ce921504df9ceae210a345bc2f6c5a61432089bbab070" dependencies = [ "http", "jsonrpsee-client-transport", @@ -7302,7 +7201,7 @@ dependencies = [ "elliptic-curve", "once_cell", "serdect", - "sha2 0.10.7", + "sha2 0.10.8", ] [[package]] @@ -7348,6 +7247,7 @@ dependencies = [ "node-primitives", "pallet-alliance", "pallet-asset-conversion", + "pallet-asset-conversion-ops", "pallet-asset-conversion-tx-payment", "pallet-asset-rate", "pallet-asset-tx-payment", @@ -7537,9 +7437,9 @@ checksum = "884e2677b40cc8c339eaefcb701c32ef1fd2493d71118dc0ca4b6a736c93bd67" [[package]] name = "libc" -version = "0.2.152" +version = "0.2.153" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "13e3bf6590cbc649f4d1a3eefc9d5d6eb746f5200ffb04e5e142700b8faa56e7" +checksum = "9c198f91728a82281a64e1f4f9eeb25d82cb32a5de251c6bd1b5154d63a8e7bd" [[package]] name = "libflate" @@ -7732,7 +7632,7 @@ dependencies = [ "multihash 0.17.0", "quick-protobuf", "rand 0.8.5", - "sha2 0.10.7", + "sha2 0.10.8", "thiserror", "zeroize", ] @@ -7757,7 +7657,7 @@ dependencies = [ "log", "quick-protobuf", "rand 0.8.5", - "sha2 0.10.7", + "sha2 0.10.8", "smallvec", "thiserror", "uint", @@ -7815,7 +7715,7 @@ dependencies = [ "once_cell", "quick-protobuf", "rand 0.8.5", - "sha2 0.10.7", + "sha2 0.10.8", "snow", "static_assertions", "thiserror", @@ -8150,7 +8050,7 @@ dependencies = [ [[package]] name = "litep2p" version = "0.3.0" -source = "git+https://github.com/paritytech/litep2p?branch=master#08112ca642cea3809625ae0abde05dc0dc46b4f3" +source = "git+https://github.com/paritytech/litep2p?rev=e03a6023882db111beeb24d8c0ceaac0721d3f0f#e03a6023882db111beeb24d8c0ceaac0721d3f0f" dependencies = [ "async-trait", "bs58 0.4.0", @@ -8170,14 +8070,14 @@ dependencies = [ "parking_lot 0.12.1", "pin-project", "prost 0.11.9", - "prost-build", + "prost-build 0.11.9", "quinn", "rand 0.8.5", "rcgen", "ring 0.16.20", "rustls 0.20.8", "serde", - "sha2 0.10.7", + "sha2 0.10.8", "simple-dns", "smallvec", "snow", @@ -8187,7 +8087,7 @@ dependencies = [ "thiserror", "tokio", "tokio-stream", - "tokio-tungstenite 0.20.1", + "tokio-tungstenite", "tokio-util", "tracing", "trust-dns-resolver 0.23.2", @@ -8301,7 +8201,7 @@ dependencies = [ "macro_magic_core", "macro_magic_macros", "quote 1.0.35", - "syn 2.0.53", + "syn 2.0.61", ] [[package]] @@ -8313,9 +8213,9 @@ dependencies = [ "const-random", "derive-syn-parse 0.1.5", "macro_magic_core_macros", - "proc-macro2 1.0.75", + "proc-macro2 1.0.82", "quote 1.0.35", - "syn 2.0.53", + "syn 2.0.61", ] [[package]] @@ -8324,9 +8224,9 @@ version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9ea73aa640dc01d62a590d48c0c3521ed739d53b27f919b25c3551e233481654" dependencies = [ - "proc-macro2 1.0.75", + "proc-macro2 1.0.82", "quote 1.0.35", - "syn 2.0.53", + "syn 2.0.61", ] [[package]] @@ -8337,7 +8237,7 @@ checksum = "ef9d79ae96aaba821963320eb2b6e34d17df1e5a83d8a1985c29cc5be59577b3" dependencies = [ "macro_magic_core", "quote 1.0.35", - "syn 2.0.53", + "syn 2.0.61", ] [[package]] @@ -8419,15 +8319,6 @@ dependencies = [ "libc", ] -[[package]] -name = "memoffset" -version = "0.7.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5de893c32cde5f383baa4c04c5d6dbdd735cfd4a794b0debdb2bb1b421da5ff4" -dependencies = [ - "autocfg", -] - [[package]] name = "memoffset" version = "0.8.0" @@ -8508,6 +8399,19 @@ version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a" +[[package]] +name = "minimal-template" +version = "0.0.0" +dependencies = [ + "docify", + "minimal-template-node", + "minimal-template-runtime", + "pallet-minimal-template", + "polkadot-sdk-docs", + "polkadot-sdk-frame", + "simple-mermaid 0.1.1", +] + [[package]] name = "minimal-template-node" version = "0.0.0" @@ -8666,7 +8570,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "22ce75669015c4f47b289fd4d4f56e894e4c96003ffdf3ac51313126f94c6cbb" dependencies = [ "cfg-if", - "proc-macro2 1.0.75", + "proc-macro2 1.0.82", "quote 1.0.35", "syn 1.0.109", ] @@ -8713,7 +8617,7 @@ dependencies = [ "core2", "digest 0.10.7", "multihash-derive 0.8.0", - "sha2 0.10.7", + "sha2 0.10.8", "sha3", "unsigned-varint", ] @@ -8730,7 +8634,7 @@ dependencies = [ "core2", "digest 0.10.7", "multihash-derive 0.8.0", - "sha2 0.10.7", + "sha2 0.10.8", "sha3", "unsigned-varint", ] @@ -8760,7 +8664,7 @@ dependencies = [ "ripemd", "serde", "sha1", - "sha2 0.10.7", + "sha2 0.10.8", "sha3", "strobe-rs", ] @@ -8773,7 +8677,7 @@ checksum = "fc076939022111618a5026d3be019fd8b366e76314538ff9a1b59ffbcbf98bcd" dependencies = [ "proc-macro-crate 1.3.1", "proc-macro-error", - "proc-macro2 1.0.75", + "proc-macro2 1.0.82", "quote 1.0.35", "syn 1.0.109", "synstructure", @@ -8798,7 +8702,7 @@ checksum = "d38685e08adb338659871ecfc6ee47ba9b22dcc8abcf6975d379cc49145c3040" dependencies = [ "proc-macro-crate 1.3.1", "proc-macro-error", - "proc-macro2 1.0.75", + "proc-macro2 1.0.82", "quote 1.0.35", "syn 1.0.109", "synstructure", @@ -8846,7 +8750,7 @@ version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "91761aed67d03ad966ef783ae962ef9bbaca728d2dd7ceb7939ec110fffad998" dependencies = [ - "proc-macro2 1.0.75", + "proc-macro2 1.0.82", "quote 1.0.35", "syn 1.0.109", ] @@ -8965,19 +8869,18 @@ dependencies = [ "bitflags 1.3.2", "cfg-if", "libc", - "memoffset 0.7.1", - "pin-utils", "static_assertions", ] [[package]] name = "nix" -version = "0.27.1" +version = "0.28.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2eb04e9c688eff1c89d72b407f168cf79bb9e867a9d3323ed6c01519eb9cc053" +checksum = "ab2156c4fce2f8df6c499cc1c763e4394b7482525bf2a9701c9d79d215f519e4" dependencies = [ "bitflags 2.4.0", "cfg-if", + "cfg_aliases", "libc", ] @@ -8997,7 +8900,7 @@ checksum = "43794a0ace135be66a25d3ae77d41b91615fb68ae937f904090203e81f755b65" name = "node-bench" version = "0.9.0-dev" dependencies = [ - "array-bytes 6.1.0", + "array-bytes", "clap 4.5.3", "derive_more", "fs_extra", @@ -9088,7 +8991,7 @@ dependencies = [ "flate2", "fs_extra", "glob", - "itertools 0.10.5", + "itertools 0.11.0", "tar", "tempfile", "toml_edit 0.19.15", @@ -9154,6 +9057,12 @@ dependencies = [ "minimal-lexical", ] +[[package]] +name = "nonempty" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e9e591e719385e6ebaeb5ce5d3887f7d5676fceca6411d1925ccc95745f3d6f7" + [[package]] name = "nonzero_ext" version = "0.3.0" @@ -9372,9 +9281,9 @@ version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a948666b637a0f465e8564c73e89d4dde00d72d4d473cc972f390fc3dcee7d9c" dependencies = [ - "proc-macro2 1.0.75", + "proc-macro2 1.0.82", "quote 1.0.35", - "syn 2.0.53", + "syn 2.0.61", ] [[package]] @@ -9413,9 +9322,9 @@ checksum = "04744f49eae99ab78e0d5c0b603ab218f515ea8cfe5a456d7629ad883a3b6e7d" [[package]] name = "orchestra" -version = "0.3.5" +version = "0.3.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2356622ffdfe72362a45a1e5e87bb113b8327e596e39b91f11f0ef4395c8da79" +checksum = "92829eef0328a3d1cd22a02c0e51deb92a5362df3e7d21a4e9bdc38934694e66" dependencies = [ "async-trait", "dyn-clonable", @@ -9430,16 +9339,16 @@ dependencies = [ [[package]] name = "orchestra-proc-macro" -version = "0.3.5" +version = "0.3.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eedb646674596266dc9bb2b5c7eea7c36b32ecc7777eba0d510196972d72c4fd" +checksum = "1344346d5af32c95bbddea91b18a88cc83eac394192d20ef2fc4c40a74332355" dependencies = [ - "expander 2.0.0", + "expander", "indexmap 2.2.3", "itertools 0.11.0", "petgraph", - "proc-macro-crate 1.3.1", - "proc-macro2 1.0.75", + "proc-macro-crate 3.1.0", + "proc-macro2 1.0.82", "quote 1.0.35", "syn 1.0.109", ] @@ -9475,36 +9384,58 @@ checksum = "c1b04fb49957986fdce4d6ee7a65027d55d4b6d2265e5848bbb507b58ccfdb6f" name = "pallet-alliance" version = "27.0.0" dependencies = [ - "array-bytes 6.1.0", + "array-bytes", "frame-benchmarking", "frame-support", "frame-system", "log", "pallet-balances", - "pallet-collective", - "pallet-identity", + "pallet-collective", + "pallet-identity", + "parity-scale-codec", + "scale-info", + "sp-core", + "sp-crypto-hashing", + "sp-io", + "sp-runtime", + "sp-std 14.0.0", +] + +[[package]] +name = "pallet-asset-conversion" +version = "10.0.0" +dependencies = [ + "frame-benchmarking", + "frame-support", + "frame-system", + "log", + "pallet-assets", + "pallet-balances", "parity-scale-codec", + "primitive-types", "scale-info", + "sp-api", + "sp-arithmetic", "sp-core", - "sp-crypto-hashing", "sp-io", "sp-runtime", "sp-std 14.0.0", ] [[package]] -name = "pallet-asset-conversion" -version = "10.0.0" +name = "pallet-asset-conversion-ops" +version = "0.1.0" dependencies = [ "frame-benchmarking", "frame-support", "frame-system", + "log", + "pallet-asset-conversion", "pallet-assets", "pallet-balances", "parity-scale-codec", "primitive-types", "scale-info", - "sp-api", "sp-arithmetic", "sp-core", "sp-io", @@ -9571,7 +9502,7 @@ dependencies = [ [[package]] name = "pallet-assets" -version = "29.0.0" +version = "29.1.0" dependencies = [ "frame-benchmarking", "frame-support", @@ -9683,7 +9614,7 @@ dependencies = [ name = "pallet-bags-list" version = "27.0.0" dependencies = [ - "aquamarine 0.5.0", + "aquamarine", "docify", "frame-benchmarking", "frame-election-provider-support", @@ -9779,7 +9710,7 @@ dependencies = [ name = "pallet-beefy-mmr" version = "28.0.0" dependencies = [ - "array-bytes 6.1.0", + "array-bytes", "binary-merkle-tree", "frame-support", "frame-system", @@ -9825,7 +9756,7 @@ dependencies = [ "bp-beefy", "bp-runtime", "bp-test-utils", - "ckb-merkle-mountain-range", + "ckb-merkle-mountain-range 0.5.2", "frame-support", "frame-system", "log", @@ -9936,6 +9867,7 @@ dependencies = [ "frame-benchmarking", "frame-support", "frame-system", + "log", "parity-scale-codec", "pretty_assertions", "scale-info", @@ -10026,7 +9958,7 @@ dependencies = [ name = "pallet-contracts" version = "27.0.0" dependencies = [ - "array-bytes 6.1.0", + "array-bytes", "assert_matches", "bitflags 1.3.2", "env_logger 0.11.3", @@ -10124,9 +10056,9 @@ dependencies = [ name = "pallet-contracts-proc-macro" version = "18.0.0" dependencies = [ - "proc-macro2 1.0.75", + "proc-macro2 1.0.82", "quote 1.0.35", - "syn 2.0.53", + "syn 2.0.61", ] [[package]] @@ -10191,6 +10123,28 @@ dependencies = [ "sp-std 14.0.0", ] +[[package]] +name = "pallet-delegated-staking" +version = "1.0.0" +dependencies = [ + "frame-election-provider-support", + "frame-support", + "frame-system", + "pallet-balances", + "pallet-staking", + "pallet-staking-reward-curve", + "pallet-timestamp", + "parity-scale-codec", + "scale-info", + "sp-core", + "sp-io", + "sp-runtime", + "sp-staking", + "sp-std 14.0.0", + "sp-tracing 16.0.0", + "substrate-test-utils", +] + [[package]] name = "pallet-democracy" version = "28.0.0" @@ -10710,12 +10664,12 @@ dependencies = [ name = "pallet-mmr" version = "27.0.0" dependencies = [ - "array-bytes 6.1.0", + "array-bytes", "env_logger 0.11.3", "frame-benchmarking", "frame-support", "frame-system", - "itertools 0.10.5", + "itertools 0.11.0", "log", "parity-scale-codec", "scale-info", @@ -11203,7 +11157,7 @@ dependencies = [ name = "pallet-sassafras" version = "0.3.5-dev" dependencies = [ - "array-bytes 6.1.0", + "array-bytes", "frame-benchmarking", "frame-support", "frame-system", @@ -11320,7 +11274,7 @@ dependencies = [ "log", "pallet-balances", "parity-scale-codec", - "rand_chacha 0.2.2", + "rand_chacha 0.3.1", "scale-info", "sp-arithmetic", "sp-core", @@ -11346,7 +11300,7 @@ dependencies = [ "pallet-staking-reward-curve", "pallet-timestamp", "parity-scale-codec", - "rand_chacha 0.2.2", + "rand_chacha 0.3.1", "scale-info", "serde", "sp-application-crypto", @@ -11364,11 +11318,11 @@ dependencies = [ name = "pallet-staking-reward-curve" version = "11.0.0" dependencies = [ - "proc-macro-crate 3.0.0", - "proc-macro2 1.0.75", + "proc-macro-crate 3.1.0", + "proc-macro2 1.0.82", "quote 1.0.35", "sp-runtime", - "syn 2.0.53", + "syn 2.0.61", ] [[package]] @@ -11548,7 +11502,7 @@ dependencies = [ name = "pallet-transaction-storage" version = "27.0.0" dependencies = [ - "array-bytes 6.1.0", + "array-bytes", "frame-benchmarking", "frame-support", "frame-system", @@ -11716,7 +11670,6 @@ dependencies = [ "polkadot-primitives", "polkadot-runtime-common", "scale-info", - "sp-core", "sp-io", "sp-runtime", "sp-std 14.0.0", @@ -11785,6 +11738,7 @@ dependencies = [ "cumulus-primitives-core", "cumulus-primitives-parachain-inherent", "cumulus-relay-chain-interface", + "docify", "frame-benchmarking", "frame-benchmarking-cli", "futures", @@ -11837,9 +11791,11 @@ dependencies = [ "cumulus-pallet-session-benchmarking", "cumulus-pallet-xcm", "cumulus-pallet-xcmp-queue", + "cumulus-primitives-aura", "cumulus-primitives-core", "cumulus-primitives-storage-weight-reclaim", "cumulus-primitives-utility", + "docify", "frame-benchmarking", "frame-executive", "frame-support", @@ -12003,9 +11959,9 @@ dependencies = [ [[package]] name = "parity-scale-codec" -version = "3.6.5" +version = "3.6.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0dec8a8073036902368c2cdc0387e85ff9a37054d7e7c98e592145e0c92cd4fb" +checksum = "306800abfa29c7f16596b5970a588435e3d5b3149683d00c12b699cc19f895ee" dependencies = [ "arrayvec 0.7.4", "bitvec", @@ -12018,12 +11974,12 @@ dependencies = [ [[package]] name = "parity-scale-codec-derive" -version = "3.6.5" +version = "3.6.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "312270ee71e1cd70289dacf597cab7b207aa107d2f28191c2ae45b2ece18a260" +checksum = "d830939c76d294956402033aee57a6da7b438f2294eb94864c37b0569053a42c" dependencies = [ - "proc-macro-crate 1.3.1", - "proc-macro2 1.0.75", + "proc-macro-crate 3.1.0", + "proc-macro2 1.0.82", "quote 1.0.35", "syn 1.0.109", ] @@ -12058,7 +12014,7 @@ version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f557c32c6d268a07c921471619c0295f5efad3a0e76d4f97a05c091a51d110b2" dependencies = [ - "proc-macro2 1.0.75", + "proc-macro2 1.0.82", "syn 1.0.109", "synstructure", ] @@ -12243,6 +12199,7 @@ dependencies = [ "staging-xcm-builder", "staging-xcm-executor", "substrate-wasm-builder", + "xcm-fee-payment-runtime-api", ] [[package]] @@ -12479,9 +12436,9 @@ checksum = "68ca01446f50dbda87c1786af8770d535423fa8a53aec03b8f4e3d7eb10e0929" dependencies = [ "pest", "pest_meta", - "proc-macro2 1.0.75", + "proc-macro2 1.0.82", "quote 1.0.35", - "syn 2.0.53", + "syn 2.0.61", ] [[package]] @@ -12492,7 +12449,7 @@ checksum = "56af0a30af74d0445c0bf6d9d051c979b516a1a5af790d251daee76005420a48" dependencies = [ "once_cell", "pest", - "sha2 0.10.7", + "sha2 0.10.8", ] [[package]] @@ -12520,9 +12477,9 @@ version = "1.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4359fd9c9171ec6e8c62926d6faaf553a8dc3f64e1507e76da7911b4f6a04405" dependencies = [ - "proc-macro2 1.0.75", + "proc-macro2 1.0.82", "quote 1.0.35", - "syn 2.0.53", + "syn 2.0.61", ] [[package]] @@ -12599,7 +12556,7 @@ version = "6.0.0" dependencies = [ "assert_cmd", "color-eyre", - "nix 0.26.2", + "nix 0.28.0", "polkadot-cli", "polkadot-core-primitives", "polkadot-node-core-pvf", @@ -12623,7 +12580,7 @@ dependencies = [ "env_logger 0.11.3", "futures", "futures-timer", - "itertools 0.10.5", + "itertools 0.11.0", "log", "polkadot-node-jaeger", "polkadot-node-metrics", @@ -12780,6 +12737,7 @@ dependencies = [ "polkadot-node-subsystem-util", "polkadot-primitives", "polkadot-primitives-test-helpers", + "rstest", "sc-keystore", "sc-network", "sp-core", @@ -12839,7 +12797,7 @@ dependencies = [ name = "polkadot-erasure-coding" version = "7.0.0" dependencies = [ - "criterion 0.4.0", + "criterion", "parity-scale-codec", "polkadot-node-primitives", "polkadot-primitives", @@ -12942,7 +12900,7 @@ dependencies = [ "env_logger 0.11.3", "futures", "futures-timer", - "itertools 0.10.5", + "itertools 0.11.0", "kvdb", "kvdb-memorydb", "log", @@ -12957,6 +12915,7 @@ dependencies = [ "polkadot-overseer", "polkadot-primitives", "polkadot-primitives-test-helpers", + "polkadot-subsystem-bench", "rand 0.8.5", "rand_chacha 0.3.1", "rand_core 0.6.4", @@ -13175,7 +13134,6 @@ dependencies = [ "polkadot-node-subsystem-util", "polkadot-primitives", "polkadot-primitives-test-helpers", - "rstest", "sc-keystore", "sp-application-crypto", "sp-core", @@ -13212,11 +13170,11 @@ name = "polkadot-node-core-pvf" version = "7.0.0" dependencies = [ "always-assert", - "array-bytes 6.1.0", + "array-bytes", "assert_matches", "blake3", "cfg-if", - "criterion 0.4.0", + "criterion", "futures", "futures-timer", "hex-literal", @@ -13242,7 +13200,6 @@ dependencies = [ "slotmap", "sp-core", "sp-maybe-compressed-blob", - "sp-wasm-interface 20.0.0", "tempfile", "test-parachain-adder", "test-parachain-halt", @@ -13279,12 +13236,11 @@ name = "polkadot-node-core-pvf-common" version = "7.0.0" dependencies = [ "assert_matches", - "cfg-if", "cpu-time", "futures", "landlock", "libc", - "nix 0.27.1", + "nix 0.28.0", "parity-scale-codec", "polkadot-parachain-primitives", "polkadot-primitives", @@ -13309,7 +13265,7 @@ dependencies = [ "cfg-if", "cpu-time", "libc", - "nix 0.27.1", + "nix 0.28.0", "parity-scale-codec", "polkadot-node-core-pvf-common", "polkadot-parachain-primitives", @@ -13323,9 +13279,9 @@ version = "7.0.0" dependencies = [ "blake3", "cfg-if", - "criterion 0.4.0", + "criterion", "libc", - "nix 0.27.1", + "nix 0.28.0", "parity-scale-codec", "polkadot-node-core-pvf-common", "polkadot-primitives", @@ -13523,7 +13479,7 @@ dependencies = [ "fatality", "futures", "futures-channel", - "itertools 0.10.5", + "itertools 0.11.0", "kvdb", "kvdb-memorydb", "kvdb-shared-tests", @@ -13618,7 +13574,7 @@ dependencies = [ "hex-literal", "jsonrpsee", "log", - "nix 0.26.2", + "nix 0.28.0", "pallet-transaction-payment", "pallet-transaction-payment-rpc", "pallet-transaction-payment-rpc-runtime-api", @@ -13896,8 +13852,11 @@ dependencies = [ name = "polkadot-sdk-docs" version = "0.0.1" dependencies = [ + "cumulus-client-service", "cumulus-pallet-aura-ext", "cumulus-pallet-parachain-system", + "cumulus-primitives-proof-size-hostfunction", + "cumulus-primitives-storage-weight-reclaim", "docify", "frame-executive", "frame-support", @@ -13935,11 +13894,13 @@ dependencies = [ "sc-consensus-grandpa", "sc-consensus-manual-seal", "sc-consensus-pow", + "sc-executor", "sc-network", "sc-rpc", "sc-rpc-api", + "sc-service", "scale-info", - "simple-mermaid", + "simple-mermaid 0.1.1", "sp-api", "sp-arithmetic", "sp-core", @@ -13961,10 +13922,13 @@ name = "polkadot-sdk-frame" version = "0.1.0" dependencies = [ "docify", + "frame-benchmarking", "frame-executive", "frame-support", "frame-system", + "frame-system-benchmarking", "frame-system-rpc-runtime-api", + "frame-try-runtime", "log", "pallet-examples", "parity-scale-codec", @@ -13981,6 +13945,7 @@ dependencies = [ "sp-runtime", "sp-session", "sp-std 14.0.0", + "sp-storage 19.0.0", "sp-transaction-pool", "sp-version", ] @@ -14272,6 +14237,7 @@ dependencies = [ "polkadot-node-core-pvf-common", "polkadot-node-core-pvf-execute-worker", "polkadot-node-core-pvf-prepare-worker", + "polkadot-node-network-protocol", "polkadot-node-primitives", "polkadot-node-subsystem", "polkadot-node-subsystem-test-helpers", @@ -14289,7 +14255,6 @@ dependencies = [ name = "polkadot-test-runtime" version = "1.0.0" dependencies = [ - "bitvec", "frame-election-provider-support", "frame-executive", "frame-support", @@ -14314,16 +14279,12 @@ dependencies = [ "pallet-vesting", "pallet-xcm", "parity-scale-codec", - "polkadot-parachain-primitives", "polkadot-primitives", "polkadot-runtime-common", "polkadot-runtime-parachains", - "rustc-hex", "scale-info", "serde", - "serde_derive", "serde_json", - "smallvec", "sp-api", "sp-authority-discovery", "sp-block-builder", @@ -14460,9 +14421,9 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5c4fdfc49717fb9a196e74a5d28e0bc764eb394a2c803eb11133a31ac996c60c" dependencies = [ "polkavm-common", - "proc-macro2 1.0.75", + "proc-macro2 1.0.82", "quote 1.0.35", - "syn 2.0.53", + "syn 2.0.61", ] [[package]] @@ -14472,7 +14433,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8ba81f7b5faac81e528eb6158a6f3c9e0bb1008e0ffa19653bc8dea925ecb429" dependencies = [ "polkavm-derive-impl", - "syn 2.0.53", + "syn 2.0.61", ] [[package]] @@ -14512,17 +14473,6 @@ dependencies = [ "windows-sys 0.48.0", ] -[[package]] -name = "poly1305" -version = "0.7.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "048aeb476be11a4b6ca432ca569e375810de9294ae78f4774e78ea98a9246ede" -dependencies = [ - "cpufeatures", - "opaque-debug 0.3.0", - "universal-hash 0.4.0", -] - [[package]] name = "poly1305" version = "0.8.0" @@ -14531,19 +14481,7 @@ checksum = "8159bd90725d2df49889a078b54f4f79e87f1f8a8444194cdca81d38f5393abf" dependencies = [ "cpufeatures", "opaque-debug 0.3.0", - "universal-hash 0.5.1", -] - -[[package]] -name = "polyval" -version = "0.5.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8419d2b623c7c0896ff2d5d96e2cb4ede590fed28fcc34934f4c33c036e620a1" -dependencies = [ - "cfg-if", - "cpufeatures", - "opaque-debug 0.3.0", - "universal-hash 0.4.0", + "universal-hash", ] [[package]] @@ -14555,7 +14493,7 @@ dependencies = [ "cfg-if", "cpufeatures", "opaque-debug 0.3.0", - "universal-hash 0.5.1", + "universal-hash", ] [[package]] @@ -14657,7 +14595,7 @@ version = "0.1.25" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6c8646e95016a7a6c4adea95bafa8a16baab64b583356217f2c85db4a39d9a86" dependencies = [ - "proc-macro2 1.0.75", + "proc-macro2 1.0.82", "syn 1.0.109", ] @@ -14667,8 +14605,8 @@ version = "0.2.12" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6c64d9ba0963cdcea2e1b2230fbae2bab30eb25a174be395c41e764bfb65dd62" dependencies = [ - "proc-macro2 1.0.75", - "syn 2.0.53", + "proc-macro2 1.0.82", + "syn 2.0.61", ] [[package]] @@ -14714,9 +14652,9 @@ dependencies = [ [[package]] name = "proc-macro-crate" -version = "3.0.0" +version = "3.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6b2685dd208a3771337d8d386a89840f0f43cd68be8dae90a5f8c2384effc9cd" +checksum = "6d37c51ca738a55da99dc0c4a34860fd675453b8b36209178c2249bb13651284" dependencies = [ "toml_edit 0.21.0", ] @@ -14728,7 +14666,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "da25490ff9892aab3fcf7c36f08cfb902dd3e71ca0f9f9517bea02a73a5ce38c" dependencies = [ "proc-macro-error-attr", - "proc-macro2 1.0.75", + "proc-macro2 1.0.82", "quote 1.0.35", "syn 1.0.109", "version_check", @@ -14740,7 +14678,7 @@ version = "1.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a1be40180e52ecc98ad80b184934baf3d0d29f979574e439af5a55274b35f869" dependencies = [ - "proc-macro2 1.0.75", + "proc-macro2 1.0.82", "quote 1.0.35", "version_check", ] @@ -14757,9 +14695,9 @@ version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9b698b0b09d40e9b7c1a47b132d66a8b54bcd20583d9b6d06e4535e383b4405c" dependencies = [ - "proc-macro2 1.0.75", + "proc-macro2 1.0.82", "quote 1.0.35", - "syn 2.0.53", + "syn 2.0.61", ] [[package]] @@ -14773,9 +14711,9 @@ dependencies = [ [[package]] name = "proc-macro2" -version = "1.0.75" +version = "1.0.82" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "907a61bd0f64c2f29cd1cf1dc34d05176426a3f504a78010f08416ddb7b13708" +checksum = "8ad3d49ab951a01fbaafe34f2ec74122942fe18a3f9814c3268f1bb72042131b" dependencies = [ "unicode-ident", ] @@ -14838,9 +14776,9 @@ version = "0.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "440f724eba9f6996b75d63681b0a92b06947f1457076d503a4d2e2c8f56442b8" dependencies = [ - "proc-macro2 1.0.75", + "proc-macro2 1.0.82", "quote 1.0.35", - "syn 2.0.53", + "syn 2.0.61", ] [[package]] @@ -14887,12 +14825,12 @@ dependencies = [ [[package]] name = "prost" -version = "0.12.3" +version = "0.12.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "146c289cda302b98a28d40c8b3b90498d6e526dd24ac2ecea73e4e491685b94a" +checksum = "d0f5d036824e4761737860779c906171497f6d55681139d8312388f8fe398922" dependencies = [ "bytes", - "prost-derive 0.12.3", + "prost-derive 0.12.4", ] [[package]] @@ -14910,13 +14848,34 @@ dependencies = [ "petgraph", "prettyplease 0.1.25", "prost 0.11.9", - "prost-types", + "prost-types 0.11.9", "regex", "syn 1.0.109", "tempfile", "which", ] +[[package]] +name = "prost-build" +version = "0.12.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "80b776a1b2dc779f5ee0641f8ade0125bc1298dd41a9a0c16d8bd57b42d222b1" +dependencies = [ + "bytes", + "heck 0.5.0", + "itertools 0.11.0", + "log", + "multimap", + "once_cell", + "petgraph", + "prettyplease 0.2.12", + "prost 0.12.4", + "prost-types 0.12.4", + "regex", + "syn 2.0.61", + "tempfile", +] + [[package]] name = "prost-derive" version = "0.11.9" @@ -14925,22 +14884,22 @@ checksum = "e5d2d8d10f3c6ded6da8b05b5fb3b8a5082514344d56c9f871412d29b4e075b4" dependencies = [ "anyhow", "itertools 0.10.5", - "proc-macro2 1.0.75", + "proc-macro2 1.0.82", "quote 1.0.35", "syn 1.0.109", ] [[package]] name = "prost-derive" -version = "0.12.3" +version = "0.12.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "efb6c9a1dd1def8e2124d17e83a20af56f1570d6c2d2bd9e266ccb768df3840e" +checksum = "19de2de2a00075bf566bee3bd4db014b11587e84184d3f7a791bc17f1a8e9e48" dependencies = [ "anyhow", "itertools 0.11.0", - "proc-macro2 1.0.75", + "proc-macro2 1.0.82", "quote 1.0.35", - "syn 2.0.53", + "syn 2.0.61", ] [[package]] @@ -14952,6 +14911,15 @@ dependencies = [ "prost 0.11.9", ] +[[package]] +name = "prost-types" +version = "0.12.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3235c33eb02c1f1e212abdbe34c78b264b038fb58ca612664343271e36e55ffe" +dependencies = [ + "prost 0.12.4", +] + [[package]] name = "psm" version = "0.1.21" @@ -15121,7 +15089,7 @@ version = "1.0.35" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "291ec9ab5efd934aaf503a6466c5d5251535d108ee747472c3977cc5acc868ef" dependencies = [ - "proc-macro2 1.0.75", + "proc-macro2 1.0.82", ] [[package]] @@ -15361,9 +15329,9 @@ version = "1.0.20" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7f7473c2cfcf90008193dd0e3e16599455cb601a9fce322b5bb55de799664925" dependencies = [ - "proc-macro2 1.0.75", + "proc-macro2 1.0.82", "quote 1.0.35", - "syn 2.0.53", + "syn 2.0.61", ] [[package]] @@ -15919,12 +15887,12 @@ checksum = "d428f8247852f894ee1be110b375111b586d4fa431f6c46e64ba5a0dcccbe605" dependencies = [ "cfg-if", "glob", - "proc-macro2 1.0.75", + "proc-macro2 1.0.82", "quote 1.0.35", "regex", "relative-path", "rustc_version 0.4.0", - "syn 2.0.53", + "syn 2.0.61", "unicode-ident", ] @@ -16284,8 +16252,8 @@ dependencies = [ "multihash 0.17.0", "multihash-codetable", "parity-scale-codec", - "prost 0.12.3", - "prost-build", + "prost 0.12.4", + "prost-build 0.12.4", "quickcheck", "rand 0.8.5", "sc-client-api", @@ -16348,7 +16316,7 @@ dependencies = [ name = "sc-chain-spec" version = "28.0.0" dependencies = [ - "array-bytes 6.1.0", + "array-bytes", "docify", "log", "memmap2 0.9.3", @@ -16378,23 +16346,23 @@ dependencies = [ name = "sc-chain-spec-derive" version = "11.0.0" dependencies = [ - "proc-macro-crate 3.0.0", - "proc-macro2 1.0.75", + "proc-macro-crate 3.1.0", + "proc-macro2 1.0.82", "quote 1.0.35", - "syn 2.0.53", + "syn 2.0.61", ] [[package]] name = "sc-cli" version = "0.36.0" dependencies = [ - "array-bytes 6.1.0", + "array-bytes", "chrono", "clap 4.5.3", "fdlimit", "futures", "futures-timer", - "itertools 0.10.5", + "itertools 0.11.0", "libp2p-identity", "log", "names", @@ -16460,8 +16428,8 @@ dependencies = [ name = "sc-client-db" version = "0.35.0" dependencies = [ - "array-bytes 6.1.0", - "criterion 0.4.0", + "array-bytes", + "criterion", "hash-db", "kitchensink-runtime", "kvdb", @@ -16626,7 +16594,7 @@ dependencies = [ name = "sc-consensus-beefy" version = "13.0.0" dependencies = [ - "array-bytes 6.1.0", + "array-bytes", "async-channel", "async-trait", "fnv", @@ -16704,7 +16672,7 @@ name = "sc-consensus-grandpa" version = "0.19.0" dependencies = [ "ahash 0.8.8", - "array-bytes 6.1.0", + "array-bytes", "assert_matches", "async-trait", "dyn-clone", @@ -16862,9 +16830,9 @@ dependencies = [ name = "sc-executor" version = "0.32.0" dependencies = [ - "array-bytes 6.1.0", + "array-bytes", "assert_matches", - "criterion 0.4.0", + "criterion", "env_logger 0.11.3", "num_cpus", "parity-scale-codec", @@ -16964,7 +16932,7 @@ dependencies = [ name = "sc-keystore" version = "25.0.0" dependencies = [ - "array-bytes 6.1.0", + "array-bytes", "parking_lot 0.12.1", "serde_json", "sp-application-crypto", @@ -16978,7 +16946,7 @@ dependencies = [ name = "sc-mixnet" version = "0.4.0" dependencies = [ - "array-bytes 4.2.0", + "array-bytes", "arrayvec 0.7.4", "blake2 0.10.6", "bytes", @@ -17006,7 +16974,7 @@ dependencies = [ name = "sc-network" version = "0.34.0" dependencies = [ - "array-bytes 6.1.0", + "array-bytes", "assert_matches", "async-channel", "async-trait", @@ -17029,8 +16997,8 @@ dependencies = [ "parking_lot 0.12.1", "partial_sort", "pin-project", - "prost 0.11.9", - "prost-build", + "prost 0.12.4", + "prost-build 0.12.4", "rand 0.8.5", "sc-block-builder", "sc-client-api", @@ -17075,7 +17043,7 @@ dependencies = [ "futures", "libp2p-identity", "parity-scale-codec", - "prost-build", + "prost-build 0.12.4", "sc-consensus", "sc-network-types", "sp-consensus", @@ -17112,13 +17080,13 @@ dependencies = [ name = "sc-network-light" version = "0.33.0" dependencies = [ - "array-bytes 6.1.0", + "array-bytes", "async-channel", "futures", "log", "parity-scale-codec", - "prost 0.12.3", - "prost-build", + "prost 0.12.4", + "prost-build 0.12.4", "sc-client-api", "sc-network", "sc-network-types", @@ -17132,7 +17100,7 @@ dependencies = [ name = "sc-network-statement" version = "0.16.0" dependencies = [ - "array-bytes 6.1.0", + "array-bytes", "async-channel", "futures", "libp2p", @@ -17152,7 +17120,7 @@ dependencies = [ name = "sc-network-sync" version = "0.33.0" dependencies = [ - "array-bytes 6.1.0", + "array-bytes", "async-channel", "async-trait", "fork-tree", @@ -17162,8 +17130,8 @@ dependencies = [ "log", "mockall", "parity-scale-codec", - "prost 0.12.3", - "prost-build", + "prost 0.12.4", + "prost-build 0.12.4", "quickcheck", "sc-block-builder", "sc-client-api", @@ -17224,7 +17192,7 @@ dependencies = [ name = "sc-network-transactions" version = "0.33.0" dependencies = [ - "array-bytes 6.1.0", + "array-bytes", "futures", "libp2p", "log", @@ -17241,9 +17209,9 @@ dependencies = [ [[package]] name = "sc-network-types" -version = "0.10.0-dev" +version = "0.10.0" dependencies = [ - "bs58 0.4.0", + "bs58 0.5.0", "ed25519-dalek 2.1.1", "libp2p-identity", "litep2p", @@ -17259,7 +17227,7 @@ dependencies = [ name = "sc-offchain" version = "29.0.0" dependencies = [ - "array-bytes 6.1.0", + "array-bytes", "async-trait", "bytes", "fnv", @@ -17371,10 +17339,12 @@ dependencies = [ name = "sc-rpc-server" version = "11.0.0" dependencies = [ + "forwarded-header-value", "futures", "governor", "http", "hyper", + "ip_network", "jsonrpsee", "log", "serde_json", @@ -17388,7 +17358,7 @@ dependencies = [ name = "sc-rpc-spec-v2" version = "0.34.0" dependencies = [ - "array-bytes 6.1.0", + "array-bytes", "assert_matches", "futures", "futures-util", @@ -17407,6 +17377,7 @@ dependencies = [ "sc-transaction-pool", "sc-transaction-pool-api", "sc-utils", + "schnellru", "serde", "serde_json", "sp-api", @@ -17507,7 +17478,7 @@ dependencies = [ name = "sc-service-test" version = "2.0.0" dependencies = [ - "array-bytes 6.1.0", + "array-bytes", "async-channel", "fdlimit", "futures", @@ -17645,7 +17616,7 @@ version = "28.0.0" dependencies = [ "ansi_term", "chrono", - "criterion 0.4.0", + "criterion", "is-terminal", "lazy_static", "libc", @@ -17665,7 +17636,7 @@ dependencies = [ "sp-tracing 16.0.0", "thiserror", "tracing", - "tracing-log 0.1.3", + "tracing-log 0.2.0", "tracing-subscriber 0.3.18", ] @@ -17673,20 +17644,20 @@ dependencies = [ name = "sc-tracing-proc-macro" version = "11.0.0" dependencies = [ - "proc-macro-crate 3.0.0", - "proc-macro2 1.0.75", + "proc-macro-crate 3.1.0", + "proc-macro2 1.0.82", "quote 1.0.35", - "syn 2.0.53", + "syn 2.0.61", ] [[package]] name = "sc-transaction-pool" version = "28.0.0" dependencies = [ - "array-bytes 6.1.0", + "array-bytes", "assert_matches", "async-trait", - "criterion 0.4.0", + "criterion", "futures", "futures-timer", "linked-hash-map", @@ -17746,9 +17717,9 @@ dependencies = [ [[package]] name = "scale-info" -version = "2.11.1" +version = "2.11.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "788745a868b0e751750388f4e6546eb921ef714a4317fa6954f7cde114eb2eb7" +checksum = "eca070c12893629e2cc820a9761bedf6ce1dcddc9852984d1dc734b8bd9bd024" dependencies = [ "bitvec", "cfg-if", @@ -17760,12 +17731,12 @@ dependencies = [ [[package]] name = "scale-info-derive" -version = "2.11.1" +version = "2.11.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7dc2f4e8bc344b9fc3d5f74f72c2e55bfc38d28dc2ebc69c194a3df424e4d9ac" +checksum = "2d35494501194174bda522a32605929eefc9ecf7e0a326c26db1fdd85881eb62" dependencies = [ - "proc-macro-crate 1.3.1", - "proc-macro2 1.0.75", + "proc-macro-crate 3.1.0", + "proc-macro2 1.0.82", "quote 1.0.35", "syn 1.0.109", ] @@ -17797,7 +17768,7 @@ version = "0.8.13" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ec0f696e21e10fa546b7ffb1c9672c6de8fbc7a81acf59524386d8639bf12737" dependencies = [ - "proc-macro2 1.0.75", + "proc-macro2 1.0.82", "quote 1.0.35", "serde_derive_internals", "syn 1.0.109", @@ -17836,7 +17807,7 @@ version = "0.11.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8de18f6d8ba0aad7045f5feae07ec29899c1112584a38509a84ad7b04451eaa0" dependencies = [ - "aead 0.5.2", + "aead", "arrayref", "arrayvec 0.7.4", "curve25519-dalek 4.1.2", @@ -17844,7 +17815,7 @@ dependencies = [ "merlin", "rand_core 0.6.4", "serde_bytes", - "sha2 0.10.7", + "sha2 0.10.8", "subtle 2.5.0", "zeroize", ] @@ -18091,9 +18062,9 @@ version = "1.0.197" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7eb0b34b42edc17f6b7cac84a52a1c5f0e1bb2227e997ca9011ea3dd34e8610b" dependencies = [ - "proc-macro2 1.0.75", + "proc-macro2 1.0.82", "quote 1.0.35", - "syn 2.0.53", + "syn 2.0.61", ] [[package]] @@ -18102,7 +18073,7 @@ version = "0.26.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "85bf8229e7920a9f636479437026331ce11aa132b4dde37d121944a44d6e5f3c" dependencies = [ - "proc-macro2 1.0.75", + "proc-macro2 1.0.82", "quote 1.0.35", "syn 1.0.109", ] @@ -18192,9 +18163,9 @@ version = "2.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "91d129178576168c589c9ec973feedf7d3126c01ac2bf08795109aa35b69fb8f" dependencies = [ - "proc-macro2 1.0.75", + "proc-macro2 1.0.82", "quote 1.0.35", - "syn 2.0.53", + "syn 2.0.61", ] [[package]] @@ -18257,9 +18228,9 @@ dependencies = [ [[package]] name = "sha2" -version = "0.10.7" +version = "0.10.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "479fb9d862239e610720565ca91403019f2f00410f1864c5aa7479b950a76ed8" +checksum = "793db75ad2bcafc3ffa7c68b215fee268f537982cd901d132f89c6343f3a3dc8" dependencies = [ "cfg-if", "cpufeatures", @@ -18385,6 +18356,11 @@ dependencies = [ "bitflags 2.4.0", ] +[[package]] +name = "simple-mermaid" +version = "0.1.0" +source = "git+https://github.com/kianenigma/simple-mermaid.git?branch=main#e48b187bcfd5cc75111acd9d241f1bd36604344b" + [[package]] name = "simple-mermaid" version = "0.1.1" @@ -18459,7 +18435,7 @@ dependencies = [ "async-executor", "async-fs", "async-io", - "async-lock 2.8.0", + "async-lock", "async-net", "async-process", "blocking", @@ -18482,18 +18458,18 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c0bb30cf57b7b5f6109ce17c3164445e2d6f270af2cb48f6e4d31c2967c9a9f5" dependencies = [ "arrayvec 0.7.4", - "async-lock 2.8.0", + "async-lock", "atomic-take", "base64 0.21.2", "bip39", "blake2-rfc", "bs58 0.5.0", - "chacha20 0.9.1", + "chacha20", "crossbeam-queue", "derive_more", - "ed25519-zebra 4.0.3", + "ed25519-zebra", "either", - "event-listener 2.5.3", + "event-listener", "fnv", "futures-lite", "futures-util", @@ -18510,14 +18486,14 @@ dependencies = [ "num-traits", "pbkdf2", "pin-project", - "poly1305 0.8.0", + "poly1305", "rand 0.8.5", "rand_chacha 0.3.1", "ruzstd", "schnorrkel 0.10.2", "serde", "serde_json", - "sha2 0.10.7", + "sha2 0.10.8", "sha3", "siphasher", "slab", @@ -18536,12 +18512,12 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "256b5bad1d6b49045e95fe87492ce73d5af81545d8b4d8318a872d2007024c33" dependencies = [ "async-channel", - "async-lock 2.8.0", + "async-lock", "base64 0.21.2", "blake2-rfc", "derive_more", "either", - "event-listener 2.5.3", + "event-listener", "fnv", "futures-channel", "futures-lite", @@ -18573,18 +18549,18 @@ checksum = "5e9f0ab6ef7eb7353d9119c170a436d1bf248eea575ac42d19d12f4e34130831" [[package]] name = "snow" -version = "0.9.3" +version = "0.9.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0c9d1425eb528a21de2755c75af4c9b5d57f50a0d4c3b7f1828a4cd03f8ba155" +checksum = "850948bee068e713b8ab860fe1adc4d109676ab4c3b621fd8147f06b261f2f85" dependencies = [ - "aes-gcm 0.9.2", + "aes-gcm", "blake2 0.10.6", "chacha20poly1305", "curve25519-dalek 4.1.2", "rand_core 0.6.4", - "ring 0.16.20", + "ring 0.17.7", "rustc_version 0.4.0", - "sha2 0.10.7", + "sha2 0.10.8", "subtle 2.5.0", ] @@ -18684,7 +18660,7 @@ dependencies = [ name = "snowbridge-outbound-queue-merkle-tree" version = "0.3.0" dependencies = [ - "array-bytes 4.2.0", + "array-bytes", "env_logger 0.11.3", "hex", "hex-literal", @@ -19055,18 +19031,18 @@ dependencies = [ "Inflector", "assert_matches", "blake2 0.10.6", - "expander 2.0.0", - "proc-macro-crate 3.0.0", - "proc-macro2 1.0.75", + "expander", + "proc-macro-crate 3.1.0", + "proc-macro2 1.0.82", "quote 1.0.35", - "syn 2.0.53", + "syn 2.0.61", ] [[package]] name = "sp-api-test" version = "2.0.1" dependencies = [ - "criterion 0.4.0", + "criterion", "futures", "log", "parity-scale-codec", @@ -19112,7 +19088,7 @@ dependencies = [ name = "sp-arithmetic" version = "23.0.0" dependencies = [ - "criterion 0.4.0", + "criterion", "docify", "integer-sqrt", "num-traits", @@ -19243,7 +19219,7 @@ dependencies = [ name = "sp-consensus-beefy" version = "13.0.0" dependencies = [ - "array-bytes 6.1.0", + "array-bytes", "lazy_static", "parity-scale-codec", "scale-info", @@ -19314,20 +19290,20 @@ dependencies = [ name = "sp-core" version = "28.0.0" dependencies = [ - "array-bytes 6.1.0", + "array-bytes", "bandersnatch_vrfs", "bitflags 1.3.2", "blake2 0.10.6", "bounded-collections", "bs58 0.5.0", - "criterion 0.4.0", + "criterion", "dyn-clonable", - "ed25519-zebra 3.1.0", + "ed25519-zebra", "futures", "hash-db", "hash256-std-hasher", "impl-serde", - "itertools 0.10.5", + "itertools 0.11.0", "k256", "lazy_static", "libsecp256k1", @@ -19430,9 +19406,9 @@ version = "0.1.0" dependencies = [ "blake2b_simd", "byteorder", - "criterion 0.4.0", + "criterion", "digest 0.10.7", - "sha2 0.10.7", + "sha2 0.10.8", "sha3", "sp-crypto-hashing-proc-macro", "twox-hash", @@ -19444,7 +19420,7 @@ version = "0.1.0" dependencies = [ "quote 1.0.35", "sp-crypto-hashing", - "syn 2.0.53", + "syn 2.0.61", ] [[package]] @@ -19460,18 +19436,18 @@ name = "sp-debug-derive" version = "8.0.0" source = "git+https://github.com/paritytech/polkadot-sdk#82912acb33a9030c0ef3bf590a34fca09b72dc5f" dependencies = [ - "proc-macro2 1.0.75", + "proc-macro2 1.0.82", "quote 1.0.35", - "syn 2.0.53", + "syn 2.0.61", ] [[package]] name = "sp-debug-derive" version = "14.0.0" dependencies = [ - "proc-macro2 1.0.75", + "proc-macro2 1.0.82", "quote 1.0.35", - "syn 2.0.53", + "syn 2.0.61", ] [[package]] @@ -19559,7 +19535,7 @@ dependencies = [ "parity-scale-codec", "parking_lot 0.12.1", "rand 0.8.5", - "rand_chacha 0.2.2", + "rand_chacha 0.3.1", "sp-core", "sp-externalities 0.25.0", ] @@ -19595,8 +19571,8 @@ dependencies = [ name = "sp-mmr-primitives" version = "26.0.0" dependencies = [ - "array-bytes 6.1.0", - "ckb-merkle-mountain-range", + "array-bytes", + "ckb-merkle-mountain-range 0.6.0", "log", "parity-scale-codec", "scale-info", @@ -19670,13 +19646,14 @@ dependencies = [ "hash256-std-hasher", "impl-trait-for-tuples", "log", + "num-traits", "parity-scale-codec", "paste", "rand 0.8.5", "scale-info", "serde", "serde_json", - "simple-mermaid", + "simple-mermaid 0.1.1", "sp-api", "sp-application-crypto", "sp-arithmetic", @@ -19739,9 +19716,9 @@ source = "git+https://github.com/paritytech/polkadot-sdk#82912acb33a9030c0ef3bf5 dependencies = [ "Inflector", "proc-macro-crate 1.3.1", - "proc-macro2 1.0.75", + "proc-macro2 1.0.82", "quote 1.0.35", - "syn 2.0.53", + "syn 2.0.61", ] [[package]] @@ -19749,11 +19726,11 @@ name = "sp-runtime-interface-proc-macro" version = "17.0.0" dependencies = [ "Inflector", - "expander 2.0.0", - "proc-macro-crate 3.0.0", - "proc-macro2 1.0.75", + "expander", + "proc-macro-crate 3.1.0", + "proc-macro2 1.0.82", "quote 1.0.35", - "syn 2.0.53", + "syn 2.0.61", ] [[package]] @@ -19823,7 +19800,7 @@ dependencies = [ name = "sp-state-machine" version = "0.35.0" dependencies = [ - "array-bytes 6.1.0", + "array-bytes", "assert_matches", "hash-db", "log", @@ -19846,14 +19823,14 @@ dependencies = [ name = "sp-statement-store" version = "10.0.0" dependencies = [ - "aes-gcm 0.10.3", + "aes-gcm", "curve25519-dalek 4.1.2", "ed25519-dalek 2.1.1", "hkdf", "parity-scale-codec", "rand 0.8.5", "scale-info", - "sha2 0.10.7", + "sha2 0.10.8", "sp-api", "sp-application-crypto", "sp-core", @@ -19969,8 +19946,8 @@ name = "sp-trie" version = "29.0.0" dependencies = [ "ahash 0.8.8", - "array-bytes 6.1.0", - "criterion 0.5.1", + "array-bytes", + "criterion", "hash-db", "lazy_static", "memory-db", @@ -20012,10 +19989,10 @@ name = "sp-version-proc-macro" version = "13.0.0" dependencies = [ "parity-scale-codec", - "proc-macro2 1.0.75", + "proc-macro2 1.0.82", "quote 1.0.35", "sp-version", - "syn 2.0.53", + "syn 2.0.61", ] [[package]] @@ -20097,7 +20074,7 @@ checksum = "5e6915280e2d0db8911e5032a5c275571af6bdded2916abd691a659be25d3439" dependencies = [ "Inflector", "num-format", - "proc-macro2 1.0.75", + "proc-macro2 1.0.82", "quote 1.0.35", "serde", "serde_json", @@ -20122,7 +20099,7 @@ version = "0.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f07d54c4d01a1713eb363b55ba51595da15f6f1211435b71466460da022aa140" dependencies = [ - "proc-macro2 1.0.75", + "proc-macro2 1.0.82", "quote 1.0.35", "syn 1.0.109", ] @@ -20148,11 +20125,11 @@ dependencies = [ name = "staging-node-cli" version = "3.0.0-dev" dependencies = [ - "array-bytes 6.1.0", + "array-bytes", "assert_cmd", "clap 4.5.3", "clap_complete", - "criterion 0.4.0", + "criterion", "frame-benchmarking", "frame-benchmarking-cli", "frame-support", @@ -20163,7 +20140,7 @@ dependencies = [ "kitchensink-runtime", "log", "mmr-gadget", - "nix 0.26.2", + "nix 0.28.0", "node-primitives", "node-rpc", "node-testing", @@ -20247,7 +20224,6 @@ dependencies = [ "staging-node-inspect", "substrate-build-script-utils", "substrate-cli-test-utils", - "substrate-frame-cli", "substrate-rpc-client", "tempfile", "tokio", @@ -20294,7 +20270,7 @@ version = "2.0.0" name = "staging-xcm" version = "7.0.0" dependencies = [ - "array-bytes 6.1.0", + "array-bytes", "bounded-collections", "derivative", "environmental", @@ -20390,7 +20366,7 @@ checksum = "70a2595fc3aa78f2d0e45dd425b22282dd863273761cc77780914b2cf3003acf" dependencies = [ "cfg_aliases", "memchr", - "proc-macro2 1.0.75", + "proc-macro2 1.0.82", "quote 1.0.35", "syn 1.0.109", ] @@ -20465,7 +20441,7 @@ checksum = "dcb5ae327f9cc13b68763b5749770cb9e048a99bd9dfdfa58d0cf05d5f64afe0" dependencies = [ "heck 0.3.3", "proc-macro-error", - "proc-macro2 1.0.75", + "proc-macro2 1.0.82", "quote 1.0.35", "syn 1.0.109", ] @@ -20501,7 +20477,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1e385be0d24f186b4ce2f9982191e7101bb737312ad61c1f2f984f34bcf85d59" dependencies = [ "heck 0.4.1", - "proc-macro2 1.0.75", + "proc-macro2 1.0.82", "quote 1.0.35", "rustversion", "syn 1.0.109", @@ -20514,10 +20490,10 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "23dc1fa9ac9c169a78ba62f0b841814b7abae11bdd047b9c58f893439e309ea0" dependencies = [ "heck 0.4.1", - "proc-macro2 1.0.75", + "proc-macro2 1.0.82", "quote 1.0.35", "rustversion", - "syn 2.0.53", + "syn 2.0.61", ] [[package]] @@ -20527,10 +20503,10 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c6cf59daf282c0a494ba14fd21610a0325f9f90ec9d1231dea26bcb1d696c946" dependencies = [ "heck 0.4.1", - "proc-macro2 1.0.75", + "proc-macro2 1.0.82", "quote 1.0.35", "rustversion", - "syn 2.0.53", + "syn 2.0.61", ] [[package]] @@ -20550,7 +20526,7 @@ dependencies = [ "pbkdf2", "rustc-hex", "schnorrkel 0.11.4", - "sha2 0.10.7", + "sha2 0.10.8", "zeroize", ] @@ -20564,7 +20540,7 @@ version = "0.1.0" dependencies = [ "assert_cmd", "futures", - "nix 0.26.2", + "nix 0.28.0", "node-primitives", "regex", "sc-cli", @@ -20575,18 +20551,6 @@ dependencies = [ "tokio", ] -[[package]] -name = "substrate-frame-cli" -version = "32.0.0" -dependencies = [ - "clap 4.5.3", - "frame-support", - "frame-system", - "sc-cli", - "sp-core", - "sp-runtime", -] - [[package]] name = "substrate-frame-rpc-support" version = "29.0.0" @@ -20716,7 +20680,7 @@ dependencies = [ name = "substrate-test-client" version = "2.0.1" dependencies = [ - "array-bytes 6.1.0", + "array-bytes", "async-trait", "futures", "parity-scale-codec", @@ -20742,7 +20706,7 @@ dependencies = [ name = "substrate-test-runtime" version = "2.0.0" dependencies = [ - "array-bytes 6.1.0", + "array-bytes", "frame-executive", "frame-support", "frame-system", @@ -20975,18 +20939,18 @@ version = "1.0.109" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237" dependencies = [ - "proc-macro2 1.0.75", + "proc-macro2 1.0.82", "quote 1.0.35", "unicode-ident", ] [[package]] name = "syn" -version = "2.0.53" +version = "2.0.61" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7383cd0e49fff4b6b90ca5670bfd3e9d6a733b3f90c686605aa7eec8c4996032" +checksum = "c993ed8ccba56ae856363b1845da7266a7cb78e1d146c8a32d54b45a8b831fc9" dependencies = [ - "proc-macro2 1.0.75", + "proc-macro2 1.0.82", "quote 1.0.35", "unicode-ident", ] @@ -20998,9 +20962,9 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "86b837ef12ab88835251726eb12237655e61ec8dc8a280085d1961cdc3dfd047" dependencies = [ "paste", - "proc-macro2 1.0.75", + "proc-macro2 1.0.82", "quote 1.0.35", - "syn 2.0.53", + "syn 2.0.61", ] [[package]] @@ -21009,7 +20973,7 @@ version = "0.12.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f36bdaa60a83aca3921b5259d5400cbf5e90fc51931376a9bd4a0eb79aa7210f" dependencies = [ - "proc-macro2 1.0.75", + "proc-macro2 1.0.82", "quote 1.0.35", "syn 1.0.109", "unicode-xid 0.2.4", @@ -21112,6 +21076,28 @@ version = "0.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3369f5ac52d5eb6ab48c6b4ffdc8efbcad6b89c765749064ba298f2c68a16a76" +[[package]] +name = "test-log" +version = "0.2.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3dffced63c2b5c7be278154d76b479f9f9920ed34e7574201407f0b14e2bbb93" +dependencies = [ + "env_logger 0.11.3", + "test-log-macros", + "tracing-subscriber 0.3.18", +] + +[[package]] +name = "test-log-macros" +version = "0.2.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5999e24eaa32083191ba4e425deb75cdf25efefabe5aaccb7446dd0d4122a3f5" +dependencies = [ + "proc-macro2 1.0.82", + "quote 1.0.35", + "syn 2.0.61", +] + [[package]] name = "test-parachain-adder" version = "1.0.0" @@ -21216,11 +21202,8 @@ version = "1.0.0" dependencies = [ "frame-support", "polkadot-primitives", - "polkadot-runtime-common", "smallvec", - "sp-core", "sp-runtime", - "sp-weights", ] [[package]] @@ -21276,7 +21259,7 @@ version = "1.0.38" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "10ac1c5050e43014d16b2f94d0d2ce79e65ffdd8b38d8048f9c8f6a8a6da62ac" dependencies = [ - "proc-macro2 1.0.75", + "proc-macro2 1.0.82", "quote 1.0.35", "syn 1.0.109", ] @@ -21287,9 +21270,9 @@ version = "1.0.50" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "266b2e40bc00e5a6c09c3584011e08b06f123c00362c92b975ba9843aaaa14b8" dependencies = [ - "proc-macro2 1.0.75", + "proc-macro2 1.0.82", "quote 1.0.35", - "syn 2.0.53", + "syn 2.0.61", ] [[package]] @@ -21450,9 +21433,9 @@ version = "2.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5b8a1e28f2deaa14e508979454cb3a223b10b938b45af148bc0986de36f1923b" dependencies = [ - "proc-macro2 1.0.75", + "proc-macro2 1.0.82", "quote 1.0.35", - "syn 2.0.53", + "syn 2.0.61", ] [[package]] @@ -21512,18 +21495,6 @@ dependencies = [ "tokio-stream", ] -[[package]] -name = "tokio-tungstenite" -version = "0.17.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f714dd15bead90401d77e04243611caec13726c2408afd5b31901dfcdcb3b181" -dependencies = [ - "futures-util", - "log", - "tokio", - "tungstenite 0.17.3", -] - [[package]] name = "tokio-tungstenite" version = "0.20.1" @@ -21536,7 +21507,7 @@ dependencies = [ "rustls-native-certs 0.6.3", "tokio", "tokio-rustls 0.24.1", - "tungstenite 0.20.1", + "tungstenite", ] [[package]] @@ -21671,9 +21642,9 @@ version = "0.1.27" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "34704c8d6ebcbc939824180af020566b01a7c01f80641264eba0999f6c2b6be7" dependencies = [ - "proc-macro2 1.0.75", + "proc-macro2 1.0.82", "quote 1.0.35", - "syn 2.0.53", + "syn 2.0.61", ] [[package]] @@ -21711,11 +21682,11 @@ name = "tracing-gum-proc-macro" version = "5.0.0" dependencies = [ "assert_matches", - "expander 2.0.0", - "proc-macro-crate 3.0.0", - "proc-macro2 1.0.75", + "expander", + "proc-macro-crate 3.1.0", + "proc-macro2 1.0.82", "quote 1.0.35", - "syn 2.0.53", + "syn 2.0.61", ] [[package]] @@ -21798,7 +21769,7 @@ version = "0.39.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3092f400e9f7e3ce8c1756016a8b6287163ab7a11dd47d82169260cb4cc2d680" dependencies = [ - "criterion 0.5.1", + "criterion", "hash-db", "keccak-hasher", "memory-db", @@ -21959,25 +21930,6 @@ version = "1.0.9" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f4f195fd851901624eee5a58c4bb2b4f06399148fcd0ed336e6f1cb60a9881df" -[[package]] -name = "tungstenite" -version = "0.17.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e27992fd6a8c29ee7eef28fc78349aa244134e10ad447ce3b9f0ac0ed0fa4ce0" -dependencies = [ - "base64 0.13.1", - "byteorder", - "bytes", - "http", - "httparse", - "log", - "rand 0.8.5", - "sha-1 0.10.1", - "thiserror", - "url", - "utf-8", -] - [[package]] name = "tungstenite" version = "0.20.1" @@ -21998,6 +21950,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" @@ -22085,16 +22043,6 @@ version = "0.2.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f962df74c8c05a667b5ee8bcf162993134c104e96440b663c8daa176dc772d8c" -[[package]] -name = "universal-hash" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8326b2c654932e3e4f9196e69d08fdf7cfd718e1dc6f66b347e6024a0c961402" -dependencies = [ - "generic-array 0.14.7", - "subtle 2.5.0", -] - [[package]] name = "universal-hash" version = "0.5.1" @@ -22249,7 +22197,7 @@ dependencies = [ "rand 0.8.5", "rand_chacha 0.3.1", "rand_core 0.6.4", - "sha2 0.10.7", + "sha2 0.10.8", "sha3", "thiserror", "zeroize", @@ -22322,9 +22270,9 @@ dependencies = [ "bumpalo", "log", "once_cell", - "proc-macro2 1.0.75", + "proc-macro2 1.0.82", "quote 1.0.35", - "syn 2.0.53", + "syn 2.0.61", "wasm-bindgen-shared", ] @@ -22356,9 +22304,9 @@ version = "0.2.87" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "54681b18a46765f095758388f2d0cf16eb8d4169b639ab575a8f5693af210c7b" dependencies = [ - "proc-macro2 1.0.75", + "proc-macro2 1.0.82", "quote 1.0.35", - "syn 2.0.53", + "syn 2.0.61", "wasm-bindgen-backend", "wasm-bindgen-shared", ] @@ -22389,7 +22337,7 @@ version = "0.3.37" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ecb993dd8c836930ed130e020e77d9b2e65dd0fbab1b67c790b0f5d80b11a575" dependencies = [ - "proc-macro2 1.0.75", + "proc-macro2 1.0.82", "quote 1.0.35", ] @@ -22567,7 +22515,7 @@ dependencies = [ "log", "rustix 0.36.15", "serde", - "sha2 0.10.7", + "sha2 0.10.8", "toml 0.5.11", "windows-sys 0.45.0", "zstd 0.11.2+zstd.1.5.2", @@ -22781,8 +22729,10 @@ dependencies = [ "sp-consensus-beefy", "sp-core", "sp-runtime", + "staging-xcm", "westend-runtime", "westend-runtime-constants", + "xcm-fee-payment-runtime-api", ] [[package]] @@ -23361,6 +23311,31 @@ dependencies = [ "libc", ] +[[package]] +name = "xcm-docs" +version = "0.1.0" +dependencies = [ + "docify", + "pallet-balances", + "pallet-message-queue", + "pallet-xcm", + "parity-scale-codec", + "polkadot-parachain-primitives", + "polkadot-primitives", + "polkadot-runtime-parachains", + "polkadot-sdk-frame", + "scale-info", + "simple-mermaid 0.1.0", + "sp-io", + "sp-runtime", + "sp-std 14.0.0", + "staging-xcm", + "staging-xcm-builder", + "staging-xcm-executor", + "test-log", + "xcm-simulator", +] + [[package]] name = "xcm-emulator" version = "0.5.0" @@ -23422,14 +23397,24 @@ dependencies = [ name = "xcm-fee-payment-runtime-api" version = "0.1.0" dependencies = [ + "env_logger 0.9.3", + "frame-executive", "frame-support", + "frame-system", + "log", + "pallet-assets", + "pallet-balances", + "pallet-xcm", "parity-scale-codec", "scale-info", "sp-api", + "sp-io", "sp-runtime", "sp-std 14.0.0", "sp-weights", "staging-xcm", + "staging-xcm-builder", + "staging-xcm-executor", ] [[package]] @@ -23437,10 +23422,10 @@ name = "xcm-procedural" version = "7.0.0" dependencies = [ "Inflector", - "proc-macro2 1.0.75", + "proc-macro2 1.0.82", "quote 1.0.35", "staging-xcm", - "syn 2.0.53", + "syn 2.0.61", "trybuild", ] @@ -23449,12 +23434,16 @@ name = "xcm-simulator" version = "7.0.0" dependencies = [ "frame-support", + "frame-system", "parity-scale-codec", "paste", "polkadot-core-primitives", "polkadot-parachain-primitives", + "polkadot-primitives", "polkadot-runtime-parachains", + "scale-info", "sp-io", + "sp-runtime", "sp-std 14.0.0", "staging-xcm", "staging-xcm-builder", @@ -23560,9 +23549,9 @@ version = "0.7.32" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9ce1b18ccd8e73a9321186f97e46f9f04b778851177567b1975109d26a08d2a6" dependencies = [ - "proc-macro2 1.0.75", + "proc-macro2 1.0.82", "quote 1.0.35", - "syn 2.0.53", + "syn 2.0.61", ] [[package]] @@ -23580,9 +23569,9 @@ version = "1.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ce36e65b0d2999d2aafac989fb249189a141aee1f53c612c1f37d72631959f69" dependencies = [ - "proc-macro2 1.0.75", + "proc-macro2 1.0.82", "quote 1.0.35", - "syn 2.0.53", + "syn 2.0.61", ] [[package]] @@ -23597,7 +23586,7 @@ dependencies = [ "serde_json", "thiserror", "tokio", - "tokio-tungstenite 0.17.2", + "tokio-tungstenite", "tracing-gum", "url", ] diff --git a/Cargo.toml b/Cargo.toml index 460c49f7f37c2d43e021e4bfa8f4263ac1ea3063..1d02b701d2316ae09e84e3813304e43fee034ec5 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -103,6 +103,7 @@ members = [ "cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-westend", "cumulus/parachains/integration-tests/emulated/tests/bridges/bridge-hub-rococo", "cumulus/parachains/integration-tests/emulated/tests/bridges/bridge-hub-westend", + "cumulus/parachains/integration-tests/emulated/tests/collectives/collectives-westend", "cumulus/parachains/integration-tests/emulated/tests/people/people-rococo", "cumulus/parachains/integration-tests/emulated/tests/people/people-westend", "cumulus/parachains/pallets/collective-content", @@ -217,6 +218,7 @@ members = [ "polkadot/utils/generate-bags", "polkadot/utils/remote-ext-tests/bags-list", "polkadot/xcm", + "polkadot/xcm/docs", "polkadot/xcm/pallet-xcm", "polkadot/xcm/pallet-xcm-benchmarks", "polkadot/xcm/procedural", @@ -300,6 +302,7 @@ members = [ "substrate/frame", "substrate/frame/alliance", "substrate/frame/asset-conversion", + "substrate/frame/asset-conversion/ops", "substrate/frame/asset-rate", "substrate/frame/assets", "substrate/frame/atomic-swap", @@ -326,6 +329,7 @@ members = [ "substrate/frame/contracts/uapi", "substrate/frame/conviction-voting", "substrate/frame/core-fellowship", + "substrate/frame/delegated-staking", "substrate/frame/democracy", "substrate/frame/election-provider-multi-phase", "substrate/frame/election-provider-multi-phase/test-staking-e2e", @@ -498,7 +502,6 @@ members = [ "substrate/utils/build-script-utils", "substrate/utils/fork-tree", "substrate/utils/frame/benchmarking-cli", - "substrate/utils/frame/frame-utilities-cli", "substrate/utils/frame/generate-bags", "substrate/utils/frame/generate-bags/node-runtime", "substrate/utils/frame/omni-bencher", @@ -511,6 +514,7 @@ members = [ "substrate/utils/substrate-bip39", "substrate/utils/wasm-builder", + "templates/minimal", "templates/minimal/node", "templates/minimal/pallets/template", "templates/minimal/runtime", diff --git a/bridges/bin/runtime-common/Cargo.toml b/bridges/bin/runtime-common/Cargo.toml index 67b91a16a302d6214830241082b21c407b04c6d1..783009a8c890768bcc85dafec14dc3da9e8da573 100644 --- a/bridges/bin/runtime-common/Cargo.toml +++ b/bridges/bin/runtime-common/Cargo.toml @@ -11,11 +11,12 @@ license = "GPL-3.0-or-later WITH Classpath-exception-2.0" workspace = true [dependencies] -codec = { package = "parity-scale-codec", version = "3.6.1", default-features = false, features = ["derive"] } +codec = { package = "parity-scale-codec", version = "3.6.12", default-features = false, features = ["derive"] } hash-db = { version = "0.16.0", default-features = false } log = { workspace = true } scale-info = { version = "2.11.1", default-features = false, features = ["derive"] } static_assertions = { version = "1.1", optional = true } +tuplex = { version = "0.1", default-features = false } # Bridge dependencies @@ -82,6 +83,7 @@ std = [ "sp-runtime/std", "sp-std/std", "sp-trie/std", + "tuplex/std", "xcm-builder/std", "xcm/std", ] diff --git a/bridges/bin/runtime-common/src/extensions/check_obsolete_extension.rs b/bridges/bin/runtime-common/src/extensions/check_obsolete_extension.rs index 4b0c052df8008410cb531c21d173ead2c4fdd450..2c152aef68226aee36e791a882b5859427a9a33d 100644 --- a/bridges/bin/runtime-common/src/extensions/check_obsolete_extension.rs +++ b/bridges/bin/runtime-common/src/extensions/check_obsolete_extension.rs @@ -18,55 +18,229 @@ //! obsolete (duplicated) data or do not pass some additional pallet-specific //! checks. -use crate::messages_call_ext::MessagesCallSubType; -use pallet_bridge_grandpa::CallSubType as GrandpaCallSubType; -use pallet_bridge_parachains::CallSubType as ParachainsCallSubtype; -use sp_runtime::transaction_validity::TransactionValidity; +use crate::{ + extensions::refund_relayer_extension::RefundableParachainId, + messages_call_ext::MessagesCallSubType, +}; +use bp_relayers::ExplicitOrAccountParams; +use bp_runtime::Parachain; +use pallet_bridge_grandpa::{ + BridgedBlockNumber, CallSubType as GrandpaCallSubType, SubmitFinalityProofHelper, +}; +use pallet_bridge_parachains::{ + CallSubType as ParachainsCallSubtype, SubmitParachainHeadsHelper, SubmitParachainHeadsInfo, +}; +use pallet_bridge_relayers::Pallet as RelayersPallet; +use sp_runtime::{ + traits::{Get, PhantomData, UniqueSaturatedInto}, + transaction_validity::{TransactionPriority, TransactionValidity, ValidTransactionBuilder}, +}; /// A duplication of the `FilterCall` trait. /// /// We need this trait in order to be able to implement it for the messages pallet, /// since the implementation is done outside of the pallet crate. -pub trait BridgeRuntimeFilterCall { - /// Checks if a runtime call is valid. - fn validate(call: &Call) -> TransactionValidity; +pub trait BridgeRuntimeFilterCall { + /// Data that may be passed from the validate to `post_dispatch`. + type ToPostDispatch; + /// Called during validation. Needs to checks whether a runtime call, submitted + /// by the `who` is valid. `who` may be `None` if transaction is not signed + /// by a regular account. + fn validate(who: &AccountId, call: &Call) -> (Self::ToPostDispatch, TransactionValidity); + /// Called after transaction is dispatched. + fn post_dispatch(_who: &AccountId, _has_failed: bool, _to_post_dispatch: Self::ToPostDispatch) { + } +} + +/// Wrapper for the bridge GRANDPA pallet that checks calls for obsolete submissions +/// and also boosts transaction priority if it has submitted by registered relayer. +/// The boost is computed as +/// `(BundledHeaderNumber - 1 - BestFinalizedHeaderNumber) * Priority::get()`. +/// The boost is only applied if submitter has active registration in the relayers +/// pallet. +pub struct CheckAndBoostBridgeGrandpaTransactions( + PhantomData<(T, I, Priority, SlashAccount)>, +); + +impl, SlashAccount: Get> + BridgeRuntimeFilterCall + for CheckAndBoostBridgeGrandpaTransactions +where + T: pallet_bridge_relayers::Config + pallet_bridge_grandpa::Config, + T::RuntimeCall: GrandpaCallSubType, +{ + // bridged header number, bundled in transaction + type ToPostDispatch = Option>; + + fn validate( + who: &T::AccountId, + call: &T::RuntimeCall, + ) -> (Self::ToPostDispatch, TransactionValidity) { + match GrandpaCallSubType::::check_obsolete_submit_finality_proof(call) { + Ok(Some(our_tx)) => { + let to_post_dispatch = Some(our_tx.base.block_number); + let total_priority_boost = + compute_priority_boost::(who, our_tx.improved_by); + ( + to_post_dispatch, + ValidTransactionBuilder::default().priority(total_priority_boost).build(), + ) + }, + Ok(None) => (None, ValidTransactionBuilder::default().build()), + Err(e) => (None, Err(e)), + } + } + + fn post_dispatch( + relayer: &T::AccountId, + has_failed: bool, + bundled_block_number: Self::ToPostDispatch, + ) { + // we are only interested in associated pallet submissions + let Some(bundled_block_number) = bundled_block_number else { return }; + // we are only interested in failed or unneeded transactions + let has_failed = + has_failed || !SubmitFinalityProofHelper::::was_successful(bundled_block_number); + + if !has_failed { + return + } + + // let's slash registered relayer + RelayersPallet::::slash_and_deregister( + relayer, + ExplicitOrAccountParams::Explicit(SlashAccount::get()), + ); + } +} + +/// Wrapper for the bridge parachains pallet that checks calls for obsolete submissions +/// and also boosts transaction priority if it has submitted by registered relayer. +/// The boost is computed as +/// `(BundledHeaderNumber - 1 - BestKnownHeaderNumber) * Priority::get()`. +/// The boost is only applied if submitter has active registration in the relayers +/// pallet. +pub struct CheckAndBoostBridgeParachainsTransactions( + PhantomData<(T, RefPara, Priority, SlashAccount)>, +); + +impl, SlashAccount: Get> + BridgeRuntimeFilterCall + for CheckAndBoostBridgeParachainsTransactions +where + T: pallet_bridge_relayers::Config + pallet_bridge_parachains::Config, + RefPara: RefundableParachainId, + T::RuntimeCall: ParachainsCallSubtype, +{ + // bridged header number, bundled in transaction + type ToPostDispatch = Option; + + fn validate( + who: &T::AccountId, + call: &T::RuntimeCall, + ) -> (Self::ToPostDispatch, TransactionValidity) { + match ParachainsCallSubtype::::check_obsolete_submit_parachain_heads( + call, + ) { + Ok(Some(our_tx)) if our_tx.base.para_id.0 == RefPara::BridgedChain::PARACHAIN_ID => { + let to_post_dispatch = Some(our_tx.base); + let total_priority_boost = + compute_priority_boost::(&who, our_tx.improved_by); + ( + to_post_dispatch, + ValidTransactionBuilder::default().priority(total_priority_boost).build(), + ) + }, + Ok(_) => (None, ValidTransactionBuilder::default().build()), + Err(e) => (None, Err(e)), + } + } + + fn post_dispatch(relayer: &T::AccountId, has_failed: bool, maybe_update: Self::ToPostDispatch) { + // we are only interested in associated pallet submissions + let Some(update) = maybe_update else { return }; + // we are only interested in failed or unneeded transactions + let has_failed = has_failed || + !SubmitParachainHeadsHelper::::was_successful(&update); + + if !has_failed { + return + } + + // let's slash registered relayer + RelayersPallet::::slash_and_deregister( + relayer, + ExplicitOrAccountParams::Explicit(SlashAccount::get()), + ); + } } -impl BridgeRuntimeFilterCall for pallet_bridge_grandpa::Pallet +impl BridgeRuntimeFilterCall + for pallet_bridge_grandpa::Pallet where T: pallet_bridge_grandpa::Config, T::RuntimeCall: GrandpaCallSubType, { - fn validate(call: &T::RuntimeCall) -> TransactionValidity { - GrandpaCallSubType::::check_obsolete_submit_finality_proof(call) + type ToPostDispatch = (); + fn validate(_who: &T::AccountId, call: &T::RuntimeCall) -> ((), TransactionValidity) { + ( + (), + GrandpaCallSubType::::check_obsolete_submit_finality_proof(call) + .and_then(|_| ValidTransactionBuilder::default().build()), + ) } } -impl BridgeRuntimeFilterCall +impl BridgeRuntimeFilterCall for pallet_bridge_parachains::Pallet where T: pallet_bridge_parachains::Config, T::RuntimeCall: ParachainsCallSubtype, { - fn validate(call: &T::RuntimeCall) -> TransactionValidity { - ParachainsCallSubtype::::check_obsolete_submit_parachain_heads(call) + type ToPostDispatch = (); + fn validate(_who: &T::AccountId, call: &T::RuntimeCall) -> ((), TransactionValidity) { + ( + (), + ParachainsCallSubtype::::check_obsolete_submit_parachain_heads(call) + .and_then(|_| ValidTransactionBuilder::default().build()), + ) } } -impl, I: 'static> BridgeRuntimeFilterCall - for pallet_bridge_messages::Pallet +impl, I: 'static> + BridgeRuntimeFilterCall for pallet_bridge_messages::Pallet where T::RuntimeCall: MessagesCallSubType, { + type ToPostDispatch = (); /// Validate messages in order to avoid "mining" messages delivery and delivery confirmation /// transactions, that are delivering outdated messages/confirmations. Without this validation, /// even honest relayers may lose their funds if there are multiple relays running and /// submitting the same messages/confirmations. - fn validate(call: &T::RuntimeCall) -> TransactionValidity { - call.check_obsolete_call() + fn validate(_who: &T::AccountId, call: &T::RuntimeCall) -> ((), TransactionValidity) { + ((), call.check_obsolete_call()) } } +/// Computes priority boost that improved known header by `improved_by` +fn compute_priority_boost( + relayer: &T::AccountId, + improved_by: N, +) -> TransactionPriority +where + T: pallet_bridge_relayers::Config, + N: UniqueSaturatedInto, + Priority: Get, +{ + // we only boost priority if relayer has staked required balance + let is_relayer_registration_active = RelayersPallet::::is_registration_active(relayer); + // if tx improves by just one, there's no need to bump its priority + let improved_by: TransactionPriority = improved_by.unique_saturated_into().saturating_sub(1); + // if relayer is registered, for every skipped header we improve by `Priority` + let boost_per_header = if is_relayer_registration_active { Priority::get() } else { 0 }; + improved_by.saturating_mul(boost_per_header) +} + /// Declares a runtime-specific `BridgeRejectObsoleteHeadersAndMessages` signed extension. /// /// ## Example @@ -92,7 +266,15 @@ macro_rules! generate_bridge_reject_obsolete_headers_and_messages { type AccountId = $account_id; type Call = $call; type AdditionalSigned = (); - type Pre = (); + type Pre = ( + $account_id, + ( $( + <$filter_call as $crate::extensions::check_obsolete_extension::BridgeRuntimeFilterCall< + $account_id, + $call, + >>::ToPostDispatch, + )* ), + ); fn additional_signed(&self) -> sp_std::result::Result< (), @@ -101,29 +283,72 @@ macro_rules! generate_bridge_reject_obsolete_headers_and_messages { Ok(()) } + #[allow(unused_variables)] fn validate( &self, - _who: &Self::AccountId, + who: &Self::AccountId, call: &Self::Call, _info: &sp_runtime::traits::DispatchInfoOf, _len: usize, ) -> sp_runtime::transaction_validity::TransactionValidity { - let valid = sp_runtime::transaction_validity::ValidTransaction::default(); + let tx_validity = sp_runtime::transaction_validity::ValidTransaction::default(); + let to_prepare = (); $( - let valid = valid - .combine_with(<$filter_call as $crate::extensions::check_obsolete_extension::BridgeRuntimeFilterCall<$call>>::validate(call)?); + let (from_validate, call_filter_validity) = < + $filter_call as + $crate::extensions::check_obsolete_extension::BridgeRuntimeFilterCall< + Self::AccountId, + $call, + >>::validate(&who, call); + let tx_validity = tx_validity.combine_with(call_filter_validity?); )* - Ok(valid) + Ok(tx_validity) } + #[allow(unused_variables)] fn pre_dispatch( self, - who: &Self::AccountId, + relayer: &Self::AccountId, call: &Self::Call, info: &sp_runtime::traits::DispatchInfoOf, len: usize, ) -> Result { - self.validate(who, call, info, len).map(drop) + use tuplex::PushBack; + let to_post_dispatch = (); + $( + let (from_validate, call_filter_validity) = < + $filter_call as + $crate::extensions::check_obsolete_extension::BridgeRuntimeFilterCall< + $account_id, + $call, + >>::validate(&relayer, call); + let _ = call_filter_validity?; + let to_post_dispatch = to_post_dispatch.push_back(from_validate); + )* + Ok((relayer.clone(), to_post_dispatch)) + } + + #[allow(unused_variables)] + fn post_dispatch( + to_post_dispatch: Option, + info: &sp_runtime::traits::DispatchInfoOf, + post_info: &sp_runtime::traits::PostDispatchInfoOf, + len: usize, + result: &sp_runtime::DispatchResult, + ) -> Result<(), sp_runtime::transaction_validity::TransactionValidityError> { + use tuplex::PopFront; + let Some((relayer, to_post_dispatch)) = to_post_dispatch else { return Ok(()) }; + let has_failed = result.is_err(); + $( + let (item, to_post_dispatch) = to_post_dispatch.pop_front(); + < + $filter_call as + $crate::extensions::check_obsolete_extension::BridgeRuntimeFilterCall< + $account_id, + $call, + >>::post_dispatch(&relayer, has_failed, item); + )* + Ok(()) } } }; @@ -132,10 +357,23 @@ macro_rules! generate_bridge_reject_obsolete_headers_and_messages { #[cfg(test)] mod tests { use super::*; + use crate::{ + extensions::refund_relayer_extension::{ + tests::{ + initialize_environment, relayer_account_at_this_chain, + submit_parachain_head_call_ex, submit_relay_header_call_ex, + }, + RefundableParachain, + }, + mock::*, + }; + use bp_polkadot_core::parachains::ParaId; + use bp_runtime::HeaderId; use frame_support::{assert_err, assert_ok}; use sp_runtime::{ - traits::SignedExtension, + traits::{ConstU64, SignedExtension}, transaction_validity::{InvalidTransaction, TransactionValidity, ValidTransaction}, + DispatchError, }; pub struct MockCall { @@ -143,7 +381,7 @@ mod tests { } impl sp_runtime::traits::Dispatchable for MockCall { - type RuntimeOrigin = (); + type RuntimeOrigin = u64; type Config = (); type Info = (); type PostInfo = (); @@ -156,50 +394,287 @@ mod tests { } } - struct FirstFilterCall; - impl BridgeRuntimeFilterCall for FirstFilterCall { - fn validate(call: &MockCall) -> TransactionValidity { + pub struct FirstFilterCall; + impl FirstFilterCall { + fn post_dispatch_called_with(success: bool) { + frame_support::storage::unhashed::put(&[1], &success); + } + + fn verify_post_dispatch_called_with(success: bool) { + assert_eq!(frame_support::storage::unhashed::get::(&[1]), Some(success)); + } + } + + impl BridgeRuntimeFilterCall for FirstFilterCall { + type ToPostDispatch = u64; + fn validate(_who: &u64, call: &MockCall) -> (u64, TransactionValidity) { if call.data <= 1 { - return InvalidTransaction::Custom(1).into() + return (1, InvalidTransaction::Custom(1).into()) } - Ok(ValidTransaction { priority: 1, ..Default::default() }) + (1, Ok(ValidTransaction { priority: 1, ..Default::default() })) + } + + fn post_dispatch(_who: &u64, has_failed: bool, to_post_dispatch: Self::ToPostDispatch) { + Self::post_dispatch_called_with(!has_failed); + assert_eq!(to_post_dispatch, 1); + } + } + + pub struct SecondFilterCall; + + impl SecondFilterCall { + fn post_dispatch_called_with(success: bool) { + frame_support::storage::unhashed::put(&[2], &success); + } + + fn verify_post_dispatch_called_with(success: bool) { + assert_eq!(frame_support::storage::unhashed::get::(&[2]), Some(success)); } } - struct SecondFilterCall; - impl BridgeRuntimeFilterCall for SecondFilterCall { - fn validate(call: &MockCall) -> TransactionValidity { + impl BridgeRuntimeFilterCall for SecondFilterCall { + type ToPostDispatch = u64; + fn validate(_who: &u64, call: &MockCall) -> (u64, TransactionValidity) { if call.data <= 2 { - return InvalidTransaction::Custom(2).into() + return (2, InvalidTransaction::Custom(2).into()) } - Ok(ValidTransaction { priority: 2, ..Default::default() }) + (2, Ok(ValidTransaction { priority: 2, ..Default::default() })) + } + + fn post_dispatch(_who: &u64, has_failed: bool, to_post_dispatch: Self::ToPostDispatch) { + Self::post_dispatch_called_with(!has_failed); + assert_eq!(to_post_dispatch, 2); } } #[test] - fn test() { + fn test_generated_obsolete_extension() { generate_bridge_reject_obsolete_headers_and_messages!( MockCall, - (), + u64, FirstFilterCall, SecondFilterCall ); - assert_err!( - BridgeRejectObsoleteHeadersAndMessages.validate(&(), &MockCall { data: 1 }, &(), 0), - InvalidTransaction::Custom(1) - ); + run_test(|| { + assert_err!( + BridgeRejectObsoleteHeadersAndMessages.validate(&42, &MockCall { data: 1 }, &(), 0), + InvalidTransaction::Custom(1) + ); + assert_err!( + BridgeRejectObsoleteHeadersAndMessages.pre_dispatch( + &42, + &MockCall { data: 1 }, + &(), + 0 + ), + InvalidTransaction::Custom(1) + ); - assert_err!( - BridgeRejectObsoleteHeadersAndMessages.validate(&(), &MockCall { data: 2 }, &(), 0), - InvalidTransaction::Custom(2) - ); + assert_err!( + BridgeRejectObsoleteHeadersAndMessages.validate(&42, &MockCall { data: 2 }, &(), 0), + InvalidTransaction::Custom(2) + ); + assert_err!( + BridgeRejectObsoleteHeadersAndMessages.pre_dispatch( + &42, + &MockCall { data: 2 }, + &(), + 0 + ), + InvalidTransaction::Custom(2) + ); - assert_ok!( - BridgeRejectObsoleteHeadersAndMessages.validate(&(), &MockCall { data: 3 }, &(), 0), - ValidTransaction { priority: 3, ..Default::default() } - ) + assert_eq!( + BridgeRejectObsoleteHeadersAndMessages + .validate(&42, &MockCall { data: 3 }, &(), 0) + .unwrap(), + ValidTransaction { priority: 3, ..Default::default() }, + ); + assert_eq!( + BridgeRejectObsoleteHeadersAndMessages + .pre_dispatch(&42, &MockCall { data: 3 }, &(), 0) + .unwrap(), + (42, (1, 2)), + ); + + // when post_dispatch is called with `Ok(())`, it is propagated to all "nested" + // extensions + assert_ok!(BridgeRejectObsoleteHeadersAndMessages::post_dispatch( + Some((0, (1, 2))), + &(), + &(), + 0, + &Ok(()) + )); + FirstFilterCall::verify_post_dispatch_called_with(true); + SecondFilterCall::verify_post_dispatch_called_with(true); + + // when post_dispatch is called with `Err(())`, it is propagated to all "nested" + // extensions + assert_ok!(BridgeRejectObsoleteHeadersAndMessages::post_dispatch( + Some((0, (1, 2))), + &(), + &(), + 0, + &Err(DispatchError::BadOrigin) + )); + FirstFilterCall::verify_post_dispatch_called_with(false); + SecondFilterCall::verify_post_dispatch_called_with(false); + }); + } + + frame_support::parameter_types! { + pub SlashDestination: ThisChainAccountId = 42; + } + + type BridgeGrandpaWrapper = + CheckAndBoostBridgeGrandpaTransactions, SlashDestination>; + + #[test] + fn grandpa_wrapper_does_not_boost_extensions_for_unregistered_relayer() { + run_test(|| { + initialize_environment(100, 100, 100); + + let priority_boost = BridgeGrandpaWrapper::validate( + &relayer_account_at_this_chain(), + &submit_relay_header_call_ex(200), + ) + .1 + .unwrap() + .priority; + assert_eq!(priority_boost, 0); + }) + } + + #[test] + fn grandpa_wrapper_boosts_extensions_for_registered_relayer() { + run_test(|| { + initialize_environment(100, 100, 100); + BridgeRelayers::register(RuntimeOrigin::signed(relayer_account_at_this_chain()), 1000) + .unwrap(); + + let priority_boost = BridgeGrandpaWrapper::validate( + &relayer_account_at_this_chain(), + &submit_relay_header_call_ex(200), + ) + .1 + .unwrap() + .priority; + assert_eq!(priority_boost, 99_000); + }) + } + + #[test] + fn grandpa_wrapper_slashes_registered_relayer_if_transaction_fails() { + run_test(|| { + initialize_environment(100, 100, 100); + BridgeRelayers::register(RuntimeOrigin::signed(relayer_account_at_this_chain()), 1000) + .unwrap(); + + assert!(BridgeRelayers::is_registration_active(&relayer_account_at_this_chain())); + BridgeGrandpaWrapper::post_dispatch(&relayer_account_at_this_chain(), true, Some(150)); + assert!(!BridgeRelayers::is_registration_active(&relayer_account_at_this_chain())); + }) + } + + #[test] + fn grandpa_wrapper_does_not_slash_registered_relayer_if_transaction_succeeds() { + run_test(|| { + initialize_environment(100, 100, 100); + BridgeRelayers::register(RuntimeOrigin::signed(relayer_account_at_this_chain()), 1000) + .unwrap(); + + assert!(BridgeRelayers::is_registration_active(&relayer_account_at_this_chain())); + BridgeGrandpaWrapper::post_dispatch(&relayer_account_at_this_chain(), false, Some(100)); + assert!(BridgeRelayers::is_registration_active(&relayer_account_at_this_chain())); + }) + } + + type BridgeParachainsWrapper = CheckAndBoostBridgeParachainsTransactions< + TestRuntime, + RefundableParachain<(), BridgedUnderlyingParachain>, + ConstU64<1_000>, + SlashDestination, + >; + + #[test] + fn parachains_wrapper_does_not_boost_extensions_for_unregistered_relayer() { + run_test(|| { + initialize_environment(100, 100, 100); + + let priority_boost = BridgeParachainsWrapper::validate( + &relayer_account_at_this_chain(), + &submit_parachain_head_call_ex(200), + ) + .1 + .unwrap() + .priority; + assert_eq!(priority_boost, 0); + }) + } + + #[test] + fn parachains_wrapper_boosts_extensions_for_registered_relayer() { + run_test(|| { + initialize_environment(100, 100, 100); + BridgeRelayers::register(RuntimeOrigin::signed(relayer_account_at_this_chain()), 1000) + .unwrap(); + + let priority_boost = BridgeParachainsWrapper::validate( + &relayer_account_at_this_chain(), + &submit_parachain_head_call_ex(200), + ) + .1 + .unwrap() + .priority; + assert_eq!(priority_boost, 99_000); + }) + } + + #[test] + fn parachains_wrapper_slashes_registered_relayer_if_transaction_fails() { + run_test(|| { + initialize_environment(100, 100, 100); + BridgeRelayers::register(RuntimeOrigin::signed(relayer_account_at_this_chain()), 1000) + .unwrap(); + + assert!(BridgeRelayers::is_registration_active(&relayer_account_at_this_chain())); + BridgeParachainsWrapper::post_dispatch( + &relayer_account_at_this_chain(), + true, + Some(SubmitParachainHeadsInfo { + at_relay_block: HeaderId(150, Default::default()), + para_id: ParaId(BridgedUnderlyingParachain::PARACHAIN_ID), + para_head_hash: [150u8; 32].into(), + is_free_execution_expected: false, + }), + ); + assert!(!BridgeRelayers::is_registration_active(&relayer_account_at_this_chain())); + }) + } + + #[test] + fn parachains_wrapper_does_not_slash_registered_relayer_if_transaction_succeeds() { + run_test(|| { + initialize_environment(100, 100, 100); + BridgeRelayers::register(RuntimeOrigin::signed(relayer_account_at_this_chain()), 1000) + .unwrap(); + + assert!(BridgeRelayers::is_registration_active(&relayer_account_at_this_chain())); + BridgeParachainsWrapper::post_dispatch( + &relayer_account_at_this_chain(), + false, + Some(SubmitParachainHeadsInfo { + at_relay_block: HeaderId(100, Default::default()), + para_id: ParaId(BridgedUnderlyingParachain::PARACHAIN_ID), + para_head_hash: [100u8; 32].into(), + is_free_execution_expected: false, + }), + ); + assert!(BridgeRelayers::is_registration_active(&relayer_account_at_this_chain())); + }) } } diff --git a/bridges/bin/runtime-common/src/extensions/priority_calculator.rs b/bridges/bin/runtime-common/src/extensions/priority_calculator.rs index 5035553f508dfea94a0cb5ddf9b916dd7d9b4ea5..92810290f95e77a7fdc04cafaa1e6ab290e1661a 100644 --- a/bridges/bin/runtime-common/src/extensions/priority_calculator.rs +++ b/bridges/bin/runtime-common/src/extensions/priority_calculator.rs @@ -22,7 +22,6 @@ //! single message with nonce `N`, then the transaction with nonces `N..=N+100` will //! be rejected. This can lower bridge throughput down to one message per block. -use bp_messages::MessageNonce; use frame_support::traits::Get; use sp_runtime::transaction_validity::TransactionPriority; @@ -30,16 +29,19 @@ use sp_runtime::transaction_validity::TransactionPriority; #[allow(unused_imports)] pub use integrity_tests::*; -/// Compute priority boost for message delivery transaction that delivers -/// given number of messages. -pub fn compute_priority_boost( - messages: MessageNonce, -) -> TransactionPriority +/// We'll deal with different bridge items here - messages, headers, ... +/// To avoid being too verbose with generic code, let's just define a separate alias. +pub type ItemCount = u64; + +/// Compute priority boost for transaction that brings given number of bridge +/// items (messages, headers, ...), when every additional item adds `PriorityBoostPerItem` +/// to transaction priority. +pub fn compute_priority_boost(n_items: ItemCount) -> TransactionPriority where - PriorityBoostPerMessage: Get, + PriorityBoostPerItem: Get, { - // we don't want any boost for transaction with single message => minus one - PriorityBoostPerMessage::get().saturating_mul(messages.saturating_sub(1)) + // we don't want any boost for transaction with single (additional) item => minus one + PriorityBoostPerItem::get().saturating_mul(n_items.saturating_sub(1)) } #[cfg(not(feature = "integrity-test"))] @@ -47,7 +49,8 @@ mod integrity_tests {} #[cfg(feature = "integrity-test")] mod integrity_tests { - use super::compute_priority_boost; + use super::{compute_priority_boost, ItemCount}; + use crate::extensions::refund_relayer_extension::RefundableParachainId; use bp_messages::MessageNonce; use bp_runtime::PreComputedSize; @@ -55,7 +58,6 @@ mod integrity_tests { dispatch::{DispatchClass, DispatchInfo, Pays, PostDispatchInfo}, traits::Get, }; - use pallet_bridge_messages::WeightInfoExt; use pallet_transaction_payment::OnChargeTransaction; use sp_runtime::{ traits::{Dispatchable, UniqueSaturatedInto, Zero}, @@ -68,37 +70,33 @@ mod integrity_tests { T, >>::Balance; - /// Ensures that the value of `PriorityBoostPerMessage` matches the value of - /// `tip_boost_per_message`. + /// Ensures that the value of `PriorityBoostPerItem` matches the value of + /// `tip_boost_per_item`. /// - /// We want two transactions, `TX1` with `N` messages and `TX2` with `N+1` messages, have almost - /// the same priority if we'll add `tip_boost_per_message` tip to the `TX1`. We want to be sure - /// that if we add plain `PriorityBoostPerMessage` priority to `TX1`, the priority will be close + /// We want two transactions, `TX1` with `N` items and `TX2` with `N+1` items, have almost + /// the same priority if we'll add `tip_boost_per_item` tip to the `TX1`. We want to be sure + /// that if we add plain `PriorityBoostPerItem` priority to `TX1`, the priority will be close /// to `TX2` as well. - pub fn ensure_priority_boost_is_sane( - tip_boost_per_message: BalanceOf, + fn ensure_priority_boost_is_sane( + param_name: &str, + max_items: ItemCount, + tip_boost_per_item: Balance, + estimate_priority: impl Fn(ItemCount, Balance) -> TransactionPriority, ) where - Runtime: - pallet_transaction_payment::Config + pallet_bridge_messages::Config, - MessagesInstance: 'static, - PriorityBoostPerMessage: Get, - Runtime::RuntimeCall: Dispatchable, - BalanceOf: Send + Sync + FixedPointOperand, + PriorityBoostPerItem: Get, + ItemCount: UniqueSaturatedInto, + Balance: FixedPointOperand + Zero, { - let priority_boost_per_message = PriorityBoostPerMessage::get(); - let maximal_messages_in_delivery_transaction = - Runtime::MaxUnconfirmedMessagesAtInboundLane::get(); - for messages in 1..=maximal_messages_in_delivery_transaction { - let base_priority = estimate_message_delivery_transaction_priority::< - Runtime, - MessagesInstance, - >(messages, Zero::zero()); - let priority_boost = compute_priority_boost::(messages); - let priority_with_boost = base_priority + priority_boost; - - let tip = tip_boost_per_message.saturating_mul((messages - 1).unique_saturated_into()); - let priority_with_tip = - estimate_message_delivery_transaction_priority::(1, tip); + let priority_boost_per_item = PriorityBoostPerItem::get(); + for n_items in 1..=max_items { + let base_priority = estimate_priority(n_items, Zero::zero()); + let priority_boost = compute_priority_boost::(n_items); + let priority_with_boost = base_priority + .checked_add(priority_boost) + .expect("priority overflow: try lowering `max_items` or `tip_boost_per_item`?"); + + let tip = tip_boost_per_item.saturating_mul((n_items - 1).unique_saturated_into()); + let priority_with_tip = estimate_priority(1, tip); const ERROR_MARGIN: TransactionPriority = 5; // 5% if priority_with_boost.abs_diff(priority_with_tip).saturating_mul(100) / @@ -106,97 +104,304 @@ mod integrity_tests { ERROR_MARGIN { panic!( - "The PriorityBoostPerMessage value ({}) must be fixed to: {}", - priority_boost_per_message, - compute_priority_boost_per_message::( - tip_boost_per_message + "The {param_name} value ({}) must be fixed to: {}", + priority_boost_per_item, + compute_priority_boost_per_item( + max_items, + tip_boost_per_item, + estimate_priority ), ); } } } - /// Compute priority boost that we give to message delivery transaction for additional message. + /// Compute priority boost that we give to bridge transaction for every + /// additional bridge item. #[cfg(feature = "integrity-test")] - fn compute_priority_boost_per_message( - tip_boost_per_message: BalanceOf, + fn compute_priority_boost_per_item( + max_items: ItemCount, + tip_boost_per_item: Balance, + estimate_priority: impl Fn(ItemCount, Balance) -> TransactionPriority, ) -> TransactionPriority where - Runtime: - pallet_transaction_payment::Config + pallet_bridge_messages::Config, - MessagesInstance: 'static, - Runtime::RuntimeCall: Dispatchable, - BalanceOf: Send + Sync + FixedPointOperand, + ItemCount: UniqueSaturatedInto, + Balance: FixedPointOperand + Zero, { - // estimate priority of transaction that delivers one message and has large tip - let maximal_messages_in_delivery_transaction = - Runtime::MaxUnconfirmedMessagesAtInboundLane::get(); + // estimate priority of transaction that delivers one item and has large tip let small_with_tip_priority = - estimate_message_delivery_transaction_priority::( - 1, - tip_boost_per_message - .saturating_mul(maximal_messages_in_delivery_transaction.saturated_into()), - ); - // estimate priority of transaction that delivers maximal number of messages, but has no tip - let large_without_tip_priority = estimate_message_delivery_transaction_priority::< - Runtime, - MessagesInstance, - >(maximal_messages_in_delivery_transaction, Zero::zero()); + estimate_priority(1, tip_boost_per_item.saturating_mul(max_items.saturated_into())); + // estimate priority of transaction that delivers maximal number of items, but has no tip + let large_without_tip_priority = estimate_priority(max_items, Zero::zero()); small_with_tip_priority .saturating_sub(large_without_tip_priority) - .saturating_div(maximal_messages_in_delivery_transaction - 1) + .saturating_div(max_items - 1) } - /// Estimate message delivery transaction priority. - #[cfg(feature = "integrity-test")] - fn estimate_message_delivery_transaction_priority( - messages: MessageNonce, - tip: BalanceOf, - ) -> TransactionPriority - where - Runtime: - pallet_transaction_payment::Config + pallet_bridge_messages::Config, - MessagesInstance: 'static, - Runtime::RuntimeCall: Dispatchable, - BalanceOf: Send + Sync + FixedPointOperand, - { - // just an estimation of extra transaction bytes that are added to every transaction - // (including signature, signed extensions extra and etc + in our case it includes - // all call arguments except the proof itself) - let base_tx_size = 512; - // let's say we are relaying similar small messages and for every message we add more trie - // nodes to the proof (x0.5 because we expect some nodes to be reused) - let estimated_message_size = 512; - // let's say all our messages have the same dispatch weight - let estimated_message_dispatch_weight = - Runtime::WeightInfo::message_dispatch_weight(estimated_message_size); - // messages proof argument size is (for every message) messages size + some additional - // trie nodes. Some of them are reused by different messages, so let's take 2/3 of default - // "overhead" constant - let messages_proof_size = Runtime::WeightInfo::expected_extra_storage_proof_size() - .saturating_mul(2) - .saturating_div(3) - .saturating_add(estimated_message_size) - .saturating_mul(messages as _); - - // 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( - &PreComputedSize(transaction_size as _), - messages as _, - estimated_message_dispatch_weight.saturating_mul(messages), - ); - - pallet_transaction_payment::ChargeTransactionPayment::::get_priority( - &DispatchInfo { - weight: transaction_weight, - class: DispatchClass::Normal, - pays_fee: Pays::Yes, - }, - transaction_size as _, - tip, - Zero::zero(), - ) + /// Computations, specific to bridge relay chains transactions. + pub mod per_relay_header { + use super::*; + + use bp_header_chain::{ + max_expected_submit_finality_proof_arguments_size, ChainWithGrandpa, + }; + use pallet_bridge_grandpa::WeightInfoExt; + + /// Ensures that the value of `PriorityBoostPerHeader` matches the value of + /// `tip_boost_per_header`. + /// + /// We want two transactions, `TX1` with `N` headers and `TX2` with `N+1` headers, have + /// almost the same priority if we'll add `tip_boost_per_header` tip to the `TX1`. We want + /// to be sure that if we add plain `PriorityBoostPerHeader` priority to `TX1`, the priority + /// will be close to `TX2` as well. + pub fn ensure_priority_boost_is_sane( + tip_boost_per_header: BalanceOf, + ) where + Runtime: + pallet_transaction_payment::Config + pallet_bridge_grandpa::Config, + GrandpaInstance: 'static, + PriorityBoostPerHeader: Get, + Runtime::RuntimeCall: Dispatchable, + BalanceOf: Send + Sync + FixedPointOperand, + { + // the meaning of `max_items` here is different when comparing with message + // transactions - with messages we have a strict limit on maximal number of + // messages we can fit into a single transaction. With headers, current best + // header may be improved by any "number of items". But this number is only + // used to verify priority boost, so it should be fine to select this arbitrary + // value - it SHALL NOT affect any value, it just adds more tests for the value. + let maximal_improved_by = 4_096; + super::ensure_priority_boost_is_sane::>( + "PriorityBoostPerRelayHeader", + maximal_improved_by, + tip_boost_per_header, + |_n_headers, tip| { + estimate_relay_header_submit_transaction_priority::( + tip, + ) + }, + ); + } + + /// Estimate relay header delivery transaction priority. + #[cfg(feature = "integrity-test")] + fn estimate_relay_header_submit_transaction_priority( + tip: BalanceOf, + ) -> TransactionPriority + where + Runtime: + pallet_transaction_payment::Config + pallet_bridge_grandpa::Config, + GrandpaInstance: 'static, + Runtime::RuntimeCall: Dispatchable, + BalanceOf: Send + Sync + FixedPointOperand, + { + // just an estimation of extra transaction bytes that are added to every transaction + // (including signature, signed extensions extra and etc + in our case it includes + // all call arguments except the proof itself) + let base_tx_size = 512; + // let's say we are relaying largest relay chain headers + let tx_call_size = max_expected_submit_finality_proof_arguments_size::< + Runtime::BridgedChain, + >(true, Runtime::BridgedChain::MAX_AUTHORITIES_COUNT * 2 / 3 + 1); + + // finally we are able to estimate transaction size and weight + let transaction_size = base_tx_size.saturating_add(tx_call_size); + let transaction_weight = Runtime::WeightInfo::submit_finality_proof_weight( + Runtime::BridgedChain::MAX_AUTHORITIES_COUNT * 2 / 3 + 1, + Runtime::BridgedChain::REASONABLE_HEADERS_IN_JUSTIFICATION_ANCESTRY, + ); + + pallet_transaction_payment::ChargeTransactionPayment::::get_priority( + &DispatchInfo { + weight: transaction_weight, + class: DispatchClass::Normal, + pays_fee: Pays::Yes, + }, + transaction_size as _, + tip, + Zero::zero(), + ) + } + } + + /// Computations, specific to bridge parachains transactions. + pub mod per_parachain_header { + use super::*; + + use bp_runtime::Parachain; + use pallet_bridge_parachains::WeightInfoExt; + + /// Ensures that the value of `PriorityBoostPerHeader` matches the value of + /// `tip_boost_per_header`. + /// + /// We want two transactions, `TX1` with `N` headers and `TX2` with `N+1` headers, have + /// almost the same priority if we'll add `tip_boost_per_header` tip to the `TX1`. We want + /// to be sure that if we add plain `PriorityBoostPerHeader` priority to `TX1`, the priority + /// will be close to `TX2` as well. + pub fn ensure_priority_boost_is_sane( + tip_boost_per_header: BalanceOf, + ) where + Runtime: pallet_transaction_payment::Config + + pallet_bridge_parachains::Config, + RefundableParachain: RefundableParachainId, + PriorityBoostPerHeader: Get, + Runtime::RuntimeCall: Dispatchable, + BalanceOf: Send + Sync + FixedPointOperand, + { + // the meaning of `max_items` here is different when comparing with message + // transactions - with messages we have a strict limit on maximal number of + // messages we can fit into a single transaction. With headers, current best + // header may be improved by any "number of items". But this number is only + // used to verify priority boost, so it should be fine to select this arbitrary + // value - it SHALL NOT affect any value, it just adds more tests for the value. + let maximal_improved_by = 4_096; + super::ensure_priority_boost_is_sane::>( + "PriorityBoostPerParachainHeader", + maximal_improved_by, + tip_boost_per_header, + |_n_headers, tip| { + estimate_parachain_header_submit_transaction_priority::< + Runtime, + RefundableParachain, + >(tip) + }, + ); + } + + /// Estimate parachain header delivery transaction priority. + #[cfg(feature = "integrity-test")] + fn estimate_parachain_header_submit_transaction_priority( + tip: BalanceOf, + ) -> TransactionPriority + where + Runtime: pallet_transaction_payment::Config + + pallet_bridge_parachains::Config, + RefundableParachain: RefundableParachainId, + Runtime::RuntimeCall: Dispatchable, + BalanceOf: Send + Sync + FixedPointOperand, + { + // just an estimation of extra transaction bytes that are added to every transaction + // (including signature, signed extensions extra and etc + in our case it includes + // all call arguments except the proof itself) + let base_tx_size = 512; + // let's say we are relaying largest parachain headers and proof takes some more bytes + let tx_call_size = >::WeightInfo::expected_extra_storage_proof_size() + .saturating_add(RefundableParachain::BridgedChain::MAX_HEADER_SIZE); + + // finally we are able to estimate transaction size and weight + let transaction_size = base_tx_size.saturating_add(tx_call_size); + let transaction_weight = >::WeightInfo::submit_parachain_heads_weight( + Runtime::DbWeight::get(), + &PreComputedSize(transaction_size as _), + // just one parachain - all other submissions won't receive any boost + 1, + ); + + pallet_transaction_payment::ChargeTransactionPayment::::get_priority( + &DispatchInfo { + weight: transaction_weight, + class: DispatchClass::Normal, + pays_fee: Pays::Yes, + }, + transaction_size as _, + tip, + Zero::zero(), + ) + } + } + + /// Computations, specific to bridge messages transactions. + pub mod per_message { + use super::*; + + use pallet_bridge_messages::WeightInfoExt; + + /// Ensures that the value of `PriorityBoostPerMessage` matches the value of + /// `tip_boost_per_message`. + /// + /// We want two transactions, `TX1` with `N` messages and `TX2` with `N+1` messages, have + /// almost the same priority if we'll add `tip_boost_per_message` tip to the `TX1`. We want + /// to be sure that if we add plain `PriorityBoostPerMessage` priority to `TX1`, the + /// priority will be close to `TX2` as well. + pub fn ensure_priority_boost_is_sane( + tip_boost_per_message: BalanceOf, + ) where + Runtime: pallet_transaction_payment::Config + + pallet_bridge_messages::Config, + MessagesInstance: 'static, + PriorityBoostPerMessage: Get, + Runtime::RuntimeCall: Dispatchable, + BalanceOf: Send + Sync + FixedPointOperand, + { + let maximal_messages_in_delivery_transaction = + Runtime::MaxUnconfirmedMessagesAtInboundLane::get(); + super::ensure_priority_boost_is_sane::>( + "PriorityBoostPerMessage", + maximal_messages_in_delivery_transaction, + tip_boost_per_message, + |n_messages, tip| { + estimate_message_delivery_transaction_priority::( + n_messages, tip, + ) + }, + ); + } + + /// Estimate message delivery transaction priority. + #[cfg(feature = "integrity-test")] + fn estimate_message_delivery_transaction_priority( + messages: MessageNonce, + tip: BalanceOf, + ) -> TransactionPriority + where + Runtime: pallet_transaction_payment::Config + + pallet_bridge_messages::Config, + MessagesInstance: 'static, + Runtime::RuntimeCall: Dispatchable, + BalanceOf: Send + Sync + FixedPointOperand, + { + // just an estimation of extra transaction bytes that are added to every transaction + // (including signature, signed extensions extra and etc + in our case it includes + // all call arguments except the proof itself) + let base_tx_size = 512; + // let's say we are relaying similar small messages and for every message we add more + // trie nodes to the proof (x0.5 because we expect some nodes to be reused) + let estimated_message_size = 512; + // let's say all our messages have the same dispatch weight + let estimated_message_dispatch_weight = + Runtime::WeightInfo::message_dispatch_weight(estimated_message_size); + // messages proof argument size is (for every message) messages size + some additional + // trie nodes. Some of them are reused by different messages, so let's take 2/3 of + // default "overhead" constant + let messages_proof_size = Runtime::WeightInfo::expected_extra_storage_proof_size() + .saturating_mul(2) + .saturating_div(3) + .saturating_add(estimated_message_size) + .saturating_mul(messages as _); + + // 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( + &PreComputedSize(transaction_size as _), + messages as _, + estimated_message_dispatch_weight.saturating_mul(messages), + ); + + pallet_transaction_payment::ChargeTransactionPayment::::get_priority( + &DispatchInfo { + weight: transaction_weight, + class: DispatchClass::Normal, + pays_fee: Pays::Yes, + }, + transaction_size as _, + tip, + Zero::zero(), + ) + } } } diff --git a/bridges/bin/runtime-common/src/extensions/refund_relayer_extension.rs b/bridges/bin/runtime-common/src/extensions/refund_relayer_extension.rs index 64ae1d0b669f2ea8fdfba0df73752a9b0f6e8aec..5aa7f1c095d540a4ee5050aeb7d694c98b744683 100644 --- a/bridges/bin/runtime-common/src/extensions/refund_relayer_extension.rs +++ b/bridges/bin/runtime-common/src/extensions/refund_relayer_extension.rs @@ -24,7 +24,7 @@ use crate::messages_call_ext::{ }; use bp_messages::{LaneId, MessageNonce}; use bp_relayers::{ExplicitOrAccountParams, RewardsAccountOwner, RewardsAccountParams}; -use bp_runtime::{Chain, Parachain, ParachainIdOf, RangeInclusiveExt, StaticStrProvider}; +use bp_runtime::{Parachain, RangeInclusiveExt, StaticStrProvider}; use codec::{Codec, Decode, Encode}; use frame_support::{ dispatch::{CallableCallFor, DispatchInfo, PostDispatchInfo}, @@ -33,8 +33,7 @@ use frame_support::{ CloneNoBound, DefaultNoBound, EqNoBound, PartialEqNoBound, RuntimeDebugNoBound, }; use pallet_bridge_grandpa::{ - CallSubType as GrandpaCallSubType, Config as GrandpaConfig, SubmitFinalityProofHelper, - SubmitFinalityProofInfo, + CallSubType as GrandpaCallSubType, SubmitFinalityProofHelper, SubmitFinalityProofInfo, }; use pallet_bridge_messages::Config as MessagesConfig; use pallet_bridge_parachains::{ @@ -66,20 +65,9 @@ type CallOf = ::RuntimeCall; /// coming from this parachain. pub trait RefundableParachainId { /// The instance of the bridge parachains pallet. - type Instance; + type Instance: 'static; /// The parachain Id. - type Id: Get; -} - -/// Default implementation of `RefundableParachainId`. -pub struct DefaultRefundableParachainId(PhantomData<(Instance, Id)>); - -impl RefundableParachainId for DefaultRefundableParachainId -where - Id: Get, -{ - type Instance = Instance; - type Id = Id; + type BridgedChain: Parachain; } /// Implementation of `RefundableParachainId` for `trait Parachain`. @@ -87,10 +75,11 @@ pub struct RefundableParachain(PhantomData<(Instance, Para)>); impl RefundableParachainId for RefundableParachain where + Instance: 'static, Para: Parachain, { type Instance = Instance; - type Id = ParachainIdOf; + type BridgedChain = Para; } /// Trait identifying a bridged messages lane. A relayer might be refunded for delivering messages @@ -242,17 +231,10 @@ pub enum RelayerAccountAction { /// Everything common among our refund signed extensions. pub trait RefundSignedExtension: 'static + Clone + Codec + sp_std::fmt::Debug + Default + Eq + PartialEq + Send + Sync + TypeInfo -where - >::BridgedChain: - Chain, { /// This chain runtime. - type Runtime: UtilityConfig> - + GrandpaConfig - + MessagesConfig<::Instance> + type Runtime: MessagesConfig<::Instance> + RelayersConfig; - /// Grandpa pallet reference. - type GrandpaInstance: 'static; /// Messages pallet and lane reference. type Msgs: RefundableMessagesLaneId; /// Refund amount calculator. @@ -276,11 +258,13 @@ where call: &CallOf, ) -> Result<&CallOf, TransactionValidityError>; - /// Called from post-dispatch and shall perform additional checks (apart from relay - /// chain finality and messages transaction finality) of given call result. + /// Called from post-dispatch and shall perform additional checks (apart from messages + /// transaction success) of given call result. fn additional_call_result_check( relayer: &AccountIdOf, call_info: &CallInfo, + extra_weight: &mut Weight, + extra_size: &mut u32, ) -> bool; /// Given post-dispatch information, analyze the outcome of relayer call and return @@ -348,35 +332,6 @@ where return slash_relayer_if_delivery_result } - // check if relay chain state has been updated - if let Some(finality_proof_info) = call_info.submit_finality_proof_info() { - if !SubmitFinalityProofHelper::::was_successful( - finality_proof_info.block_number, - ) { - // we only refund relayer if all calls have updated chain state - log::trace!( - target: "runtime::bridge", - "{} via {:?}: relayer {:?} has submitted invalid relay chain finality proof", - Self::Id::STR, - ::Id::get(), - relayer, - ); - return slash_relayer_if_delivery_result - } - - // there's a conflict between how bridge GRANDPA pallet works and a `utility.batchAll` - // transaction. If relay chain header is mandatory, the GRANDPA pallet returns - // `Pays::No`, because such transaction is mandatory for operating the bridge. But - // `utility.batchAll` transaction always requires payment. But in both cases we'll - // refund relayer - either explicitly here, or using `Pays::No` if he's choosing - // to submit dedicated transaction. - - // submitter has means to include extra weight/bytes in the `submit_finality_proof` - // call, so let's subtract extra weight/size to avoid refunding for this extra stuff - extra_weight = finality_proof_info.extra_weight; - extra_size = finality_proof_info.extra_size; - } - // Check if the `ReceiveMessagesProof` call delivered at least some of the messages that // it contained. If this happens, we consider the transaction "helpful" and refund it. let msgs_call_info = call_info.messages_call_info(); @@ -391,8 +346,13 @@ where return slash_relayer_if_delivery_result } - // do additional check - if !Self::additional_call_result_check(&relayer, &call_info) { + // do additional checks + if !Self::additional_call_result_check( + &relayer, + &call_info, + &mut extra_weight, + &mut extra_size, + ) { return slash_relayer_if_delivery_result } @@ -468,18 +428,11 @@ where RuntimeDebugNoBound, TypeInfo, )] -pub struct RefundSignedExtensionAdapter(T) -where - >::BridgedChain: - Chain; +pub struct RefundSignedExtensionAdapter(T); impl SignedExtension for RefundSignedExtensionAdapter where - >::BridgedChain: - Chain, CallOf: Dispatchable - + IsSubType, T::Runtime>> - + GrandpaCallSubType + MessagesCallSubType::Instance>, { const IDENTIFIER: &'static str = T::Id::STR; @@ -644,6 +597,14 @@ impl RefundSignedExtension for RefundBridgedParachainMessages where Self: 'static + Send + Sync, + RefundBridgedGrandpaMessages< + Runtime, + Runtime::BridgesGrandpaPalletInstance, + Msgs, + Refund, + Priority, + Id, + >: 'static + Send + Sync, Runtime: UtilityConfig> + BoundedBridgeGrandpaConfig + ParachainsConfig @@ -661,7 +622,6 @@ where + MessagesCallSubType, { type Runtime = Runtime; - type GrandpaInstance = Runtime::BridgesGrandpaPalletInstance; type Msgs = Msgs; type Refund = Refund; type Priority = Priority; @@ -687,7 +647,7 @@ where let para_finality_call = calls .next() .transpose()? - .and_then(|c| c.submit_parachain_heads_info_for(Para::Id::get())); + .and_then(|c| c.submit_parachain_heads_info_for(Para::BridgedChain::PARACHAIN_ID)); let relay_finality_call = calls.next().transpose()?.and_then(|c| c.submit_finality_proof_info()); @@ -711,7 +671,26 @@ where Ok(call) } - fn additional_call_result_check(relayer: &Runtime::AccountId, call_info: &CallInfo) -> bool { + fn additional_call_result_check( + relayer: &Runtime::AccountId, + call_info: &CallInfo, + extra_weight: &mut Weight, + extra_size: &mut u32, + ) -> bool { + // check if relay chain state has been updated + let is_grandpa_call_successful = + RefundBridgedGrandpaMessages::< + Runtime, + Runtime::BridgesGrandpaPalletInstance, + Msgs, + Refund, + Priority, + Id, + >::additional_call_result_check(relayer, call_info, extra_weight, extra_size); + if !is_grandpa_call_successful { + return false + } + // check if parachain state has been updated if let Some(para_proof_info) = call_info.submit_parachain_heads_info() { if !SubmitParachainHeadsHelper::::was_successful( @@ -722,7 +701,7 @@ where target: "runtime::bridge", "{} from parachain {} via {:?}: relayer {:?} has submitted invalid parachain finality proof", Id::STR, - Para::Id::get(), + Para::BridgedChain::PARACHAIN_ID, Msgs::Id::get(), relayer, ); @@ -794,7 +773,6 @@ where + MessagesCallSubType, { type Runtime = Runtime; - type GrandpaInstance = GrandpaInstance; type Msgs = Msgs; type Refund = Refund; type Priority = Priority; @@ -836,13 +814,125 @@ where Ok(call) } - fn additional_call_result_check(_relayer: &Runtime::AccountId, _call_info: &CallInfo) -> bool { + fn additional_call_result_check( + relayer: &Runtime::AccountId, + call_info: &CallInfo, + extra_weight: &mut Weight, + extra_size: &mut u32, + ) -> bool { + // check if relay chain state has been updated + if let Some(finality_proof_info) = call_info.submit_finality_proof_info() { + if !SubmitFinalityProofHelper::::was_successful( + finality_proof_info.block_number, + ) { + // we only refund relayer if all calls have updated chain state + log::trace!( + target: "runtime::bridge", + "{} via {:?}: relayer {:?} has submitted invalid relay chain finality proof", + Self::Id::STR, + ::Id::get(), + relayer, + ); + return false + } + + // there's a conflict between how bridge GRANDPA pallet works and a `utility.batchAll` + // transaction. If relay chain header is mandatory, the GRANDPA pallet returns + // `Pays::No`, because such transaction is mandatory for operating the bridge. But + // `utility.batchAll` transaction always requires payment. But in both cases we'll + // refund relayer - either explicitly here, or using `Pays::No` if he's choosing + // to submit dedicated transaction. + + // submitter has means to include extra weight/bytes in the `submit_finality_proof` + // call, so let's subtract extra weight/size to avoid refunding for this extra stuff + *extra_weight = (*extra_weight).saturating_add(finality_proof_info.extra_weight); + *extra_size = (*extra_size).saturating_add(finality_proof_info.extra_size); + } + + true + } +} + +/// Transaction extension that refunds a relayer for standalone messages delivery and confirmation +/// transactions. Finality transactions are not refunded. +#[derive( + DefaultNoBound, + CloneNoBound, + Decode, + Encode, + EqNoBound, + PartialEqNoBound, + RuntimeDebugNoBound, + TypeInfo, +)] +#[scale_info(skip_type_params(Runtime, GrandpaInstance, Msgs, Refund, Priority, Id))] +pub struct RefundBridgedMessages( + PhantomData<( + // runtime with `pallet-bridge-messages` and `pallet-bridge-relayers` pallets deployed + Runtime, + // implementation of `RefundableMessagesLaneId` trait, which specifies the instance of + // the used `pallet-bridge-messages` pallet and the lane within this pallet + Msgs, + // implementation of the `RefundCalculator` trait, that is used to compute refund that + // we give to relayer for his transaction + Refund, + // getter for per-message `TransactionPriority` boost that we give to message + // delivery transactions + Priority, + // the runtime-unique identifier of this signed extension + Id, + )>, +); + +impl RefundSignedExtension + for RefundBridgedMessages +where + Self: 'static + Send + Sync, + Runtime: MessagesConfig + RelayersConfig, + Msgs: RefundableMessagesLaneId, + Refund: RefundCalculator, + Priority: Get, + Id: StaticStrProvider, + CallOf: Dispatchable + + MessagesCallSubType, +{ + type Runtime = Runtime; + type Msgs = Msgs; + type Refund = Refund; + type Priority = Priority; + type Id = Id; + + fn expand_call(call: &CallOf) -> Vec<&CallOf> { + vec![call] + } + + fn parse_and_check_for_obsolete_call( + call: &CallOf, + ) -> Result, TransactionValidityError> { + let call = Self::check_obsolete_parsed_call(call)?; + Ok(call.call_info_for(Msgs::Id::get()).map(CallInfo::Msgs)) + } + + fn check_obsolete_parsed_call( + call: &CallOf, + ) -> Result<&CallOf, TransactionValidityError> { + call.check_obsolete_call()?; + Ok(call) + } + + fn additional_call_result_check( + _relayer: &Runtime::AccountId, + _call_info: &CallInfo, + _extra_weight: &mut Weight, + _extra_size: &mut u32, + ) -> bool { + // everything is checked by the `RefundTransactionExtension` true } } #[cfg(test)] -mod tests { +pub(crate) mod tests { use super::*; use crate::{ messages::{ @@ -854,6 +944,7 @@ mod tests { }, mock::*, }; + use bp_header_chain::StoredHeaderDataBuilder; use bp_messages::{ DeliveredMessages, InboundLaneData, MessageNonce, MessagesOperatingMode, OutboundLaneData, UnrewardedRelayer, UnrewardedRelayersState, @@ -879,7 +970,6 @@ mod tests { }; parameter_types! { - TestParachain: u32 = 1000; pub TestLaneId: LaneId = TEST_LANE_ID; pub MsgProofsRewardsAccount: RewardsAccountParams = RewardsAccountParams::new( TEST_LANE_ID, @@ -895,6 +985,14 @@ mod tests { bp_runtime::generate_static_str_provider!(TestExtension); + type TestMessagesExtensionProvider = RefundBridgedMessages< + TestRuntime, + RefundableMessagesLane<(), TestLaneId>, + ActualFeeRefund, + ConstU64<1>, + StrTestExtension, + >; + type TestMessagesExtension = RefundSignedExtensionAdapter; type TestGrandpaExtensionProvider = RefundBridgedGrandpaMessages< TestRuntime, (), @@ -906,7 +1004,7 @@ mod tests { type TestGrandpaExtension = RefundSignedExtensionAdapter; type TestExtensionProvider = RefundBridgedParachainMessages< TestRuntime, - DefaultRefundableParachainId<(), TestParachain>, + RefundableParachain<(), BridgedUnderlyingParachain>, RefundableMessagesLane<(), TestLaneId>, ActualFeeRefund, ConstU64<1>, @@ -930,7 +1028,7 @@ mod tests { TestPaymentProcedure::rewards_account(MsgDeliveryProofsRewardsAccount::get()) } - fn relayer_account_at_this_chain() -> ThisChainAccountId { + pub fn relayer_account_at_this_chain() -> ThisChainAccountId { 0 } @@ -938,7 +1036,7 @@ mod tests { 0 } - fn initialize_environment( + pub fn initialize_environment( best_relay_header_number: RelayBlockNumber, parachain_head_at_relay_header_number: RelayBlockNumber, best_message: MessageNonce, @@ -949,8 +1047,12 @@ mod tests { StoredAuthoritySet::try_new(authorities, TEST_GRANDPA_SET_ID).unwrap(), ); pallet_bridge_grandpa::BestFinalized::::put(best_relay_header); + pallet_bridge_grandpa::ImportedHeaders::::insert( + best_relay_header.hash(), + bp_test_utils::test_header::(0).build(), + ); - let para_id = ParaId(TestParachain::get()); + let para_id = ParaId(BridgedUnderlyingParachain::PARACHAIN_ID); let para_info = ParaInfo { best_head_hash: BestParaHeadHash { at_relay_block_number: parachain_head_at_relay_header_number, @@ -994,7 +1096,7 @@ mod tests { }) } - fn submit_relay_header_call_ex(relay_header_number: RelayBlockNumber) -> RuntimeCall { + pub fn submit_relay_header_call_ex(relay_header_number: RelayBlockNumber) -> RuntimeCall { let relay_header = BridgedChainHeader::new( relay_header_number, Default::default(), @@ -1008,6 +1110,7 @@ mod tests { finality_target: Box::new(relay_header), justification: relay_justification, current_set_id: TEST_GRANDPA_SET_ID, + is_free_execution_expected: false, }) } @@ -1017,10 +1120,24 @@ mod tests { RuntimeCall::BridgeParachains(ParachainsCall::submit_parachain_heads { at_relay_block: (parachain_head_at_relay_header_number, RelayBlockHash::default()), parachains: vec![( - ParaId(TestParachain::get()), + ParaId(BridgedUnderlyingParachain::PARACHAIN_ID), + [parachain_head_at_relay_header_number as u8; 32].into(), + )], + parachain_heads_proof: ParaHeadsProof { storage_proof: vec![] }, + }) + } + + pub fn submit_parachain_head_call_ex( + parachain_head_at_relay_header_number: RelayBlockNumber, + ) -> RuntimeCall { + RuntimeCall::BridgeParachains(ParachainsCall::submit_parachain_heads_ex { + at_relay_block: (parachain_head_at_relay_header_number, RelayBlockHash::default()), + parachains: vec![( + ParaId(BridgedUnderlyingParachain::PARACHAIN_ID), [parachain_head_at_relay_header_number as u8; 32].into(), )], parachain_heads_proof: ParaHeadsProof { storage_proof: vec![] }, + is_free_execution_expected: false, }) } @@ -1151,7 +1268,7 @@ mod tests { RuntimeCall::Utility(UtilityCall::batch_all { calls: vec![ submit_relay_header_call_ex(relay_header_number), - submit_parachain_head_call(parachain_head_at_relay_header_number), + submit_parachain_head_call_ex(parachain_head_at_relay_header_number), message_delivery_call(best_message), ], }) @@ -1179,7 +1296,7 @@ mod tests { RuntimeCall::Utility(UtilityCall::batch_all { calls: vec![ submit_relay_header_call_ex(relay_header_number), - submit_parachain_head_call(parachain_head_at_relay_header_number), + submit_parachain_head_call_ex(parachain_head_at_relay_header_number), message_confirmation_call(best_message), ], }) @@ -1194,11 +1311,14 @@ mod tests { current_set_id: None, extra_weight: Weight::zero(), extra_size: 0, + is_mandatory: false, + is_free_execution_expected: false, }, SubmitParachainHeadsInfo { - at_relay_block_number: 200, - para_id: ParaId(TestParachain::get()), + at_relay_block: HeaderId(200, [0u8; 32].into()), + para_id: ParaId(BridgedUnderlyingParachain::PARACHAIN_ID), para_head_hash: [200u8; 32].into(), + is_free_execution_expected: false, }, MessagesCallInfo::ReceiveMessagesProof(ReceiveMessagesProofInfo { base: BaseMessagesProofInfo { @@ -1231,11 +1351,14 @@ mod tests { current_set_id: None, extra_weight: Weight::zero(), extra_size: 0, + is_mandatory: false, + is_free_execution_expected: false, }, SubmitParachainHeadsInfo { - at_relay_block_number: 200, - para_id: ParaId(TestParachain::get()), + at_relay_block: HeaderId(200, [0u8; 32].into()), + para_id: ParaId(BridgedUnderlyingParachain::PARACHAIN_ID), para_head_hash: [200u8; 32].into(), + is_free_execution_expected: false, }, MessagesCallInfo::ReceiveMessagesDeliveryProof(ReceiveMessagesDeliveryProofInfo( BaseMessagesProofInfo { @@ -1264,6 +1387,8 @@ mod tests { current_set_id: None, extra_weight: Weight::zero(), extra_size: 0, + is_mandatory: false, + is_free_execution_expected: false, }, MessagesCallInfo::ReceiveMessagesProof(ReceiveMessagesProofInfo { base: BaseMessagesProofInfo { @@ -1296,6 +1421,8 @@ mod tests { current_set_id: None, extra_weight: Weight::zero(), extra_size: 0, + is_mandatory: false, + is_free_execution_expected: false, }, MessagesCallInfo::ReceiveMessagesDeliveryProof(ReceiveMessagesDeliveryProofInfo( BaseMessagesProofInfo { @@ -1320,9 +1447,10 @@ mod tests { relayer: relayer_account_at_this_chain(), call_info: CallInfo::ParachainFinalityAndMsgs( SubmitParachainHeadsInfo { - at_relay_block_number: 200, - para_id: ParaId(TestParachain::get()), + at_relay_block: HeaderId(200, [0u8; 32].into()), + para_id: ParaId(BridgedUnderlyingParachain::PARACHAIN_ID), para_head_hash: [200u8; 32].into(), + is_free_execution_expected: false, }, MessagesCallInfo::ReceiveMessagesProof(ReceiveMessagesProofInfo { base: BaseMessagesProofInfo { @@ -1344,9 +1472,10 @@ mod tests { relayer: relayer_account_at_this_chain(), call_info: CallInfo::ParachainFinalityAndMsgs( SubmitParachainHeadsInfo { - at_relay_block_number: 200, - para_id: ParaId(TestParachain::get()), + at_relay_block: HeaderId(200, [0u8; 32].into()), + para_id: ParaId(BridgedUnderlyingParachain::PARACHAIN_ID), para_head_hash: [200u8; 32].into(), + is_free_execution_expected: false, }, MessagesCallInfo::ReceiveMessagesDeliveryProof(ReceiveMessagesDeliveryProofInfo( BaseMessagesProofInfo { @@ -1421,8 +1550,14 @@ mod tests { extension.validate(&relayer_account_at_this_chain(), &call, &DispatchInfo::default(), 0) } - fn run_validate_ignore_priority(call: RuntimeCall) -> TransactionValidity { - run_validate(call).map(|mut tx| { + fn run_messages_validate(call: RuntimeCall) -> TransactionValidity { + let extension: TestMessagesExtension = + RefundSignedExtensionAdapter(RefundBridgedMessages(PhantomData)); + extension.validate(&relayer_account_at_this_chain(), &call, &DispatchInfo::default(), 0) + } + + fn ignore_priority(tx: TransactionValidity) -> TransactionValidity { + tx.map(|mut tx| { tx.priority = 0; tx }) @@ -1444,6 +1579,14 @@ mod tests { extension.pre_dispatch(&relayer_account_at_this_chain(), &call, &DispatchInfo::default(), 0) } + fn run_messages_pre_dispatch( + call: RuntimeCall, + ) -> Result>, TransactionValidityError> { + let extension: TestMessagesExtension = + RefundSignedExtensionAdapter(RefundBridgedMessages(PhantomData)); + extension.pre_dispatch(&relayer_account_at_this_chain(), &call, &DispatchInfo::default(), 0) + } + fn dispatch_info() -> DispatchInfo { DispatchInfo { weight: Weight::from_parts( @@ -1502,40 +1645,48 @@ mod tests { Balances::set_balance(&relayer_account_at_this_chain(), ExistentialDeposit::get()); // message delivery is failing - assert_eq!(run_validate(message_delivery_call(200)), Ok(Default::default()),); - assert_eq!( - run_validate(parachain_finality_and_delivery_batch_call(200, 200)), - Ok(Default::default()), - ); - assert_eq!( - run_validate(all_finality_and_delivery_batch_call(200, 200, 200)), - Ok(Default::default()), - ); + let fns = [run_validate, run_grandpa_validate, run_messages_validate]; + for f in fns { + assert_eq!(f(message_delivery_call(200)), Ok(Default::default()),); + assert_eq!( + f(parachain_finality_and_delivery_batch_call(200, 200)), + Ok(Default::default()), + ); + assert_eq!( + f(all_finality_and_delivery_batch_call(200, 200, 200)), + Ok(Default::default()), + ); + assert_eq!( + f(all_finality_and_delivery_batch_call_ex(200, 200, 200)), + Ok(Default::default()), + ); + } + + // message confirmation validation is passing assert_eq!( - run_validate(all_finality_and_delivery_batch_call_ex(200, 200, 200)), + ignore_priority(run_validate(message_confirmation_call(200))), Ok(Default::default()), ); - // message confirmation validation is passing assert_eq!( - run_validate_ignore_priority(message_confirmation_call(200)), + ignore_priority(run_messages_validate(message_confirmation_call(200))), Ok(Default::default()), ); assert_eq!( - run_validate_ignore_priority(parachain_finality_and_confirmation_batch_call( + ignore_priority(run_validate(parachain_finality_and_confirmation_batch_call( 200, 200 - )), + ))), Ok(Default::default()), ); assert_eq!( - run_validate_ignore_priority(all_finality_and_confirmation_batch_call( + ignore_priority(run_validate(all_finality_and_confirmation_batch_call( 200, 200, 200 - )), + ))), Ok(Default::default()), ); assert_eq!( - run_validate_ignore_priority(all_finality_and_confirmation_batch_call_ex( + ignore_priority(run_validate(all_finality_and_confirmation_batch_call_ex( 200, 200, 200 - )), + ))), Ok(Default::default()), ); }); @@ -1549,25 +1700,28 @@ mod tests { BridgeRelayers::register(RuntimeOrigin::signed(relayer_account_at_this_chain()), 1000) .unwrap(); - let priority_of_100_messages_delivery = - run_validate(message_delivery_call(200)).unwrap().priority; - let priority_of_200_messages_delivery = - run_validate(message_delivery_call(300)).unwrap().priority; - assert!( - priority_of_200_messages_delivery > priority_of_100_messages_delivery, - "Invalid priorities: {} for 200 messages vs {} for 100 messages", - priority_of_200_messages_delivery, - priority_of_100_messages_delivery, - ); + let fns = [run_validate, run_grandpa_validate, run_messages_validate]; + for f in fns { + let priority_of_100_messages_delivery = + f(message_delivery_call(200)).unwrap().priority; + let priority_of_200_messages_delivery = + f(message_delivery_call(300)).unwrap().priority; + assert!( + priority_of_200_messages_delivery > priority_of_100_messages_delivery, + "Invalid priorities: {} for 200 messages vs {} for 100 messages", + priority_of_200_messages_delivery, + priority_of_100_messages_delivery, + ); - let priority_of_100_messages_confirmation = - run_validate(message_confirmation_call(200)).unwrap().priority; - let priority_of_200_messages_confirmation = - run_validate(message_confirmation_call(300)).unwrap().priority; - assert_eq!( - priority_of_100_messages_confirmation, - priority_of_200_messages_confirmation - ); + let priority_of_100_messages_confirmation = + f(message_confirmation_call(200)).unwrap().priority; + let priority_of_200_messages_confirmation = + f(message_confirmation_call(300)).unwrap().priority; + assert_eq!( + priority_of_100_messages_confirmation, + priority_of_200_messages_confirmation + ); + } }); } @@ -1579,23 +1733,24 @@ mod tests { BridgeRelayers::register(RuntimeOrigin::signed(relayer_account_at_this_chain()), 1000) .unwrap(); - let priority_of_max_messages_delivery = run_validate(message_delivery_call( - 100 + MaxUnconfirmedMessagesAtInboundLane::get(), - )) - .unwrap() - .priority; - let priority_of_more_than_max_messages_delivery = run_validate(message_delivery_call( - 100 + MaxUnconfirmedMessagesAtInboundLane::get() + 1, - )) - .unwrap() - .priority; - - assert!( - priority_of_max_messages_delivery > priority_of_more_than_max_messages_delivery, - "Invalid priorities: {} for MAX messages vs {} for MAX+1 messages", - priority_of_max_messages_delivery, - priority_of_more_than_max_messages_delivery, - ); + let fns = [run_validate, run_grandpa_validate, run_messages_validate]; + for f in fns { + let priority_of_max_messages_delivery = + f(message_delivery_call(100 + MaxUnconfirmedMessagesAtInboundLane::get())) + .unwrap() + .priority; + let priority_of_more_than_max_messages_delivery = + f(message_delivery_call(100 + MaxUnconfirmedMessagesAtInboundLane::get() + 1)) + .unwrap() + .priority; + + assert!( + priority_of_max_messages_delivery > priority_of_more_than_max_messages_delivery, + "Invalid priorities: {} for MAX messages vs {} for MAX+1 messages", + priority_of_max_messages_delivery, + priority_of_more_than_max_messages_delivery, + ); + } }); } @@ -1605,45 +1760,54 @@ mod tests { initialize_environment(100, 100, 100); assert_eq!( - run_validate_ignore_priority(message_delivery_call(200)), + ignore_priority(run_validate(message_delivery_call(200))), + Ok(ValidTransaction::default()), + ); + assert_eq!( + ignore_priority(run_validate(message_confirmation_call(200))), + Ok(ValidTransaction::default()), + ); + + assert_eq!( + ignore_priority(run_messages_validate(message_delivery_call(200))), Ok(ValidTransaction::default()), ); assert_eq!( - run_validate_ignore_priority(message_confirmation_call(200)), + ignore_priority(run_messages_validate(message_confirmation_call(200))), Ok(ValidTransaction::default()), ); assert_eq!( - run_validate_ignore_priority(parachain_finality_and_delivery_batch_call(200, 200)), + ignore_priority(run_validate(parachain_finality_and_delivery_batch_call(200, 200))), Ok(ValidTransaction::default()), ); assert_eq!( - run_validate_ignore_priority(parachain_finality_and_confirmation_batch_call( + ignore_priority(run_validate(parachain_finality_and_confirmation_batch_call( 200, 200 - )), + ))), Ok(ValidTransaction::default()), ); assert_eq!( - run_validate_ignore_priority(all_finality_and_delivery_batch_call(200, 200, 200)), + ignore_priority(run_validate(all_finality_and_delivery_batch_call(200, 200, 200))), Ok(ValidTransaction::default()), ); assert_eq!( - run_validate_ignore_priority(all_finality_and_delivery_batch_call_ex( + ignore_priority(run_validate(all_finality_and_delivery_batch_call_ex( 200, 200, 200 - )), + ))), Ok(ValidTransaction::default()), ); assert_eq!( - run_validate_ignore_priority(all_finality_and_confirmation_batch_call( + ignore_priority(run_validate(all_finality_and_confirmation_batch_call( 200, 200, 200 - )), + ))), Ok(ValidTransaction::default()), ); assert_eq!( - run_validate_ignore_priority(all_finality_and_confirmation_batch_call_ex( + ignore_priority(run_validate(all_finality_and_confirmation_batch_call_ex( 200, 200, 200 - )), + ))), Ok(ValidTransaction::default()), ); }); @@ -1933,8 +2097,11 @@ mod tests { RuntimeCall::BridgeParachains(ParachainsCall::submit_parachain_heads { at_relay_block: (100, RelayBlockHash::default()), parachains: vec![ - (ParaId(TestParachain::get()), [1u8; 32].into()), - (ParaId(TestParachain::get() + 1), [1u8; 32].into()), + (ParaId(BridgedUnderlyingParachain::PARACHAIN_ID), [1u8; 32].into()), + ( + ParaId(BridgedUnderlyingParachain::PARACHAIN_ID + 1), + [1u8; 32].into(), + ), ], parachain_heads_proof: ParaHeadsProof { storage_proof: vec![] }, }), @@ -2318,6 +2485,148 @@ mod tests { }); } + #[test] + fn messages_ext_only_parses_standalone_transactions() { + run_test(|| { + initialize_environment(100, 100, 100); + + // relay + parachain + message delivery calls batch is ignored + assert_eq!( + TestMessagesExtensionProvider::parse_and_check_for_obsolete_call( + &all_finality_and_delivery_batch_call(200, 200, 200) + ), + Ok(None), + ); + assert_eq!( + TestMessagesExtensionProvider::parse_and_check_for_obsolete_call( + &all_finality_and_delivery_batch_call_ex(200, 200, 200) + ), + Ok(None), + ); + + // relay + parachain + message confirmation calls batch is ignored + assert_eq!( + TestMessagesExtensionProvider::parse_and_check_for_obsolete_call( + &all_finality_and_confirmation_batch_call(200, 200, 200) + ), + Ok(None), + ); + assert_eq!( + TestMessagesExtensionProvider::parse_and_check_for_obsolete_call( + &all_finality_and_confirmation_batch_call_ex(200, 200, 200) + ), + Ok(None), + ); + + // parachain + message delivery call batch is ignored + assert_eq!( + TestMessagesExtensionProvider::parse_and_check_for_obsolete_call( + ¶chain_finality_and_delivery_batch_call(200, 200) + ), + Ok(None), + ); + + // parachain + message confirmation call batch is ignored + assert_eq!( + TestMessagesExtensionProvider::parse_and_check_for_obsolete_call( + ¶chain_finality_and_confirmation_batch_call(200, 200) + ), + Ok(None), + ); + + // relay + message delivery call batch is ignored + assert_eq!( + TestMessagesExtensionProvider::parse_and_check_for_obsolete_call( + &relay_finality_and_delivery_batch_call(200, 200) + ), + Ok(None), + ); + assert_eq!( + TestMessagesExtensionProvider::parse_and_check_for_obsolete_call( + &relay_finality_and_delivery_batch_call_ex(200, 200) + ), + Ok(None), + ); + + // relay + message confirmation call batch is ignored + assert_eq!( + TestMessagesExtensionProvider::parse_and_check_for_obsolete_call( + &relay_finality_and_confirmation_batch_call(200, 200) + ), + Ok(None), + ); + assert_eq!( + TestMessagesExtensionProvider::parse_and_check_for_obsolete_call( + &relay_finality_and_confirmation_batch_call_ex(200, 200) + ), + Ok(None), + ); + + // message delivery call batch is accepted + assert_eq!( + TestMessagesExtensionProvider::parse_and_check_for_obsolete_call( + &message_delivery_call(200) + ), + Ok(Some(delivery_pre_dispatch_data().call_info)), + ); + + // message confirmation call batch is accepted + assert_eq!( + TestMessagesExtensionProvider::parse_and_check_for_obsolete_call( + &message_confirmation_call(200) + ), + Ok(Some(confirmation_pre_dispatch_data().call_info)), + ); + }); + } + + #[test] + fn messages_ext_rejects_calls_with_obsolete_messages() { + run_test(|| { + initialize_environment(100, 100, 100); + + assert_eq!( + run_messages_pre_dispatch(message_delivery_call(100)), + Err(TransactionValidityError::Invalid(InvalidTransaction::Stale)), + ); + assert_eq!( + run_messages_pre_dispatch(message_confirmation_call(100)), + Err(TransactionValidityError::Invalid(InvalidTransaction::Stale)), + ); + + assert_eq!( + run_messages_validate(message_delivery_call(100)), + Err(TransactionValidityError::Invalid(InvalidTransaction::Stale)), + ); + assert_eq!( + run_messages_validate(message_confirmation_call(100)), + Err(TransactionValidityError::Invalid(InvalidTransaction::Stale)), + ); + }); + } + + #[test] + fn messages_ext_accepts_calls_with_new_messages() { + run_test(|| { + initialize_environment(100, 100, 100); + + assert_eq!( + run_messages_pre_dispatch(message_delivery_call(200)), + Ok(Some(delivery_pre_dispatch_data())), + ); + assert_eq!( + run_messages_pre_dispatch(message_confirmation_call(200)), + Ok(Some(confirmation_pre_dispatch_data())), + ); + + assert_eq!(run_messages_validate(message_delivery_call(200)), Ok(Default::default()),); + assert_eq!( + run_messages_validate(message_confirmation_call(200)), + Ok(Default::default()), + ); + }); + } + #[test] fn grandpa_ext_only_parses_valid_batches() { run_test(|| { diff --git a/bridges/bin/runtime-common/src/messages.rs b/bridges/bin/runtime-common/src/messages.rs index 4aca53f3b98361b1a5f7d5dc89dc72ec0bc1323c..0fe9935dbdb6dfc776977ff8cfbad87d3eee9f6e 100644 --- a/bridges/bin/runtime-common/src/messages.rs +++ b/bridges/bin/runtime-common/src/messages.rs @@ -35,7 +35,7 @@ use frame_support::{traits::Get, weights::Weight}; use hash_db::Hasher; use scale_info::TypeInfo; use sp_runtime::RuntimeDebug; -use sp_std::{convert::TryFrom, marker::PhantomData, vec::Vec}; +use sp_std::{marker::PhantomData, vec::Vec}; /// Bidirectional message bridge. pub trait MessageBridge { diff --git a/bridges/bin/runtime-common/src/mock.rs b/bridges/bin/runtime-common/src/mock.rs index ad71cd0d456d827d3757433d214f7ea794406fca..e323f1edfc71da8c84fe8cabb977da85ce4d303e 100644 --- a/bridges/bin/runtime-common/src/mock.rs +++ b/bridges/bin/runtime-common/src/mock.rs @@ -183,7 +183,8 @@ impl pallet_transaction_payment::Config for TestRuntime { impl pallet_bridge_grandpa::Config for TestRuntime { type RuntimeEvent = RuntimeEvent; type BridgedChain = BridgedUnderlyingChain; - type MaxFreeMandatoryHeadersPerBlock = ConstU32<4>; + type MaxFreeHeadersPerBlock = ConstU32<4>; + type FreeHeadersInterval = ConstU32<1_024>; type HeadersToKeep = ConstU32<8>; type WeightInfo = pallet_bridge_grandpa::weights::BridgeWeight; } @@ -406,6 +407,7 @@ impl Chain for BridgedUnderlyingParachain { impl Parachain for BridgedUnderlyingParachain { const PARACHAIN_ID: u32 = 42; + const MAX_HEADER_SIZE: u32 = 1_024; } /// The other, bridged chain, used in tests. diff --git a/bridges/chains/chain-asset-hub-rococo/Cargo.toml b/bridges/chains/chain-asset-hub-rococo/Cargo.toml index 9a6419a5b4055be348f4f8813e3c1301f14f7142..d9afe2c8bf76713104beead1ad4c36dc08dae1ed 100644 --- a/bridges/chains/chain-asset-hub-rococo/Cargo.toml +++ b/bridges/chains/chain-asset-hub-rococo/Cargo.toml @@ -11,7 +11,7 @@ repository.workspace = true workspace = true [dependencies] -codec = { package = "parity-scale-codec", version = "3.6.1", default-features = false } +codec = { package = "parity-scale-codec", version = "3.6.12", default-features = false } scale-info = { version = "2.11.1", default-features = false, features = ["derive"] } # Substrate Dependencies diff --git a/bridges/chains/chain-asset-hub-westend/Cargo.toml b/bridges/chains/chain-asset-hub-westend/Cargo.toml index 1c08ee28e417cb50ce9ef9ded5f17163e1bb30d4..4b3ed052f1382d0c7f076ad5152c861f60d8bef1 100644 --- a/bridges/chains/chain-asset-hub-westend/Cargo.toml +++ b/bridges/chains/chain-asset-hub-westend/Cargo.toml @@ -11,7 +11,7 @@ repository.workspace = true workspace = true [dependencies] -codec = { package = "parity-scale-codec", version = "3.6.1", default-features = false } +codec = { package = "parity-scale-codec", version = "3.6.12", default-features = false } scale-info = { version = "2.11.1", default-features = false, features = ["derive"] } # Substrate Dependencies diff --git a/bridges/chains/chain-bridge-hub-cumulus/src/lib.rs b/bridges/chains/chain-bridge-hub-cumulus/src/lib.rs index c49aa4b856397d28746d017fd8333ae3ad10655e..a5c90ceba111e0c8a095f7e96e6d4a8dba92d183 100644 --- a/bridges/chains/chain-bridge-hub-cumulus/src/lib.rs +++ b/bridges/chains/chain-bridge-hub-cumulus/src/lib.rs @@ -39,6 +39,9 @@ use frame_support::{ use frame_system::limits; use sp_std::time::Duration; +/// Maximal bridge hub header size. +pub const MAX_BRIDGE_HUB_HEADER_SIZE: u32 = 4_096; + /// Average block interval in Cumulus-based parachains. /// /// Corresponds to the `MILLISECS_PER_BLOCK` from `parachains_common` crate. diff --git a/bridges/chains/chain-bridge-hub-kusama/src/lib.rs b/bridges/chains/chain-bridge-hub-kusama/src/lib.rs index 576e3dbee80d0babbdb7c0bbdfc420c5a636b68b..ef3ef4ab7b7a9bc111218e3c53091ac232f34721 100644 --- a/bridges/chains/chain-bridge-hub-kusama/src/lib.rs +++ b/bridges/chains/chain-bridge-hub-kusama/src/lib.rs @@ -62,6 +62,7 @@ impl Chain for BridgeHubKusama { impl Parachain for BridgeHubKusama { const PARACHAIN_ID: u32 = BRIDGE_HUB_KUSAMA_PARACHAIN_ID; + const MAX_HEADER_SIZE: u32 = MAX_BRIDGE_HUB_HEADER_SIZE; } impl ChainWithMessages for BridgeHubKusama { diff --git a/bridges/chains/chain-bridge-hub-polkadot/src/lib.rs b/bridges/chains/chain-bridge-hub-polkadot/src/lib.rs index 6db389c92994d74fb0d8176509cd81d64b806df2..9db71af928e5df01170cf4ab8bf5f20cd72f7610 100644 --- a/bridges/chains/chain-bridge-hub-polkadot/src/lib.rs +++ b/bridges/chains/chain-bridge-hub-polkadot/src/lib.rs @@ -59,6 +59,7 @@ impl Chain for BridgeHubPolkadot { impl Parachain for BridgeHubPolkadot { const PARACHAIN_ID: u32 = BRIDGE_HUB_POLKADOT_PARACHAIN_ID; + const MAX_HEADER_SIZE: u32 = MAX_BRIDGE_HUB_HEADER_SIZE; } impl ChainWithMessages for BridgeHubPolkadot { diff --git a/bridges/chains/chain-bridge-hub-rococo/src/lib.rs b/bridges/chains/chain-bridge-hub-rococo/src/lib.rs index abce872d7ba35cf24b013aa26b4b1f1d796b5785..d7097f01c5316a58851f400a86b98eda3d7e8bcc 100644 --- a/bridges/chains/chain-bridge-hub-rococo/src/lib.rs +++ b/bridges/chains/chain-bridge-hub-rococo/src/lib.rs @@ -59,6 +59,7 @@ impl Chain for BridgeHubRococo { impl Parachain for BridgeHubRococo { const PARACHAIN_ID: u32 = BRIDGE_HUB_ROCOCO_PARACHAIN_ID; + const MAX_HEADER_SIZE: u32 = MAX_BRIDGE_HUB_HEADER_SIZE; } impl ChainWithMessages for BridgeHubRococo { @@ -103,9 +104,9 @@ frame_support::parameter_types! { /// Transaction fee that is paid at the Rococo BridgeHub for delivering single inbound message. /// (initially was calculated by test `BridgeHubRococo::can_calculate_fee_for_complex_message_delivery_transaction` + `33%`) - pub const BridgeHubRococoBaseDeliveryFeeInRocs: u128 = 5_651_581_649; + pub const BridgeHubRococoBaseDeliveryFeeInRocs: u128 = 314_037_860; /// 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_901_781; + pub const BridgeHubRococoBaseConfirmationFeeInRocs: u128 = 57_414_813; } diff --git a/bridges/chains/chain-bridge-hub-westend/src/lib.rs b/bridges/chains/chain-bridge-hub-westend/src/lib.rs index 4af895cc6d328bdb350fa95b0e0a74f0cc731b04..800f290d7bfa41cec4139e80a7dc9ea8962a6da5 100644 --- a/bridges/chains/chain-bridge-hub-westend/src/lib.rs +++ b/bridges/chains/chain-bridge-hub-westend/src/lib.rs @@ -58,6 +58,7 @@ impl Chain for BridgeHubWestend { impl Parachain for BridgeHubWestend { const PARACHAIN_ID: u32 = BRIDGE_HUB_WESTEND_PARACHAIN_ID; + const MAX_HEADER_SIZE: u32 = MAX_BRIDGE_HUB_HEADER_SIZE; } impl ChainWithMessages for BridgeHubWestend { @@ -93,10 +94,10 @@ frame_support::parameter_types! { pub const BridgeHubWestendBaseXcmFeeInWnds: u128 = 17_756_830_000; /// Transaction fee that is paid at the Westend BridgeHub for delivering single inbound message. - /// (initially was calculated by test `BridgeHubWestend::can_calculate_fee_for_complex_message_delivery_transaction` + `33%`) - pub const BridgeHubWestendBaseDeliveryFeeInWnds: u128 = 1_695_489_961_344; + /// (initially was calculated by test `BridgeHubWestend::can_calculate_fee_for_standalone_message_delivery_transaction` + `33%`) + pub const BridgeHubWestendBaseDeliveryFeeInWnds: u128 = 94_211_536_452; /// Transaction fee that is paid at the Westend BridgeHub for delivering single outbound message confirmation. - /// (initially was calculated by test `BridgeHubWestend::can_calculate_fee_for_complex_message_confirmation_transaction` + `33%`) - pub const BridgeHubWestendBaseConfirmationFeeInWnds: u128 = 1_618_309_961_344; + /// (initially was calculated by test `BridgeHubWestend::can_calculate_fee_for_standalone_message_confirmation_transaction` + `33%`) + pub const BridgeHubWestendBaseConfirmationFeeInWnds: u128 = 17_224_486_452; } diff --git a/bridges/chains/chain-kusama/src/lib.rs b/bridges/chains/chain-kusama/src/lib.rs index a81004afe8127b556211d0207d2bc1f9ecc02955..fd7172c5869d468ff534e54f9ef6278cf86a88ed 100644 --- a/bridges/chains/chain-kusama/src/lib.rs +++ b/bridges/chains/chain-kusama/src/lib.rs @@ -67,6 +67,8 @@ pub const PARAS_PALLET_NAME: &str = "Paras"; /// Name of the With-Kusama GRANDPA pallet instance that is deployed at bridged chains. pub const WITH_KUSAMA_GRANDPA_PALLET_NAME: &str = "BridgeKusamaGrandpa"; +/// Name of the With-Kusama parachains pallet instance that is deployed at bridged chains. +pub const WITH_KUSAMA_BRIDGE_PARACHAINS_PALLET_NAME: &str = "BridgeKusamaParachains"; /// Maximal size of encoded `bp_parachains::ParaStoredHeaderData` structure among all Polkadot /// parachains. diff --git a/bridges/chains/chain-polkadot-bulletin/Cargo.toml b/bridges/chains/chain-polkadot-bulletin/Cargo.toml index 2db16a00e92492e3a167458343a88a24c2186748..700247b7055a891bec2d4a40bfd126720a0d952c 100644 --- a/bridges/chains/chain-polkadot-bulletin/Cargo.toml +++ b/bridges/chains/chain-polkadot-bulletin/Cargo.toml @@ -11,7 +11,7 @@ repository.workspace = true workspace = true [dependencies] -codec = { package = "parity-scale-codec", version = "3.6.1", default-features = false, features = ["derive"] } +codec = { package = "parity-scale-codec", version = "3.6.12", default-features = false, features = ["derive"] } scale-info = { version = "2.11.1", default-features = false, features = ["derive"] } # Bridge Dependencies diff --git a/bridges/chains/chain-polkadot/src/lib.rs b/bridges/chains/chain-polkadot/src/lib.rs index 00d35783a9b61844bab7701fdb60711125447ca3..a8cac0467d574e9355a8fe9ba2e7c2378019349d 100644 --- a/bridges/chains/chain-polkadot/src/lib.rs +++ b/bridges/chains/chain-polkadot/src/lib.rs @@ -69,6 +69,8 @@ pub const PARAS_PALLET_NAME: &str = "Paras"; /// Name of the With-Polkadot GRANDPA pallet instance that is deployed at bridged chains. pub const WITH_POLKADOT_GRANDPA_PALLET_NAME: &str = "BridgePolkadotGrandpa"; +/// Name of the With-Polkadot parachains pallet instance that is deployed at bridged chains. +pub const WITH_POLKADOT_BRIDGE_PARACHAINS_PALLET_NAME: &str = "BridgePolkadotParachains"; /// Maximal size of encoded `bp_parachains::ParaStoredHeaderData` structure among all Polkadot /// parachains. diff --git a/bridges/chains/chain-rococo/src/lib.rs b/bridges/chains/chain-rococo/src/lib.rs index 2385dd2cbb250181ce5f46aef9f1e76f8fd010d2..b290fe71c829d08130556a2b061c0d63f0787d4c 100644 --- a/bridges/chains/chain-rococo/src/lib.rs +++ b/bridges/chains/chain-rococo/src/lib.rs @@ -67,6 +67,8 @@ pub const PARAS_PALLET_NAME: &str = "Paras"; /// Name of the With-Rococo GRANDPA pallet instance that is deployed at bridged chains. pub const WITH_ROCOCO_GRANDPA_PALLET_NAME: &str = "BridgeRococoGrandpa"; +/// Name of the With-Rococo parachains pallet instance that is deployed at bridged chains. +pub const WITH_ROCOCO_BRIDGE_PARACHAINS_PALLET_NAME: &str = "BridgeRococoParachains"; /// Maximal size of encoded `bp_parachains::ParaStoredHeaderData` structure among all Rococo /// parachains. diff --git a/bridges/chains/chain-westend/src/lib.rs b/bridges/chains/chain-westend/src/lib.rs index b344b7f4bf93392c08502446513a9ae39296b512..ef451f7de0a9640bc1a278e1c712bbb099193ceb 100644 --- a/bridges/chains/chain-westend/src/lib.rs +++ b/bridges/chains/chain-westend/src/lib.rs @@ -67,6 +67,8 @@ pub const PARAS_PALLET_NAME: &str = "Paras"; /// Name of the With-Westend GRANDPA pallet instance that is deployed at bridged chains. pub const WITH_WESTEND_GRANDPA_PALLET_NAME: &str = "BridgeWestendGrandpa"; +/// Name of the With-Westend parachains pallet instance that is deployed at bridged chains. +pub const WITH_WESTEND_BRIDGE_PARACHAINS_PALLET_NAME: &str = "BridgeWestendParachains"; /// Maximal size of encoded `bp_parachains::ParaStoredHeaderData` structure among all Westend /// parachains. diff --git a/bridges/modules/beefy/Cargo.toml b/bridges/modules/beefy/Cargo.toml index 438f32fb146042f2704deb3092381a2b5cc68394..e36bbb615f23a20d4ef4a4f4ea8418e752d5b01f 100644 --- a/bridges/modules/beefy/Cargo.toml +++ b/bridges/modules/beefy/Cargo.toml @@ -12,7 +12,7 @@ publish = false workspace = true [dependencies] -codec = { package = "parity-scale-codec", version = "3.6.1", default-features = false } +codec = { package = "parity-scale-codec", version = "3.6.12", default-features = false } log = { workspace = true } scale-info = { version = "2.11.1", default-features = false, features = ["derive"] } serde = { optional = true, workspace = true } diff --git a/bridges/modules/grandpa/Cargo.toml b/bridges/modules/grandpa/Cargo.toml index 0db1827211a05f715cd1aed0db93da0f52c9d67c..0ca6b67503511976ea9122f64e3c2e515e971177 100644 --- a/bridges/modules/grandpa/Cargo.toml +++ b/bridges/modules/grandpa/Cargo.toml @@ -13,7 +13,7 @@ workspace = true # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] -codec = { package = "parity-scale-codec", version = "3.6.1", default-features = false } +codec = { package = "parity-scale-codec", version = "3.6.12", default-features = false } finality-grandpa = { version = "0.16.2", default-features = false } log = { workspace = true } scale-info = { version = "2.11.1", default-features = false, features = ["derive"] } diff --git a/bridges/modules/grandpa/src/call_ext.rs b/bridges/modules/grandpa/src/call_ext.rs index 4a7ebb3cc8d42d7cb9d97d5c6990bb33658416bd..98fbeaa30bbac4c6bade6dc4b7d2f97d53940c6b 100644 --- a/bridges/modules/grandpa/src/call_ext.rs +++ b/bridges/modules/grandpa/src/call_ext.rs @@ -15,20 +15,24 @@ // along with Parity Bridges Common. If not, see . use crate::{ - weights::WeightInfo, BridgedBlockNumber, BridgedHeader, Config, CurrentAuthoritySet, Error, - Pallet, + weights::WeightInfo, BestFinalized, BridgedBlockNumber, BridgedHeader, Config, + CurrentAuthoritySet, Error, FreeHeadersRemaining, Pallet, }; use bp_header_chain::{ justification::GrandpaJustification, max_expected_submit_finality_proof_arguments_size, ChainWithGrandpa, GrandpaConsensusLogReader, }; -use bp_runtime::{BlockNumberOf, OwnedBridgeModule}; +use bp_runtime::{BlockNumberOf, Chain, OwnedBridgeModule}; use codec::Encode; -use frame_support::{dispatch::CallableCallFor, traits::IsSubType, weights::Weight}; +use frame_support::{ + dispatch::CallableCallFor, + traits::{Get, IsSubType}, + weights::Weight, +}; use sp_consensus_grandpa::SetId; use sp_runtime::{ - traits::{Header, Zero}, - transaction_validity::{InvalidTransaction, TransactionValidity, ValidTransaction}, + traits::{CheckedSub, Header, Zero}, + transaction_validity::{InvalidTransaction, TransactionValidityError}, RuntimeDebug, SaturatedConversion, }; @@ -40,6 +44,11 @@ pub struct SubmitFinalityProofInfo { /// An identifier of the validators set that has signed the submitted justification. /// It might be `None` if deprecated version of the `submit_finality_proof` is used. pub current_set_id: Option, + /// If `true`, then the call proves new **mandatory** header. + pub is_mandatory: bool, + /// If `true`, then the call must be free (assuming that everything else is valid) to + /// be treated as valid. + pub is_free_execution_expected: bool, /// Extra weight that we assume is included in the call. /// /// We have some assumptions about headers and justifications of the bridged chain. @@ -54,6 +63,16 @@ pub struct SubmitFinalityProofInfo { pub extra_size: u32, } +/// Verified `SubmitFinalityProofInfo`. +#[derive(Copy, Clone, PartialEq, RuntimeDebug)] +pub struct VerifiedSubmitFinalityProofInfo { + /// Base call information. + pub base: SubmitFinalityProofInfo, + /// A difference between bundled bridged header and best bridged header known to us + /// before the call. + pub improved_by: N, +} + impl SubmitFinalityProofInfo { /// Returns `true` if call size/weight is below our estimations for regular calls. pub fn fits_limits(&self) -> bool { @@ -67,14 +86,91 @@ pub struct SubmitFinalityProofHelper, I: 'static> { } impl, I: 'static> SubmitFinalityProofHelper { + /// Returns `true` if we may fit more free headers into the current block. If `false` is + /// returned, the call will be paid even if `is_free_execution_expected` has been set + /// to `true`. + pub fn has_free_header_slots() -> bool { + // `unwrap_or(u32::MAX)` means that if `FreeHeadersRemaining` is `None`, we may accept + // this header for free. That is a small cheat - it is `None` if executed outside of + // transaction (e.g. during block initialization). Normal relayer would never submit + // such calls, but if he did, that is not our problem. During normal transactions, + // the `FreeHeadersRemaining` is always `Some(_)`. + let free_headers_remaining = FreeHeadersRemaining::::get().unwrap_or(u32::MAX); + free_headers_remaining > 0 + } + + /// Check that the: (1) GRANDPA head provided by the `SubmitFinalityProof` is better than the + /// best one we know (2) if `current_set_id` matches the current authority set id, if specified + /// and (3) whether transaction MAY be free for the submitter if `is_free_execution_expected` + /// is `true`. + /// + /// Returns number of headers between the current best finalized header, known to the pallet + /// and the bundled header. + pub fn check_obsolete_from_extension( + call_info: &SubmitFinalityProofInfo>, + ) -> Result, Error> { + // do basic checks first + let improved_by = Self::check_obsolete(call_info.block_number, call_info.current_set_id)?; + + // if submitter has NOT specified that it wants free execution, then we are done + if !call_info.is_free_execution_expected { + return Ok(improved_by); + } + + // else - if we can not accept more free headers, "reject" the transaction + if !Self::has_free_header_slots() { + log::trace!( + target: crate::LOG_TARGET, + "Cannot accept free {:?} header {:?}. No more free slots remaining", + T::BridgedChain::ID, + call_info.block_number, + ); + + return Err(Error::::FreeHeadersLimitExceded); + } + + // ensure that the `improved_by` is larger than the configured free interval + if !call_info.is_mandatory { + if let Some(free_headers_interval) = T::FreeHeadersInterval::get() { + if improved_by < free_headers_interval.into() { + log::trace!( + target: crate::LOG_TARGET, + "Cannot accept free {:?} header {:?}. Too small difference \ + between submitted headers: {:?} vs {}", + T::BridgedChain::ID, + call_info.block_number, + improved_by, + free_headers_interval, + ); + + return Err(Error::::BelowFreeHeaderInterval); + } + } + } + + // let's also check whether the header submission fits the hardcoded limits. A normal + // relayer would check that before submitting a transaction (since limits are constants + // and do not depend on a volatile runtime state), but the ckeck itself is cheap, so + // let's do it here too + if !call_info.fits_limits() { + return Err(Error::::HeaderOverflowLimits); + } + + Ok(improved_by) + } + /// Check that the GRANDPA head provided by the `SubmitFinalityProof` is better than the best /// one we know. Additionally, checks if `current_set_id` matches the current authority set - /// id, if specified. + /// id, if specified. This method is called by the call code and the transaction extension, + /// so it does not check the free execution. + /// + /// Returns number of headers between the current best finalized header, known to the pallet + /// and the bundled header. pub fn check_obsolete( finality_target: BlockNumberOf, current_set_id: Option, - ) -> Result<(), Error> { - let best_finalized = crate::BestFinalized::::get().ok_or_else(|| { + ) -> Result, Error> { + let best_finalized = BestFinalized::::get().ok_or_else(|| { log::trace!( target: crate::LOG_TARGET, "Cannot finalize header {:?} because pallet is not yet initialized", @@ -83,16 +179,19 @@ impl, I: 'static> SubmitFinalityProofHelper { >::NotInitialized })?; - if best_finalized.number() >= finality_target { - log::trace!( - target: crate::LOG_TARGET, - "Cannot finalize obsolete header: bundled {:?}, best {:?}", - finality_target, - best_finalized, - ); + let improved_by = match finality_target.checked_sub(&best_finalized.number()) { + Some(improved_by) if improved_by > Zero::zero() => improved_by, + _ => { + log::trace!( + target: crate::LOG_TARGET, + "Cannot finalize obsolete header: bundled {:?}, best {:?}", + finality_target, + best_finalized, + ); - return Err(Error::::OldHeader) - } + return Err(Error::::OldHeader) + }, + }; if let Some(current_set_id) = current_set_id { let actual_set_id = >::get().set_id; @@ -108,12 +207,12 @@ impl, I: 'static> SubmitFinalityProofHelper { } } - Ok(()) + Ok(improved_by) } /// Check if the `SubmitFinalityProof` was successfully executed. pub fn was_successful(finality_target: BlockNumberOf) -> bool { - match crate::BestFinalized::::get() { + match BestFinalized::::get() { Some(best_finalized) => best_finalized.number() == finality_target, None => false, } @@ -135,17 +234,20 @@ pub trait CallSubType, I: 'static>: finality_target, justification, None, + false, )) } else if let Some(crate::Call::::submit_finality_proof_ex { finality_target, justification, current_set_id, + is_free_execution_expected, }) = self.is_sub_type() { return Some(submit_finality_proof_info_from_args::( finality_target, justification, Some(*current_set_id), + *is_free_execution_expected, )) } @@ -155,26 +257,36 @@ pub trait CallSubType, I: 'static>: /// Validate Grandpa headers in order to avoid "mining" transactions that provide outdated /// bridged chain headers. Without this validation, even honest relayers may lose their funds /// if there are multiple relays running and submitting the same information. - fn check_obsolete_submit_finality_proof(&self) -> TransactionValidity + /// + /// Returns `Ok(None)` if the call is not the `submit_finality_proof` call of our pallet. + /// Returns `Ok(Some(_))` if the call is the `submit_finality_proof` call of our pallet and + /// we believe the call brings header that improves the pallet state. + /// Returns `Err(_)` if the call is the `submit_finality_proof` call of our pallet and we + /// believe that the call will fail. + fn check_obsolete_submit_finality_proof( + &self, + ) -> Result< + Option>>, + TransactionValidityError, + > where Self: Sized, { - let finality_target = match self.submit_finality_proof_info() { + let call_info = match self.submit_finality_proof_info() { Some(finality_proof) => finality_proof, - _ => return Ok(ValidTransaction::default()), + _ => return Ok(None), }; if Pallet::::ensure_not_halted().is_err() { - return InvalidTransaction::Call.into() + return Err(InvalidTransaction::Call.into()) } - match SubmitFinalityProofHelper::::check_obsolete( - finality_target.block_number, - finality_target.current_set_id, - ) { - Ok(_) => Ok(ValidTransaction::default()), - Err(Error::::OldHeader) => InvalidTransaction::Stale.into(), - Err(_) => InvalidTransaction::Call.into(), + let result = SubmitFinalityProofHelper::::check_obsolete_from_extension(&call_info); + match result { + Ok(improved_by) => + Ok(Some(VerifiedSubmitFinalityProofInfo { base: call_info, improved_by })), + Err(Error::::OldHeader) => Err(InvalidTransaction::Stale.into()), + Err(_) => Err(InvalidTransaction::Call.into()), } } } @@ -189,6 +301,7 @@ pub(crate) fn submit_finality_proof_info_from_args, I: 'static>( finality_target: &BridgedHeader, justification: &GrandpaJustification>, current_set_id: Option, + is_free_execution_expected: bool, ) -> SubmitFinalityProofInfo> { let block_number = *finality_target.number(); @@ -230,16 +343,26 @@ pub(crate) fn submit_finality_proof_info_from_args, I: 'static>( ); let extra_size = actual_call_size.saturating_sub(max_expected_call_size); - SubmitFinalityProofInfo { block_number, current_set_id, extra_weight, extra_size } + SubmitFinalityProofInfo { + block_number, + current_set_id, + is_mandatory: is_mandatory_finality_target, + is_free_execution_expected, + extra_weight, + extra_size, + } } #[cfg(test)] mod tests { use crate::{ call_ext::CallSubType, - mock::{run_test, test_header, RuntimeCall, TestBridgedChain, TestNumber, TestRuntime}, - BestFinalized, Config, CurrentAuthoritySet, PalletOperatingMode, StoredAuthoritySet, - SubmitFinalityProofInfo, WeightInfo, + mock::{ + run_test, test_header, FreeHeadersInterval, RuntimeCall, TestBridgedChain, TestNumber, + TestRuntime, + }, + BestFinalized, Config, CurrentAuthoritySet, FreeHeadersRemaining, PalletOperatingMode, + StoredAuthoritySet, SubmitFinalityProofInfo, WeightInfo, }; use bp_header_chain::ChainWithGrandpa; use bp_runtime::{BasicOperatingMode, HeaderId}; @@ -247,6 +370,7 @@ mod tests { make_default_justification, make_justification_for_header, JustificationGeneratorParams, TEST_GRANDPA_SET_ID, }; + use codec::Encode; use frame_support::weights::Weight; use sp_runtime::{testing::DigestItem, traits::Header as _, SaturatedConversion}; @@ -256,6 +380,7 @@ mod tests { justification: make_default_justification(&test_header(num)), // not initialized => zero current_set_id: 0, + is_free_execution_expected: false, }; RuntimeCall::check_obsolete_submit_finality_proof(&RuntimeCall::Grandpa( bridge_grandpa_call, @@ -311,6 +436,179 @@ mod tests { }); } + #[test] + fn extension_rejects_new_header_if_free_execution_is_requested_and_free_submissions_are_not_accepted( + ) { + run_test(|| { + let bridge_grandpa_call = crate::Call::::submit_finality_proof_ex { + finality_target: Box::new(test_header(10 + FreeHeadersInterval::get() as u64)), + justification: make_default_justification(&test_header( + 10 + FreeHeadersInterval::get() as u64, + )), + current_set_id: 0, + is_free_execution_expected: true, + }; + sync_to_header_10(); + + // when we can accept free headers => Ok + FreeHeadersRemaining::::put(2); + assert!(RuntimeCall::check_obsolete_submit_finality_proof(&RuntimeCall::Grandpa( + bridge_grandpa_call.clone(), + ),) + .is_ok()); + + // when we can NOT accept free headers => Err + FreeHeadersRemaining::::put(0); + assert!(RuntimeCall::check_obsolete_submit_finality_proof(&RuntimeCall::Grandpa( + bridge_grandpa_call.clone(), + ),) + .is_err()); + + // when called outside of transaction => Ok + FreeHeadersRemaining::::kill(); + assert!(RuntimeCall::check_obsolete_submit_finality_proof(&RuntimeCall::Grandpa( + bridge_grandpa_call, + ),) + .is_ok()); + }) + } + + #[test] + fn extension_rejects_new_header_if_it_overflow_size_limits() { + run_test(|| { + let mut large_finality_target = test_header(10 + FreeHeadersInterval::get() as u64); + large_finality_target + .digest_mut() + .push(DigestItem::Other(vec![42u8; 1024 * 1024])); + let justification_params = JustificationGeneratorParams { + header: large_finality_target.clone(), + ..Default::default() + }; + let large_justification = make_justification_for_header(justification_params); + + let bridge_grandpa_call = crate::Call::::submit_finality_proof_ex { + finality_target: Box::new(large_finality_target), + justification: large_justification, + current_set_id: 0, + is_free_execution_expected: true, + }; + sync_to_header_10(); + + // if overflow size limits => Err + FreeHeadersRemaining::::put(2); + assert!(RuntimeCall::check_obsolete_submit_finality_proof(&RuntimeCall::Grandpa( + bridge_grandpa_call.clone(), + ),) + .is_err()); + }) + } + + #[test] + fn extension_rejects_new_header_if_it_overflow_weight_limits() { + run_test(|| { + let finality_target = test_header(10 + FreeHeadersInterval::get() as u64); + let justification_params = JustificationGeneratorParams { + header: finality_target.clone(), + ancestors: TestBridgedChain::REASONABLE_HEADERS_IN_JUSTIFICATION_ANCESTRY, + ..Default::default() + }; + let justification = make_justification_for_header(justification_params); + + let bridge_grandpa_call = crate::Call::::submit_finality_proof_ex { + finality_target: Box::new(finality_target), + justification, + current_set_id: 0, + is_free_execution_expected: true, + }; + sync_to_header_10(); + + // if overflow weight limits => Err + FreeHeadersRemaining::::put(2); + assert!(RuntimeCall::check_obsolete_submit_finality_proof(&RuntimeCall::Grandpa( + bridge_grandpa_call.clone(), + ),) + .is_err()); + }) + } + + #[test] + fn extension_rejects_new_header_if_free_execution_is_requested_and_improved_by_is_below_expected( + ) { + run_test(|| { + let bridge_grandpa_call = crate::Call::::submit_finality_proof_ex { + finality_target: Box::new(test_header(100)), + justification: make_default_justification(&test_header(100)), + current_set_id: 0, + is_free_execution_expected: true, + }; + sync_to_header_10(); + + // when `improved_by` is less than the free interval + BestFinalized::::put(HeaderId( + 100 - FreeHeadersInterval::get() as u64 + 1, + sp_core::H256::default(), + )); + assert!(RuntimeCall::check_obsolete_submit_finality_proof(&RuntimeCall::Grandpa( + bridge_grandpa_call.clone(), + ),) + .is_err()); + + // when `improved_by` is equal to the free interval + BestFinalized::::put(HeaderId( + 100 - FreeHeadersInterval::get() as u64, + sp_core::H256::default(), + )); + assert!(RuntimeCall::check_obsolete_submit_finality_proof(&RuntimeCall::Grandpa( + bridge_grandpa_call.clone(), + ),) + .is_ok()); + + // when `improved_by` is larger than the free interval + BestFinalized::::put(HeaderId( + 100 - FreeHeadersInterval::get() as u64 - 1, + sp_core::H256::default(), + )); + assert!(RuntimeCall::check_obsolete_submit_finality_proof(&RuntimeCall::Grandpa( + bridge_grandpa_call.clone(), + ),) + .is_ok()); + + // when `improved_by` is less than the free interval BUT it is a mandatory header + let mut mandatory_header = test_header(100); + let consensus_log = sp_consensus_grandpa::ConsensusLog::::ScheduledChange( + sp_consensus_grandpa::ScheduledChange { + next_authorities: bp_test_utils::authority_list(), + delay: 0, + }, + ); + mandatory_header.digest = sp_runtime::Digest { + logs: vec![DigestItem::Consensus( + sp_consensus_grandpa::GRANDPA_ENGINE_ID, + consensus_log.encode(), + )], + }; + let justification = make_justification_for_header(JustificationGeneratorParams { + header: mandatory_header.clone(), + set_id: 1, + ..Default::default() + }); + let bridge_grandpa_call = crate::Call::::submit_finality_proof_ex { + finality_target: Box::new(mandatory_header), + justification, + current_set_id: 0, + is_free_execution_expected: true, + }; + BestFinalized::::put(HeaderId( + 100 - FreeHeadersInterval::get() as u64 + 1, + sp_core::H256::default(), + )); + assert!(RuntimeCall::check_obsolete_submit_finality_proof(&RuntimeCall::Grandpa( + bridge_grandpa_call.clone(), + ),) + .is_ok()); + }) + } + #[test] fn extension_accepts_new_header() { run_test(|| { @@ -336,6 +634,8 @@ mod tests { current_set_id: None, extra_weight: Weight::zero(), extra_size: 0, + is_mandatory: false, + is_free_execution_expected: false, }) ); @@ -345,6 +645,7 @@ mod tests { finality_target: Box::new(test_header(42)), justification: make_default_justification(&test_header(42)), current_set_id: 777, + is_free_execution_expected: false, }); assert_eq!( deprecated_call.submit_finality_proof_info(), @@ -353,6 +654,8 @@ mod tests { current_set_id: Some(777), extra_weight: Weight::zero(), extra_size: 0, + is_mandatory: false, + is_free_execution_expected: false, }) ); } @@ -370,6 +673,7 @@ mod tests { finality_target: Box::new(small_finality_target), justification: small_justification, current_set_id: TEST_GRANDPA_SET_ID, + is_free_execution_expected: false, }); assert_eq!(small_call.submit_finality_proof_info().unwrap().extra_size, 0); @@ -387,6 +691,7 @@ mod tests { finality_target: Box::new(large_finality_target), justification: large_justification, current_set_id: TEST_GRANDPA_SET_ID, + is_free_execution_expected: false, }); assert_ne!(large_call.submit_finality_proof_info().unwrap().extra_size, 0); } @@ -406,6 +711,7 @@ mod tests { finality_target: Box::new(finality_target.clone()), justification, current_set_id: TEST_GRANDPA_SET_ID, + is_free_execution_expected: false, }); assert_eq!(call.submit_finality_proof_info().unwrap().extra_weight, Weight::zero()); @@ -420,7 +726,52 @@ mod tests { finality_target: Box::new(finality_target), justification, current_set_id: TEST_GRANDPA_SET_ID, + is_free_execution_expected: false, }); assert_eq!(call.submit_finality_proof_info().unwrap().extra_weight, call_weight); } + + #[test] + fn check_obsolete_submit_finality_proof_returns_correct_improved_by() { + run_test(|| { + fn make_call(number: u64) -> RuntimeCall { + RuntimeCall::Grandpa(crate::Call::::submit_finality_proof_ex { + finality_target: Box::new(test_header(number)), + justification: make_default_justification(&test_header(number)), + current_set_id: 0, + is_free_execution_expected: false, + }) + } + + sync_to_header_10(); + + // when the difference between headers is 1 + assert_eq!( + RuntimeCall::check_obsolete_submit_finality_proof(&make_call(11)) + .unwrap() + .unwrap() + .improved_by, + 1, + ); + + // when the difference between headers is 2 + assert_eq!( + RuntimeCall::check_obsolete_submit_finality_proof(&make_call(12)) + .unwrap() + .unwrap() + .improved_by, + 2, + ); + }) + } + + #[test] + fn check_obsolete_submit_finality_proof_ignores_other_calls() { + run_test(|| { + let call = + RuntimeCall::System(frame_system::Call::::remark { remark: vec![42] }); + + assert_eq!(RuntimeCall::check_obsolete_submit_finality_proof(&call), Ok(None)); + }) + } } diff --git a/bridges/modules/grandpa/src/lib.rs b/bridges/modules/grandpa/src/lib.rs index 9e095651ef81da1e5418d7532ae56ae0fb8ef564..a927882aaaa27210c4777fa2e99a109b4d8b500b 100644 --- a/bridges/modules/grandpa/src/lib.rs +++ b/bridges/modules/grandpa/src/lib.rs @@ -44,11 +44,12 @@ use bp_header_chain::{ }; use bp_runtime::{BlockNumberOf, HashOf, HasherOf, HeaderId, HeaderOf, OwnedBridgeModule}; use frame_support::{dispatch::PostDispatchInfo, ensure, DefaultNoBound}; +use sp_consensus_grandpa::SetId; use sp_runtime::{ traits::{Header as HeaderT, Zero}, SaturatedConversion, }; -use sp_std::{boxed::Box, convert::TryInto, prelude::*}; +use sp_std::{boxed::Box, prelude::*}; mod call_ext; #[cfg(test)] @@ -57,6 +58,7 @@ mod storage_types; /// Module, containing weights for this pallet. pub mod weights; +pub mod weights_ext; #[cfg(feature = "runtime-benchmarks")] pub mod benchmarking; @@ -65,6 +67,7 @@ pub mod benchmarking; pub use call_ext::*; pub use pallet::*; pub use weights::WeightInfo; +pub use weights_ext::WeightInfoExt; /// The target that will be used when publishing logs related to this pallet. pub const LOG_TARGET: &str = "runtime::bridge-grandpa"; @@ -101,17 +104,31 @@ pub mod pallet { /// The chain we are bridging to here. type BridgedChain: ChainWithGrandpa; - /// Maximal number of "free" mandatory header transactions per block. + /// Maximal number of "free" header transactions per block. /// /// To be able to track the bridged chain, the pallet requires all headers that are /// changing GRANDPA authorities set at the bridged chain (we call them mandatory). - /// So it is a common good deed to submit mandatory headers to the pallet. However, if the - /// bridged chain gets compromised, its validators may generate as many mandatory headers - /// as they want. And they may fill the whole block (at this chain) for free. This constants - /// limits number of calls that we may refund in a single block. All calls above this - /// limit are accepted, but are not refunded. + /// So it is a common good deed to submit mandatory headers to the pallet. + /// + /// The pallet may be configured (see `[Self::FreeHeadersInterval]`) to import some + /// non-mandatory headers for free as well. It also may be treated as a common good + /// deed, because it may help to reduce bridge fees - this cost may be deducted from + /// bridge fees, paid by message senders. + /// + /// However, if the bridged chain gets compromised, its validators may generate as many + /// "free" headers as they want. And they may fill the whole block (at this chain) for + /// free. This constants limits number of calls that we may refund in a single block. + /// All calls above this limit are accepted, but are not refunded. + #[pallet::constant] + type MaxFreeHeadersPerBlock: Get; + + /// The distance between bridged chain headers, that may be submitted for free. The + /// first free header is header number zero, the next one is header number + /// `FreeHeadersInterval::get()` or any of its descendant if that header has not + /// been submitted. In other words, interval between free headers should be at least + /// `FreeHeadersInterval`. #[pallet::constant] - type MaxFreeMandatoryHeadersPerBlock: Get; + type FreeHeadersInterval: Get>; /// Maximal number of finalized headers to keep in the storage. /// @@ -124,7 +141,7 @@ pub mod pallet { type HeadersToKeep: Get; /// Weights gathered through benchmarking. - type WeightInfo: WeightInfo; + type WeightInfo: WeightInfoExt; } #[pallet::pallet] @@ -133,12 +150,12 @@ pub mod pallet { #[pallet::hooks] impl, I: 'static> Hooks> for Pallet { fn on_initialize(_n: BlockNumberFor) -> Weight { - FreeMandatoryHeadersRemaining::::put(T::MaxFreeMandatoryHeadersPerBlock::get()); + FreeHeadersRemaining::::put(T::MaxFreeHeadersPerBlock::get()); Weight::zero() } fn on_finalize(_n: BlockNumberFor) { - FreeMandatoryHeadersRemaining::::kill(); + FreeHeadersRemaining::::kill(); } } @@ -155,7 +172,7 @@ pub mod pallet { /// `submit_finality_proof_ex` instead. Semantically, this call is an equivalent of the /// `submit_finality_proof_ex` call without current authority set id check. #[pallet::call_index(0)] - #[pallet::weight(::submit_finality_proof( + #[pallet::weight(T::WeightInfo::submit_finality_proof_weight( justification.commit.precommits.len().saturated_into(), justification.votes_ancestries.len().saturated_into(), ))] @@ -175,6 +192,8 @@ pub mod pallet { // the `submit_finality_proof_ex` also reads this value, but it is done from the // cache, so we don't treat it as an additional db access >::get().set_id, + // cannot enforce free execution using this call + false, ) } @@ -250,8 +269,14 @@ pub mod pallet { /// - verification is not optimized or invalid; /// /// - header contains forced authorities set change or change with non-zero delay. + /// + /// The `is_free_execution_expected` parameter is not really used inside the call. It is + /// used by the transaction extension, which should be registered at the runtime level. If + /// this parameter is `true`, the transaction will be treated as invalid, if the call won't + /// be executed for free. If transaction extension is not used by the runtime, this + /// parameter is not used at all. #[pallet::call_index(4)] - #[pallet::weight(::submit_finality_proof( + #[pallet::weight(T::WeightInfo::submit_finality_proof_weight( justification.commit.precommits.len().saturated_into(), justification.votes_ancestries.len().saturated_into(), ))] @@ -260,6 +285,7 @@ pub mod pallet { finality_target: Box>, justification: GrandpaJustification>, current_set_id: sp_consensus_grandpa::SetId, + _is_free_execution_expected: bool, ) -> DispatchResultWithPostInfo { Self::ensure_not_halted().map_err(Error::::BridgeModule)?; ensure_signed(origin)?; @@ -273,7 +299,8 @@ pub mod pallet { // it checks whether the `number` is better than the current best block number // and whether the `current_set_id` matches the best known set id - SubmitFinalityProofHelper::::check_obsolete(number, Some(current_set_id))?; + let improved_by = + SubmitFinalityProofHelper::::check_obsolete(number, Some(current_set_id))?; let authority_set = >::get(); let unused_proof_size = authority_set.unused_proof_size(); @@ -283,23 +310,16 @@ pub mod pallet { let maybe_new_authority_set = try_enact_authority_change::(&finality_target, set_id)?; - let may_refund_call_fee = maybe_new_authority_set.is_some() && - // if we have seen too many mandatory headers in this block, we don't want to refund - Self::free_mandatory_headers_remaining() > 0 && - // if arguments out of expected bounds, we don't want to refund - submit_finality_proof_info_from_args::(&finality_target, &justification, Some(current_set_id)) - .fits_limits(); + let may_refund_call_fee = may_refund_call_fee::( + &finality_target, + &justification, + current_set_id, + improved_by, + ); if may_refund_call_fee { - FreeMandatoryHeadersRemaining::::mutate(|count| { - *count = count.saturating_sub(1) - }); + on_free_header_imported::(); } insert_header::(*finality_target, hash); - log::info!( - target: LOG_TARGET, - "Successfully imported finalized header with hash {:?}!", - hash - ); // mandatory header is a header that changes authorities set. The pallet can't go // further without importing this header. So every bridge MUST import mandatory headers. @@ -311,6 +331,13 @@ pub mod pallet { // to pay for the transaction. let pays_fee = if may_refund_call_fee { Pays::No } else { Pays::Yes }; + log::info!( + target: LOG_TARGET, + "Successfully imported finalized header with hash {:?}! Free: {}", + hash, + if may_refund_call_fee { "Yes" } else { "No" }, + ); + // the proof size component of the call weight assumes that there are // `MaxBridgedAuthorities` in the `CurrentAuthoritySet` (we use `MaxEncodedLen` // estimation). But if their number is lower, then we may "refund" some `proof_size`, @@ -335,20 +362,18 @@ pub mod pallet { } } - /// Number mandatory headers that we may accept in the current block for free (returning - /// `Pays::No`). + /// Number of free header submissions that we may yet accept in the current block. /// - /// If the `FreeMandatoryHeadersRemaining` hits zero, all following mandatory headers in the + /// If the `FreeHeadersRemaining` hits zero, all following mandatory headers in the /// current block are accepted with fee (`Pays::Yes` is returned). /// - /// The `FreeMandatoryHeadersRemaining` is an ephemeral value that is set to - /// `MaxFreeMandatoryHeadersPerBlock` at each block initialization and is killed on block + /// The `FreeHeadersRemaining` is an ephemeral value that is set to + /// `MaxFreeHeadersPerBlock` at each block initialization and is killed on block /// finalization. So it never ends up in the storage trie. #[pallet::storage] #[pallet::whitelist_storage] - #[pallet::getter(fn free_mandatory_headers_remaining)] - pub(super) type FreeMandatoryHeadersRemaining, I: 'static = ()> = - StorageValue<_, u32, ValueQuery>; + pub type FreeHeadersRemaining, I: 'static = ()> = + StorageValue<_, u32, OptionQuery>; /// Hash of the header used to bootstrap the pallet. #[pallet::storage] @@ -473,6 +498,71 @@ pub mod pallet { /// The `current_set_id` argument of the `submit_finality_proof_ex` doesn't match /// the id of the current set, known to the pallet. InvalidAuthoritySetId, + /// The submitter wanted free execution, but we can't fit more free transactions + /// to the block. + FreeHeadersLimitExceded, + /// The submitter wanted free execution, but the difference between best known and + /// bundled header numbers is below the `FreeHeadersInterval`. + BelowFreeHeaderInterval, + /// The header (and its finality) submission overflows hardcoded chain limits: size + /// and/or weight are larger than expected. + HeaderOverflowLimits, + } + + /// Called when new free header is imported. + pub fn on_free_header_imported, I: 'static>() { + FreeHeadersRemaining::::mutate(|count| { + *count = match *count { + None => None, + // the signed extension expects that `None` means outside of block + // execution - i.e. when transaction is validated from the transaction pool, + // so use `saturating_sub` and don't go from `Some(0)`->`None` + Some(count) => Some(count.saturating_sub(1)), + } + }); + } + + /// Return true if we may refund transaction cost to the submitter. In other words, + /// this transaction is considered as common good deed w.r.t to pallet configuration. + fn may_refund_call_fee, I: 'static>( + finality_target: &BridgedHeader, + justification: &GrandpaJustification>, + current_set_id: SetId, + improved_by: BridgedBlockNumber, + ) -> bool { + // if we have refunded too much at this block => not refunding + if FreeHeadersRemaining::::get().unwrap_or(0) == 0 { + return false; + } + + // if size/weight of call is larger than expected => not refunding + let call_info = submit_finality_proof_info_from_args::( + &finality_target, + &justification, + Some(current_set_id), + // this function is called from the transaction body and we do not want + // to do MAY-be-free-executed checks here - they had to be done in the + // transaction extension before + false, + ); + if !call_info.fits_limits() { + return false; + } + + // if that's a mandatory header => refund + if call_info.is_mandatory { + return true; + } + + // if configuration allows free non-mandatory headers and the header + // matches criteria => refund + if let Some(free_headers_interval) = T::FreeHeadersInterval::get() { + if improved_by >= free_headers_interval.into() { + return true; + } + } + + false } /// Check the given header for a GRANDPA scheduled authority set change. If a change @@ -692,8 +782,8 @@ pub fn initialize_for_benchmarks, I: 'static>(header: BridgedHeader mod tests { use super::*; use crate::mock::{ - run_test, test_header, RuntimeEvent as TestEvent, RuntimeOrigin, System, TestBridgedChain, - TestHeader, TestNumber, TestRuntime, MAX_BRIDGED_AUTHORITIES, + run_test, test_header, FreeHeadersInterval, RuntimeEvent as TestEvent, RuntimeOrigin, + System, TestBridgedChain, TestHeader, TestNumber, TestRuntime, MAX_BRIDGED_AUTHORITIES, }; use bp_header_chain::BridgeGrandpaCall; use bp_runtime::BasicOperatingMode; @@ -747,6 +837,7 @@ mod tests { Box::new(header), justification, TEST_GRANDPA_SET_ID, + false, ) } @@ -766,6 +857,7 @@ mod tests { Box::new(header), justification, set_id, + false, ) } @@ -794,6 +886,7 @@ mod tests { Box::new(header), justification, set_id, + false, ) } @@ -1009,6 +1102,7 @@ mod tests { Box::new(header.clone()), justification.clone(), TEST_GRANDPA_SET_ID, + false, ), >::InvalidJustification ); @@ -1018,6 +1112,7 @@ mod tests { Box::new(header), justification, next_set_id, + false, ), >::InvalidAuthoritySetId ); @@ -1039,6 +1134,7 @@ mod tests { Box::new(header), justification, TEST_GRANDPA_SET_ID, + false, ), >::InvalidJustification ); @@ -1069,6 +1165,7 @@ mod tests { Box::new(header), justification, TEST_GRANDPA_SET_ID, + false, ), >::InvalidAuthoritySet ); @@ -1108,6 +1205,7 @@ mod tests { Box::new(header.clone()), justification.clone(), TEST_GRANDPA_SET_ID, + false, ); assert_ok!(result); assert_eq!(result.unwrap().pays_fee, frame_support::dispatch::Pays::No); @@ -1171,6 +1269,7 @@ mod tests { Box::new(header.clone()), justification, TEST_GRANDPA_SET_ID, + false, ); assert_ok!(result); assert_eq!(result.unwrap().pays_fee, frame_support::dispatch::Pays::Yes); @@ -1203,6 +1302,7 @@ mod tests { Box::new(header.clone()), justification, TEST_GRANDPA_SET_ID, + false, ); assert_ok!(result); assert_eq!(result.unwrap().pays_fee, frame_support::dispatch::Pays::Yes); @@ -1233,6 +1333,7 @@ mod tests { Box::new(header), justification, TEST_GRANDPA_SET_ID, + false, ), >::UnsupportedScheduledChange ); @@ -1259,6 +1360,7 @@ mod tests { Box::new(header), justification, TEST_GRANDPA_SET_ID, + false, ), >::UnsupportedScheduledChange ); @@ -1285,6 +1387,7 @@ mod tests { Box::new(header), justification, TEST_GRANDPA_SET_ID, + false, ), >::TooManyAuthoritiesInSet ); @@ -1350,12 +1453,13 @@ mod tests { Box::new(header), invalid_justification, TEST_GRANDPA_SET_ID, + false, ) }; initialize_substrate_bridge(); - for _ in 0..::MaxFreeMandatoryHeadersPerBlock::get() + 1 { + for _ in 0..::MaxFreeHeadersPerBlock::get() + 1 { assert_err!(submit_invalid_request(), >::InvalidJustification); } @@ -1423,6 +1527,64 @@ mod tests { }) } + #[test] + fn may_import_non_mandatory_header_for_free() { + run_test(|| { + initialize_substrate_bridge(); + + // set best finalized to `100` + const BEST: u8 = 12; + fn reset_best() { + BestFinalized::::set(Some(HeaderId( + BEST as _, + Default::default(), + ))); + } + + // non-mandatory header is imported with fee + reset_best(); + let non_free_header_number = BEST + FreeHeadersInterval::get() as u8 - 1; + let result = submit_finality_proof(non_free_header_number); + assert_eq!(result.unwrap().pays_fee, Pays::Yes); + + // non-mandatory free header is imported without fee + reset_best(); + let free_header_number = BEST + FreeHeadersInterval::get() as u8; + let result = submit_finality_proof(free_header_number); + assert_eq!(result.unwrap().pays_fee, Pays::No); + + // another non-mandatory free header is imported without fee + let free_header_number = BEST + FreeHeadersInterval::get() as u8 * 2; + let result = submit_finality_proof(free_header_number); + assert_eq!(result.unwrap().pays_fee, Pays::No); + + // now the rate limiter starts charging fees even for free headers + let free_header_number = BEST + FreeHeadersInterval::get() as u8 * 3; + let result = submit_finality_proof(free_header_number); + assert_eq!(result.unwrap().pays_fee, Pays::Yes); + + // check that we can import for free if `improved_by` is larger + // than the free interval + next_block(); + reset_best(); + let free_header_number = FreeHeadersInterval::get() as u8 + 42; + let result = submit_finality_proof(free_header_number); + assert_eq!(result.unwrap().pays_fee, Pays::No); + + // check that the rate limiter shares the counter between mandatory + // and free non-mandatory headers + next_block(); + reset_best(); + let free_header_number = BEST + FreeHeadersInterval::get() as u8 * 4; + let result = submit_finality_proof(free_header_number); + assert_eq!(result.unwrap().pays_fee, Pays::No); + let result = submit_mandatory_finality_proof(free_header_number + 1, 1); + assert_eq!(result.expect("call failed").pays_fee, Pays::No); + let result = submit_mandatory_finality_proof(free_header_number + 2, 2); + assert_eq!(result.expect("call failed").pays_fee, Pays::Yes); + }); + } + #[test] fn should_prune_headers_over_headers_to_keep_parameter() { run_test(|| { @@ -1519,9 +1681,23 @@ mod tests { Box::new(header), justification, TEST_GRANDPA_SET_ID, + false, ), DispatchError::BadOrigin, ); }) } + + #[test] + fn on_free_header_imported_never_sets_to_none() { + run_test(|| { + FreeHeadersRemaining::::set(Some(2)); + on_free_header_imported::(); + assert_eq!(FreeHeadersRemaining::::get(), Some(1)); + on_free_header_imported::(); + assert_eq!(FreeHeadersRemaining::::get(), Some(0)); + on_free_header_imported::(); + assert_eq!(FreeHeadersRemaining::::get(), Some(0)); + }) + } } diff --git a/bridges/modules/grandpa/src/mock.rs b/bridges/modules/grandpa/src/mock.rs index e689e520c92ffcb230a83f7a728722a688729417..27df9d9c78f540d0d73f74c6a86ba19af30d4b6b 100644 --- a/bridges/modules/grandpa/src/mock.rs +++ b/bridges/modules/grandpa/src/mock.rs @@ -48,14 +48,16 @@ impl frame_system::Config for TestRuntime { } parameter_types! { - pub const MaxFreeMandatoryHeadersPerBlock: u32 = 2; + pub const MaxFreeHeadersPerBlock: u32 = 2; + pub const FreeHeadersInterval: u32 = 32; pub const HeadersToKeep: u32 = 5; } impl grandpa::Config for TestRuntime { type RuntimeEvent = RuntimeEvent; type BridgedChain = TestBridgedChain; - type MaxFreeMandatoryHeadersPerBlock = MaxFreeMandatoryHeadersPerBlock; + type MaxFreeHeadersPerBlock = MaxFreeHeadersPerBlock; + type FreeHeadersInterval = FreeHeadersInterval; type HeadersToKeep = HeadersToKeep; type WeightInfo = (); } diff --git a/bridges/modules/grandpa/src/weights_ext.rs b/bridges/modules/grandpa/src/weights_ext.rs new file mode 100644 index 0000000000000000000000000000000000000000..66edea6fb6a64cfa530bd48b0dfd1762af9c545f --- /dev/null +++ b/bridges/modules/grandpa/src/weights_ext.rs @@ -0,0 +1,58 @@ +// Copyright (C) Parity Technologies (UK) Ltd. +// This file is part of Parity Bridges Common. + +// Parity Bridges Common is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// Parity Bridges Common is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with Parity Bridges Common. If not, see . + +//! Weight-related utilities. + +use crate::weights::{BridgeWeight, WeightInfo}; + +use frame_support::weights::Weight; + +/// Extended weight info. +pub trait WeightInfoExt: WeightInfo { + // Our configuration assumes that the runtime has special signed extensions used to: + // + // 1) boost priority of `submit_finality_proof` transactions; + // + // 2) slash relayer if he submits an invalid transaction. + // + // We read and update storage values of other pallets (`pallet-bridge-relayers` and + // balances/assets pallet). So we need to add this weight to the weight of our call. + // Hence two following methods. + + /// Extra weight that is added to the `submit_finality_proof` call weight by signed extensions + /// that are declared at runtime level. + fn submit_finality_proof_overhead_from_runtime() -> Weight; + + // Functions that are directly mapped to extrinsics weights. + + /// Weight of message delivery extrinsic. + fn submit_finality_proof_weight(precommits_len: u32, votes_ancestries_len: u32) -> Weight { + let base_weight = Self::submit_finality_proof(precommits_len, votes_ancestries_len); + base_weight.saturating_add(Self::submit_finality_proof_overhead_from_runtime()) + } +} + +impl WeightInfoExt for BridgeWeight { + fn submit_finality_proof_overhead_from_runtime() -> Weight { + Weight::zero() + } +} + +impl WeightInfoExt for () { + fn submit_finality_proof_overhead_from_runtime() -> Weight { + Weight::zero() + } +} diff --git a/bridges/modules/messages/Cargo.toml b/bridges/modules/messages/Cargo.toml index df5b92db7402bd048b1afca9c13cfb1dddc74863..71c86ccc0361708684d0a93166f858118dbf0d92 100644 --- a/bridges/modules/messages/Cargo.toml +++ b/bridges/modules/messages/Cargo.toml @@ -11,7 +11,7 @@ repository.workspace = true workspace = true [dependencies] -codec = { package = "parity-scale-codec", version = "3.6.1", default-features = false } +codec = { package = "parity-scale-codec", version = "3.6.12", default-features = false } log = { workspace = true } num-traits = { version = "0.2", default-features = false } scale-info = { version = "2.11.1", default-features = false, features = ["derive"] } diff --git a/bridges/modules/parachains/Cargo.toml b/bridges/modules/parachains/Cargo.toml index 35213be0674a8c8d31de79afb720fbf457f3445a..d3152f8d0a4aa9b6dc1c726441c5e139e08de162 100644 --- a/bridges/modules/parachains/Cargo.toml +++ b/bridges/modules/parachains/Cargo.toml @@ -11,7 +11,7 @@ repository.workspace = true workspace = true [dependencies] -codec = { package = "parity-scale-codec", version = "3.6.1", default-features = false } +codec = { package = "parity-scale-codec", version = "3.6.12", default-features = false } log = { workspace = true } scale-info = { version = "2.11.1", default-features = false, features = ["derive"] } diff --git a/bridges/modules/parachains/src/call_ext.rs b/bridges/modules/parachains/src/call_ext.rs index da91a40a2322393ee715bf1c61840e4b18df23b8..fe6b319205d41491ce2df36d8a1d112eb37f94b4 100644 --- a/bridges/modules/parachains/src/call_ext.rs +++ b/bridges/modules/parachains/src/call_ext.rs @@ -14,25 +14,45 @@ // You should have received a copy of the GNU General Public License // along with Parity Bridges Common. If not, see . -use crate::{Config, Pallet, RelayBlockNumber}; +use crate::{Config, GrandpaPalletOf, Pallet, RelayBlockHash, RelayBlockNumber}; +use bp_header_chain::HeaderChain; use bp_parachains::BestParaHeadHash; use bp_polkadot_core::parachains::{ParaHash, ParaId}; -use bp_runtime::OwnedBridgeModule; -use frame_support::{dispatch::CallableCallFor, traits::IsSubType}; +use bp_runtime::{HeaderId, OwnedBridgeModule}; +use frame_support::{ + dispatch::CallableCallFor, + traits::{Get, IsSubType}, +}; +use pallet_bridge_grandpa::SubmitFinalityProofHelper; use sp_runtime::{ - transaction_validity::{InvalidTransaction, TransactionValidity, ValidTransaction}, + traits::Zero, + transaction_validity::{InvalidTransaction, TransactionValidityError}, RuntimeDebug, }; /// Info about a `SubmitParachainHeads` call which tries to update a single parachain. #[derive(PartialEq, RuntimeDebug)] pub struct SubmitParachainHeadsInfo { - /// Number of the finalized relay block that has been used to prove parachain finality. - pub at_relay_block_number: RelayBlockNumber, + /// Number and hash of the finalized relay block that has been used to prove parachain + /// finality. + pub at_relay_block: HeaderId, /// Parachain identifier. pub para_id: ParaId, /// Hash of the bundled parachain head. pub para_head_hash: ParaHash, + /// If `true`, then the call must be free (assuming that everything else is valid) to + /// be treated as valid. + pub is_free_execution_expected: bool, +} + +/// Verified `SubmitParachainHeadsInfo`. +#[derive(PartialEq, RuntimeDebug)] +pub struct VerifiedSubmitParachainHeadsInfo { + /// Base call information. + pub base: SubmitParachainHeadsInfo, + /// A difference between bundled bridged relay chain header and relay chain header number + /// used to prove best bridged parachain header, known to us before the call. + pub improved_by: RelayBlockNumber, } /// Helper struct that provides methods for working with the `SubmitParachainHeads` call. @@ -41,40 +61,117 @@ pub struct SubmitParachainHeadsHelper, I: 'static> { } impl, I: 'static> SubmitParachainHeadsHelper { - /// Check if the para head provided by the `SubmitParachainHeads` is better than the best one - /// we know. - pub fn is_obsolete(update: &SubmitParachainHeadsInfo) -> bool { - let stored_best_head = match crate::ParasInfo::::get(update.para_id) { - Some(stored_best_head) => stored_best_head, - None => return false, + /// Check that is called from signed extension and takes the `is_free_execution_expected` + /// into account. + pub fn check_obsolete_from_extension( + update: &SubmitParachainHeadsInfo, + ) -> Result { + // first do all base checks + let improved_by = Self::check_obsolete(update)?; + + // if we don't expect free execution - no more checks + if !update.is_free_execution_expected { + return Ok(improved_by); + } + + // reject if no more free slots remaining in the block + if !SubmitFinalityProofHelper::::has_free_header_slots() + { + log::trace!( + target: crate::LOG_TARGET, + "The free parachain {:?} head can't be updated: no more free slots \ + left in the block.", + update.para_id, + ); + + return Err(InvalidTransaction::Call.into()); + } + + // if free headers interval is not configured and call is expected to execute + // for free => it is a relayer error, it should've been able to detect that. + let free_headers_interval = match T::FreeHeadersInterval::get() { + Some(free_headers_interval) => free_headers_interval, + None => return Ok(improved_by), }; - if stored_best_head.best_head_hash.at_relay_block_number >= update.at_relay_block_number { + // reject if we are importing parachain headers too often + if improved_by < free_headers_interval { log::trace!( target: crate::LOG_TARGET, - "The parachain head can't be updated. The parachain head for {:?} \ - was already updated at better relay chain block {} >= {}.", + "The free parachain {:?} head can't be updated: it improves previous + best head by {} while at least {} is expected.", update.para_id, - stored_best_head.best_head_hash.at_relay_block_number, - update.at_relay_block_number + improved_by, + free_headers_interval, ); - return true + + return Err(InvalidTransaction::Stale.into()); } - if stored_best_head.best_head_hash.head_hash == update.para_head_hash { + Ok(improved_by) + } + + /// Check if the para head provided by the `SubmitParachainHeads` is better than the best one + /// we know. + pub fn check_obsolete( + update: &SubmitParachainHeadsInfo, + ) -> Result { + // check if we know better parachain head already + let improved_by = match crate::ParasInfo::::get(update.para_id) { + Some(stored_best_head) => { + let improved_by = match update + .at_relay_block + .0 + .checked_sub(stored_best_head.best_head_hash.at_relay_block_number) + { + Some(improved_by) if improved_by > Zero::zero() => improved_by, + _ => { + log::trace!( + target: crate::LOG_TARGET, + "The parachain head can't be updated. The parachain head for {:?} \ + was already updated at better relay chain block {} >= {}.", + update.para_id, + stored_best_head.best_head_hash.at_relay_block_number, + update.at_relay_block.0 + ); + return Err(InvalidTransaction::Stale.into()) + }, + }; + + if stored_best_head.best_head_hash.head_hash == update.para_head_hash { + log::trace!( + target: crate::LOG_TARGET, + "The parachain head can't be updated. The parachain head hash for {:?} \ + was already updated to {} at block {} < {}.", + update.para_id, + update.para_head_hash, + stored_best_head.best_head_hash.at_relay_block_number, + update.at_relay_block.0 + ); + return Err(InvalidTransaction::Stale.into()) + } + + improved_by + }, + None => RelayBlockNumber::MAX, + }; + + // let's check if our chain had no reorgs and we still know the relay chain header + // used to craft the proof + if GrandpaPalletOf::::finalized_header_state_root(update.at_relay_block.1).is_none() { log::trace!( target: crate::LOG_TARGET, - "The parachain head can't be updated. The parachain head hash for {:?} \ - was already updated to {} at block {} < {}.", + "The parachain {:?} head can't be updated. Relay chain header {}/{} used to create \ + parachain proof is missing from the storage.", update.para_id, - update.para_head_hash, - stored_best_head.best_head_hash.at_relay_block_number, - update.at_relay_block_number + update.at_relay_block.0, + update.at_relay_block.1, ); - return true + + return Err(InvalidTransaction::Call.into()) } - false + Ok(improved_by) } /// Check if the `SubmitParachainHeads` was successfully executed. @@ -83,7 +180,7 @@ impl, I: 'static> SubmitParachainHeadsHelper { Some(stored_best_head) => stored_best_head.best_head_hash == BestParaHeadHash { - at_relay_block_number: update.at_relay_block_number, + at_relay_block_number: update.at_relay_block.0, head_hash: update.para_head_hash, }, None => false, @@ -98,22 +195,36 @@ pub trait CallSubType, I: 'static>: /// Create a new instance of `SubmitParachainHeadsInfo` from a `SubmitParachainHeads` call with /// one single parachain entry. fn one_entry_submit_parachain_heads_info(&self) -> Option { - if let Some(crate::Call::::submit_parachain_heads { - ref at_relay_block, - ref parachains, - .. - }) = self.is_sub_type() - { - if let &[(para_id, para_head_hash)] = parachains.as_slice() { - return Some(SubmitParachainHeadsInfo { - at_relay_block_number: at_relay_block.0, + match self.is_sub_type() { + Some(crate::Call::::submit_parachain_heads { + ref at_relay_block, + ref parachains, + .. + }) => match ¶chains[..] { + &[(para_id, para_head_hash)] => Some(SubmitParachainHeadsInfo { + at_relay_block: HeaderId(at_relay_block.0, at_relay_block.1), para_id, para_head_hash, - }) - } + is_free_execution_expected: false, + }), + _ => None, + }, + Some(crate::Call::::submit_parachain_heads_ex { + ref at_relay_block, + ref parachains, + is_free_execution_expected, + .. + }) => match ¶chains[..] { + &[(para_id, para_head_hash)] => Some(SubmitParachainHeadsInfo { + at_relay_block: HeaderId(at_relay_block.0, at_relay_block.1), + para_id, + para_head_hash, + is_free_execution_expected: *is_free_execution_expected, + }), + _ => None, + }, + _ => None, } - - None } /// Create a new instance of `SubmitParachainHeadsInfo` from a `SubmitParachainHeads` call with @@ -133,24 +244,23 @@ pub trait CallSubType, I: 'static>: /// block production, or "eat" significant portion of block production time literally /// for nothing. In addition, the single-parachain-head-per-transaction is how the /// pallet will be used in our environment. - fn check_obsolete_submit_parachain_heads(&self) -> TransactionValidity + fn check_obsolete_submit_parachain_heads( + &self, + ) -> Result, TransactionValidityError> where Self: Sized, { let update = match self.one_entry_submit_parachain_heads_info() { Some(update) => update, - None => return Ok(ValidTransaction::default()), + None => return Ok(None), }; if Pallet::::ensure_not_halted().is_err() { - return InvalidTransaction::Call.into() + return Err(InvalidTransaction::Call.into()) } - if SubmitParachainHeadsHelper::::is_obsolete(&update) { - return InvalidTransaction::Stale.into() - } - - Ok(ValidTransaction::default()) + SubmitParachainHeadsHelper::::check_obsolete_from_extension(&update) + .map(|improved_by| Some(VerifiedSubmitParachainHeadsInfo { base: update, improved_by })) } } @@ -164,9 +274,10 @@ where #[cfg(test)] mod tests { use crate::{ - mock::{run_test, RuntimeCall, TestRuntime}, - CallSubType, PalletOperatingMode, ParaInfo, ParasInfo, RelayBlockNumber, + mock::{run_test, FreeHeadersInterval, RuntimeCall, TestRuntime}, + CallSubType, PalletOperatingMode, ParaInfo, ParasInfo, RelayBlockHash, RelayBlockNumber, }; + use bp_header_chain::StoredHeaderData; use bp_parachains::BestParaHeadHash; use bp_polkadot_core::parachains::{ParaHash, ParaHeadsProof, ParaId}; use bp_runtime::BasicOperatingMode; @@ -175,15 +286,37 @@ mod tests { num: RelayBlockNumber, parachains: Vec<(ParaId, ParaHash)>, ) -> bool { - RuntimeCall::Parachains(crate::Call::::submit_parachain_heads { - at_relay_block: (num, Default::default()), + RuntimeCall::Parachains(crate::Call::::submit_parachain_heads_ex { + at_relay_block: (num, [num as u8; 32].into()), + parachains, + parachain_heads_proof: ParaHeadsProof { storage_proof: Vec::new() }, + is_free_execution_expected: false, + }) + .check_obsolete_submit_parachain_heads() + .is_ok() + } + + fn validate_free_submit_parachain_heads( + num: RelayBlockNumber, + parachains: Vec<(ParaId, ParaHash)>, + ) -> bool { + RuntimeCall::Parachains(crate::Call::::submit_parachain_heads_ex { + at_relay_block: (num, [num as u8; 32].into()), parachains, parachain_heads_proof: ParaHeadsProof { storage_proof: Vec::new() }, + is_free_execution_expected: true, }) .check_obsolete_submit_parachain_heads() .is_ok() } + fn insert_relay_block(num: RelayBlockNumber) { + pallet_bridge_grandpa::ImportedHeaders::::insert( + RelayBlockHash::from([num as u8; 32]), + StoredHeaderData { number: num, state_root: RelayBlockHash::from([10u8; 32]) }, + ); + } + fn sync_to_relay_header_10() { ParasInfo::::insert( ParaId(1), @@ -244,6 +377,7 @@ mod tests { // when current best finalized is #10 and we're trying to import header#15 => tx is // accepted sync_to_relay_header_10(); + insert_relay_block(15); assert!(validate_submit_parachain_heads(15, vec![(ParaId(1), [2u8; 32].into())])); }); } @@ -260,4 +394,65 @@ mod tests { )); }); } + + #[test] + fn extension_rejects_initial_parachain_head_if_missing_relay_chain_header() { + run_test(|| { + // when relay chain header is unknown => "obsolete" + assert!(!validate_submit_parachain_heads(10, vec![(ParaId(1), [1u8; 32].into())])); + // when relay chain header is unknown => "ok" + insert_relay_block(10); + assert!(validate_submit_parachain_heads(10, vec![(ParaId(1), [1u8; 32].into())])); + }); + } + + #[test] + fn extension_rejects_free_parachain_head_if_missing_relay_chain_header() { + run_test(|| { + sync_to_relay_header_10(); + // when relay chain header is unknown => "obsolete" + assert!(!validate_submit_parachain_heads(15, vec![(ParaId(2), [15u8; 32].into())])); + // when relay chain header is unknown => "ok" + insert_relay_block(15); + assert!(validate_submit_parachain_heads(15, vec![(ParaId(2), [15u8; 32].into())])); + }); + } + + #[test] + fn extension_rejects_free_parachain_head_if_no_free_slots_remaining() { + run_test(|| { + // when current best finalized is #10 and we're trying to import header#15 => tx should + // be accepted + sync_to_relay_header_10(); + insert_relay_block(15); + // ... but since we have specified `is_free_execution_expected = true`, it'll be + // rejected + assert!(!validate_free_submit_parachain_heads(15, vec![(ParaId(1), [2u8; 32].into())])); + // ... if we have specify `is_free_execution_expected = false`, it'll be accepted + assert!(validate_submit_parachain_heads(15, vec![(ParaId(1), [2u8; 32].into())])); + }); + } + + #[test] + fn extension_rejects_free_parachain_head_if_improves_by_is_below_expected() { + run_test(|| { + // when current best finalized is #10 and we're trying to import header#15 => tx should + // be accepted + sync_to_relay_header_10(); + insert_relay_block(10 + FreeHeadersInterval::get() - 1); + insert_relay_block(10 + FreeHeadersInterval::get()); + // try to submit at 10 + FreeHeadersInterval::get() - 1 => failure + let relay_header = 10 + FreeHeadersInterval::get() - 1; + assert!(!validate_free_submit_parachain_heads( + relay_header, + vec![(ParaId(1), [2u8; 32].into())] + )); + // try to submit at 10 + FreeHeadersInterval::get() => ok + let relay_header = 10 + FreeHeadersInterval::get(); + assert!(validate_free_submit_parachain_heads( + relay_header, + vec![(ParaId(1), [2u8; 32].into())] + )); + }); + } } diff --git a/bridges/modules/parachains/src/lib.rs b/bridges/modules/parachains/src/lib.rs index 1363a637604d1202ffc4bf799bf7ced180d9fe53..61e04aed3770dcaa9cb611dc754aad21325e1b39 100644 --- a/bridges/modules/parachains/src/lib.rs +++ b/bridges/modules/parachains/src/lib.rs @@ -32,6 +32,7 @@ use bp_parachains::{parachain_head_storage_key_at_source, ParaInfo, ParaStoredHe use bp_polkadot_core::parachains::{ParaHash, ParaHead, ParaHeadsProof, ParaId}; use bp_runtime::{Chain, HashOf, HeaderId, HeaderIdOf, Parachain, StorageProofError}; use frame_support::{dispatch::PostDispatchInfo, DefaultNoBound}; +use pallet_bridge_grandpa::SubmitFinalityProofHelper; use sp_std::{marker::PhantomData, vec::Vec}; #[cfg(feature = "runtime-benchmarks")] @@ -92,7 +93,8 @@ pub mod pallet { BoundedStorageValue<>::MaxParaHeadDataSize, ParaStoredHeaderData>; /// Weight info of the given parachains pallet. pub type WeightInfoOf = >::WeightInfo; - type GrandpaPalletOf = + /// Bridge GRANDPA pallet that is used to verify parachain proofs. + pub type GrandpaPalletOf = pallet_bridge_grandpa::Pallet>::BridgesGrandpaPalletInstance>; #[pallet::event] @@ -192,6 +194,21 @@ pub mod pallet { /// /// The GRANDPA pallet instance must be configured to import headers of relay chain that /// we're interested in. + /// + /// The associated GRANDPA pallet is also used to configure free parachain heads + /// submissions. The parachain head submission will be free if: + /// + /// 1) the submission contains exactly one parachain head update that succeeds; + /// + /// 2) the difference between relay chain block numbers, used to prove new parachain head + /// and previous best parachain head is larger than the `FreeHeadersInterval`, configured + /// at the associated GRANDPA pallet; + /// + /// 3) there are slots for free submissions, remaining at the block. This is also configured + /// at the associated GRANDPA pallet using `MaxFreeHeadersPerBlock` parameter. + /// + /// First parachain head submission is also free for the submitted, if free submissions + /// are yet accepted to this block. type BridgesGrandpaPalletInstance: 'static; /// Name of the original `paras` pallet in the `construct_runtime!()` call at the bridged @@ -335,10 +352,83 @@ pub mod pallet { at_relay_block: (RelayBlockNumber, RelayBlockHash), parachains: Vec<(ParaId, ParaHash)>, parachain_heads_proof: ParaHeadsProof, + ) -> DispatchResultWithPostInfo { + Self::submit_parachain_heads_ex( + origin, + at_relay_block, + parachains, + parachain_heads_proof, + false, + ) + } + + /// Change `PalletOwner`. + /// + /// May only be called either by root, or by `PalletOwner`. + #[pallet::call_index(1)] + #[pallet::weight((T::DbWeight::get().reads_writes(1, 1), DispatchClass::Operational))] + pub fn set_owner(origin: OriginFor, new_owner: Option) -> DispatchResult { + >::set_owner(origin, new_owner) + } + + /// Halt or resume all pallet operations. + /// + /// May only be called either by root, or by `PalletOwner`. + #[pallet::call_index(2)] + #[pallet::weight((T::DbWeight::get().reads_writes(1, 1), DispatchClass::Operational))] + pub fn set_operating_mode( + origin: OriginFor, + operating_mode: BasicOperatingMode, + ) -> DispatchResult { + >::set_operating_mode(origin, operating_mode) + } + + /// Submit proof of one or several parachain heads. + /// + /// The proof is supposed to be proof of some `Heads` entries from the + /// `polkadot-runtime-parachains::paras` pallet instance, deployed at the bridged chain. + /// The proof is supposed to be crafted at the `relay_header_hash` that must already be + /// imported by corresponding GRANDPA pallet at this chain. + /// + /// The call fails if: + /// + /// - the pallet is halted; + /// + /// - the relay chain block `at_relay_block` is not imported by the associated bridge + /// GRANDPA pallet. + /// + /// The call may succeed, but some heads may not be updated e.g. because pallet knows + /// better head or it isn't tracked by the pallet. + /// + /// The `is_free_execution_expected` parameter is not really used inside the call. It is + /// used by the transaction extension, which should be registered at the runtime level. If + /// this parameter is `true`, the transaction will be treated as invalid, if the call won't + /// be executed for free. If transaction extension is not used by the runtime, this + /// parameter is not used at all. + #[pallet::call_index(3)] + #[pallet::weight(WeightInfoOf::::submit_parachain_heads_weight( + T::DbWeight::get(), + parachain_heads_proof, + parachains.len() as _, + ))] + pub fn submit_parachain_heads_ex( + origin: OriginFor, + at_relay_block: (RelayBlockNumber, RelayBlockHash), + parachains: Vec<(ParaId, ParaHash)>, + parachain_heads_proof: ParaHeadsProof, + _is_free_execution_expected: bool, ) -> DispatchResultWithPostInfo { Self::ensure_not_halted().map_err(Error::::BridgeModule)?; ensure_signed(origin)?; + let total_parachains = parachains.len(); + let free_headers_interval = + T::FreeHeadersInterval::get().unwrap_or(RelayBlockNumber::MAX); + // the pallet allows two kind of free submissions + // 1) if distance between all parachain heads is gte than the [`T::FreeHeadersInterval`] + // 2) if all heads are the first heads of their parachains + let mut free_parachain_heads = 0; + // we'll need relay chain header to verify that parachains heads are always increasing. let (relay_block_number, relay_block_hash) = at_relay_block; let relay_block = pallet_bridge_grandpa::ImportedHeaders::< @@ -358,6 +448,7 @@ pub mod pallet { parachains.len() as _, ); + let mut is_updated_something = false; let mut storage = GrandpaPalletOf::::storage_proof_checker( relay_block_hash, parachain_heads_proof.storage_proof, @@ -414,6 +505,7 @@ pub mod pallet { } // convert from parachain head into stored parachain head data + let parachain_head_size = parachain_head.0.len(); let parachain_head_data = match T::ParaStoredHeaderDataBuilder::try_build(parachain, ¶chain_head) { Some(parachain_head_data) => parachain_head_data, @@ -430,13 +522,30 @@ pub mod pallet { let update_result: Result<_, ()> = ParasInfo::::try_mutate(parachain, |stored_best_head| { + let is_free = parachain_head_size < + T::ParaStoredHeaderDataBuilder::max_free_head_size() as usize && + match stored_best_head { + Some(ref best_head) + if at_relay_block.0.saturating_sub( + best_head.best_head_hash.at_relay_block_number, + ) >= free_headers_interval => + true, + Some(_) => false, + None => true, + }; let artifacts = Pallet::::update_parachain_head( parachain, stored_best_head.take(), - relay_block_number, + HeaderId(relay_block_number, relay_block_hash), parachain_head_data, parachain_head_hash, )?; + + is_updated_something = true; + if is_free { + free_parachain_heads = free_parachain_heads + 1; + } + *stored_best_head = Some(artifacts.best_head); Ok(artifacts.prune_happened) }); @@ -467,28 +576,21 @@ pub mod pallet { Error::::HeaderChainStorageProof(HeaderChainError::StorageProof(e)) })?; - Ok(PostDispatchInfo { actual_weight: Some(actual_weight), pays_fee: Pays::Yes }) - } - - /// Change `PalletOwner`. - /// - /// May only be called either by root, or by `PalletOwner`. - #[pallet::call_index(1)] - #[pallet::weight((T::DbWeight::get().reads_writes(1, 1), DispatchClass::Operational))] - pub fn set_owner(origin: OriginFor, new_owner: Option) -> DispatchResult { - >::set_owner(origin, new_owner) - } + // check if we allow this submission for free + let is_free = total_parachains == 1 + && free_parachain_heads == total_parachains + && SubmitFinalityProofHelper::::has_free_header_slots(); + let pays_fee = if is_free { + log::trace!(target: LOG_TARGET, "Parachain heads update transaction is free"); + pallet_bridge_grandpa::on_free_header_imported::( + ); + Pays::No + } else { + log::trace!(target: LOG_TARGET, "Parachain heads update transaction is paid"); + Pays::Yes + }; - /// Halt or resume all pallet operations. - /// - /// May only be called either by root, or by `PalletOwner`. - #[pallet::call_index(2)] - #[pallet::weight((T::DbWeight::get().reads_writes(1, 1), DispatchClass::Operational))] - pub fn set_operating_mode( - origin: OriginFor, - operating_mode: BasicOperatingMode, - ) -> DispatchResult { - >::set_operating_mode(origin, operating_mode) + Ok(PostDispatchInfo { actual_weight: Some(actual_weight), pays_fee }) } } @@ -545,18 +647,20 @@ pub mod pallet { pub(super) fn update_parachain_head( parachain: ParaId, stored_best_head: Option, - new_at_relay_block_number: RelayBlockNumber, + new_at_relay_block: HeaderId, new_head_data: ParaStoredHeaderData, new_head_hash: ParaHash, ) -> Result { // check if head has been already updated at better relay chain block. Without this // check, we may import heads in random order let update = SubmitParachainHeadsInfo { - at_relay_block_number: new_at_relay_block_number, + at_relay_block: new_at_relay_block, para_id: parachain, para_head_hash: new_head_hash, + // doesn't actually matter here + is_free_execution_expected: false, }; - if SubmitParachainHeadsHelper::::is_obsolete(&update) { + if SubmitParachainHeadsHelper::::check_obsolete(&update).is_err() { Self::deposit_event(Event::RejectedObsoleteParachainHead { parachain, parachain_head_hash: new_head_hash, @@ -596,7 +700,7 @@ pub mod pallet { ImportedParaHashes::::try_get(parachain, next_imported_hash_position); let updated_best_para_head = ParaInfo { best_head_hash: BestParaHeadHash { - at_relay_block_number: new_at_relay_block_number, + at_relay_block_number: new_at_relay_block.0, head_hash: new_head_hash, }, next_imported_hash_position: (next_imported_hash_position + 1) % @@ -610,9 +714,10 @@ pub mod pallet { ImportedParaHeads::::insert(parachain, new_head_hash, updated_head_data); log::trace!( target: LOG_TARGET, - "Updated head of parachain {:?} to {}", + "Updated head of parachain {:?} to {} at relay block {}", parachain, new_head_hash, + new_at_relay_block.0, ); // remove old head @@ -696,14 +801,28 @@ impl, I: 'static, C: Parachain> HeaderChain pub fn initialize_for_benchmarks, I: 'static, PC: Parachain>( header: HeaderOf, ) { + use bp_runtime::HeaderIdProvider; + use sp_runtime::traits::Header; + + let relay_head = + pallet_bridge_grandpa::BridgedHeader::::new( + 0, + Default::default(), + Default::default(), + Default::default(), + Default::default(), + ); let parachain = ParaId(PC::PARACHAIN_ID); let parachain_head = ParaHead(header.encode()); let updated_head_data = T::ParaStoredHeaderDataBuilder::try_build(parachain, ¶chain_head) .expect("failed to build stored parachain head in benchmarks"); + pallet_bridge_grandpa::initialize_for_benchmarks::( + relay_head.clone(), + ); Pallet::::update_parachain_head( parachain, None, - 0, + relay_head.id(), updated_head_data, parachain_head.hash(), ) @@ -714,9 +833,9 @@ pub fn initialize_for_benchmarks, I: 'static, PC: Parachain::DbWeight; pub(crate) fn initialize(state_root: RelayBlockHash) -> RelayBlockHash { + pallet_bridge_grandpa::FreeHeadersRemaining::::set(Some(100)); pallet_bridge_grandpa::Pallet::::initialize( RuntimeOrigin::root(), bp_header_chain::InitializationData { @@ -770,10 +891,6 @@ pub(crate) mod tests { num: RelayBlockNumber, state_root: RelayBlockHash, ) -> (ParaHash, GrandpaJustification) { - pallet_bridge_grandpa::Pallet::::on_initialize( - 0, - ); - let header = test_relay_header(num, state_root); let hash = header.hash(); let justification = make_default_justification(&header); @@ -783,6 +900,7 @@ pub(crate) mod tests { Box::new(header), justification.clone(), TEST_GRANDPA_SET_ID, + false, ) ); @@ -908,7 +1026,7 @@ pub(crate) mod tests { run_test(|| { initialize(state_root); - // we're trying to update heads of parachains 1, 2 and 3 + // we're trying to update heads of parachains 1 and 3 let expected_weight = WeightInfo::submit_parachain_heads_weight(DbWeight::get(), &proof, 2); let result = Pallet::::submit_parachain_heads( @@ -918,9 +1036,10 @@ pub(crate) mod tests { proof, ); assert_ok!(result); + assert_eq!(result.expect("checked above").pays_fee, Pays::Yes); assert_eq!(result.expect("checked above").actual_weight, Some(expected_weight)); - // but only 1 and 2 are updated, because proof is missing head of parachain#2 + // 1 and 3 are updated, because proof is missing head of parachain#2 assert_eq!(ParasInfo::::get(ParaId(1)), Some(initial_best_head(1))); assert_eq!(ParasInfo::::get(ParaId(2)), None); assert_eq!( @@ -989,7 +1108,9 @@ pub(crate) mod tests { run_test(|| { // start with relay block #0 and import head#5 of parachain#1 initialize(state_root_5); - assert_ok!(import_parachain_1_head(0, state_root_5, parachains_5, proof_5)); + let result = import_parachain_1_head(0, state_root_5, parachains_5, proof_5); + // first parachain head is imported for free + assert_eq!(result.unwrap().pays_fee, Pays::No); assert_eq!( ParasInfo::::get(ParaId(1)), Some(ParaInfo { @@ -1024,7 +1145,9 @@ pub(crate) mod tests { // import head#10 of parachain#1 at relay block #1 let (relay_1_hash, justification) = proceed(1, state_root_10); - assert_ok!(import_parachain_1_head(1, state_root_10, parachains_10, proof_10)); + let result = import_parachain_1_head(1, state_root_10, parachains_10, proof_10); + // second parachain head is imported for fee + assert_eq!(result.unwrap().pays_fee, Pays::Yes); assert_eq!( ParasInfo::::get(ParaId(1)), Some(ParaInfo { @@ -1647,4 +1770,143 @@ pub(crate) mod tests { ); }) } + + #[test] + fn may_be_free_for_submitting_filtered_heads() { + run_test(|| { + let (state_root, proof, parachains) = + prepare_parachain_heads_proof::(vec![(2, head_data(2, 5))]); + // start with relay block #0 and import head#5 of parachain#2 + initialize(state_root); + // first submission is free + let result = Pallet::::submit_parachain_heads( + RuntimeOrigin::signed(1), + (0, test_relay_header(0, state_root).hash()), + parachains.clone(), + proof.clone(), + ); + assert_eq!(result.unwrap().pays_fee, Pays::No); + // next submission is NOT free, because we haven't updated anything + let result = Pallet::::submit_parachain_heads( + RuntimeOrigin::signed(1), + (0, test_relay_header(0, state_root).hash()), + parachains, + proof, + ); + assert_eq!(result.unwrap().pays_fee, Pays::Yes); + // then we submit new head, proved at relay block `FreeHeadersInterval - 1` => Pays::Yes + let (state_root, proof, parachains) = prepare_parachain_heads_proof::< + RegularParachainHeader, + >(vec![(2, head_data(2, 50))]); + let relay_block_number = FreeHeadersInterval::get() - 1; + proceed(relay_block_number, state_root); + let result = Pallet::::submit_parachain_heads( + RuntimeOrigin::signed(1), + (relay_block_number, test_relay_header(relay_block_number, state_root).hash()), + parachains, + proof, + ); + assert_eq!(result.unwrap().pays_fee, Pays::Yes); + // then we submit new head, proved after `FreeHeadersInterval` => Pays::No + let (state_root, proof, parachains) = prepare_parachain_heads_proof::< + RegularParachainHeader, + >(vec![(2, head_data(2, 100))]); + let relay_block_number = relay_block_number + FreeHeadersInterval::get(); + proceed(relay_block_number, state_root); + let result = Pallet::::submit_parachain_heads( + RuntimeOrigin::signed(1), + (relay_block_number, test_relay_header(relay_block_number, state_root).hash()), + parachains, + proof, + ); + assert_eq!(result.unwrap().pays_fee, Pays::No); + // then we submit new BIG head, proved after `FreeHeadersInterval` => Pays::Yes + // then we submit new head, proved after `FreeHeadersInterval` => Pays::No + let mut large_head = head_data(2, 100); + large_head.0.extend(&[42u8; BigParachain::MAX_HEADER_SIZE as _]); + let (state_root, proof, parachains) = + prepare_parachain_heads_proof::(vec![(2, large_head)]); + let relay_block_number = relay_block_number + FreeHeadersInterval::get(); + proceed(relay_block_number, state_root); + let result = Pallet::::submit_parachain_heads( + RuntimeOrigin::signed(1), + (relay_block_number, test_relay_header(relay_block_number, state_root).hash()), + parachains, + proof, + ); + assert_eq!(result.unwrap().pays_fee, Pays::Yes); + }) + } + + #[test] + fn grandpa_and_parachain_pallets_share_free_headers_counter() { + run_test(|| { + initialize(Default::default()); + // set free headers limit to `4` + let mut free_headers_remaining = 4; + pallet_bridge_grandpa::FreeHeadersRemaining::::set( + Some(free_headers_remaining), + ); + // import free GRANDPA and parachain headers + let mut relay_block_number = 0; + for i in 0..2 { + // import free GRANDPA header + let (state_root, proof, parachains) = prepare_parachain_heads_proof::< + RegularParachainHeader, + >(vec![(2, head_data(2, 5 + i))]); + relay_block_number = relay_block_number + FreeHeadersInterval::get(); + proceed(relay_block_number, state_root); + assert_eq!( + pallet_bridge_grandpa::FreeHeadersRemaining::< + TestRuntime, + BridgesGrandpaPalletInstance, + >::get(), + Some(free_headers_remaining - 1), + ); + free_headers_remaining = free_headers_remaining - 1; + // import free parachain header + assert_ok!(Pallet::::submit_parachain_heads( + RuntimeOrigin::signed(1), + (relay_block_number, test_relay_header(relay_block_number, state_root).hash()), + parachains, + proof, + ),); + assert_eq!( + pallet_bridge_grandpa::FreeHeadersRemaining::< + TestRuntime, + BridgesGrandpaPalletInstance, + >::get(), + Some(free_headers_remaining - 1), + ); + free_headers_remaining = free_headers_remaining - 1; + } + // try to import free GRANDPA header => non-free execution + let (state_root, proof, parachains) = + prepare_parachain_heads_proof::(vec![(2, head_data(2, 7))]); + relay_block_number = relay_block_number + FreeHeadersInterval::get(); + let result = pallet_bridge_grandpa::Pallet::::submit_finality_proof_ex( + RuntimeOrigin::signed(1), + Box::new(test_relay_header(relay_block_number, state_root)), + make_default_justification(&test_relay_header(relay_block_number, state_root)), + TEST_GRANDPA_SET_ID, + false, + ); + assert_eq!(result.unwrap().pays_fee, Pays::Yes); + // try to import free parachain header => non-free execution + let result = Pallet::::submit_parachain_heads( + RuntimeOrigin::signed(1), + (relay_block_number, test_relay_header(relay_block_number, state_root).hash()), + parachains, + proof, + ); + assert_eq!(result.unwrap().pays_fee, Pays::Yes); + assert_eq!( + pallet_bridge_grandpa::FreeHeadersRemaining::< + TestRuntime, + BridgesGrandpaPalletInstance, + >::get(), + Some(0), + ); + }); + } } diff --git a/bridges/modules/parachains/src/mock.rs b/bridges/modules/parachains/src/mock.rs index d9cbabf850ec99ee13baa0f8bfc013b1192bd000..dbb62845392d5fd2f408744f4f8a2321ec4bd34d 100644 --- a/bridges/modules/parachains/src/mock.rs +++ b/bridges/modules/parachains/src/mock.rs @@ -70,6 +70,7 @@ impl Chain for Parachain1 { impl Parachain for Parachain1 { const PARACHAIN_ID: u32 = 1; + const MAX_HEADER_SIZE: u32 = 1_024; } pub struct Parachain2; @@ -96,6 +97,7 @@ impl Chain for Parachain2 { impl Parachain for Parachain2 { const PARACHAIN_ID: u32 = 2; + const MAX_HEADER_SIZE: u32 = 1_024; } pub struct Parachain3; @@ -122,6 +124,7 @@ impl Chain for Parachain3 { impl Parachain for Parachain3 { const PARACHAIN_ID: u32 = 3; + const MAX_HEADER_SIZE: u32 = 1_024; } // this parachain is using u128 as block number and stored head data size exceeds limit @@ -149,6 +152,7 @@ impl Chain for BigParachain { impl Parachain for BigParachain { const PARACHAIN_ID: u32 = 4; + const MAX_HEADER_SIZE: u32 = 2_048; } construct_runtime! { @@ -168,12 +172,14 @@ impl frame_system::Config for TestRuntime { parameter_types! { pub const HeadersToKeep: u32 = 5; + pub const FreeHeadersInterval: u32 = 15; } impl pallet_bridge_grandpa::Config for TestRuntime { type RuntimeEvent = RuntimeEvent; type BridgedChain = TestBridgedChain; - type MaxFreeMandatoryHeadersPerBlock = ConstU32<2>; + type MaxFreeHeadersPerBlock = ConstU32<2>; + type FreeHeadersInterval = FreeHeadersInterval; type HeadersToKeep = HeadersToKeep; type WeightInfo = (); } @@ -181,7 +187,8 @@ impl pallet_bridge_grandpa::Config for TestRun impl pallet_bridge_grandpa::Config for TestRuntime { type RuntimeEvent = RuntimeEvent; type BridgedChain = TestBridgedChain; - type MaxFreeMandatoryHeadersPerBlock = ConstU32<2>; + type MaxFreeHeadersPerBlock = ConstU32<2>; + type FreeHeadersInterval = FreeHeadersInterval; type HeadersToKeep = HeadersToKeep; type WeightInfo = (); } diff --git a/bridges/modules/parachains/src/weights_ext.rs b/bridges/modules/parachains/src/weights_ext.rs index 393086a85690fcc2846c1708bc788e1d67a61d66..64dad625de08b3fd0cd96c255ee80fafa8df2be9 100644 --- a/bridges/modules/parachains/src/weights_ext.rs +++ b/bridges/modules/parachains/src/weights_ext.rs @@ -36,6 +36,20 @@ pub const EXTRA_STORAGE_PROOF_SIZE: u32 = 1024; /// Extended weight info. pub trait WeightInfoExt: WeightInfo { + // Our configuration assumes that the runtime has special signed extensions used to: + // + // 1) boost priority of `submit_parachain_heads` transactions; + // + // 2) slash relayer if he submits an invalid transaction. + // + // We read and update storage values of other pallets (`pallet-bridge-relayers` and + // balances/assets pallet). So we need to add this weight to the weight of our call. + // Hence two following methods. + + /// Extra weight that is added to the `submit_finality_proof` call weight by signed extensions + /// that are declared at runtime level. + fn submit_parachain_heads_overhead_from_runtime() -> Weight; + /// Storage proof overhead, that is included in every storage proof. /// /// The relayer would pay some extra fee for additional proof bytes, since they mean @@ -65,7 +79,10 @@ pub trait WeightInfoExt: WeightInfo { let pruning_weight = Self::parachain_head_pruning_weight(db_weight).saturating_mul(parachains_count as u64); - base_weight.saturating_add(proof_size_overhead).saturating_add(pruning_weight) + base_weight + .saturating_add(proof_size_overhead) + .saturating_add(pruning_weight) + .saturating_add(Self::submit_parachain_heads_overhead_from_runtime()) } /// Returns weight of single parachain head storage update. @@ -95,12 +112,20 @@ pub trait WeightInfoExt: WeightInfo { } impl WeightInfoExt for () { + fn submit_parachain_heads_overhead_from_runtime() -> Weight { + Weight::zero() + } + fn expected_extra_storage_proof_size() -> u32 { EXTRA_STORAGE_PROOF_SIZE } } impl WeightInfoExt for BridgeWeight { + fn submit_parachain_heads_overhead_from_runtime() -> Weight { + Weight::zero() + } + fn expected_extra_storage_proof_size() -> u32 { EXTRA_STORAGE_PROOF_SIZE } diff --git a/bridges/modules/relayers/Cargo.toml b/bridges/modules/relayers/Cargo.toml index e2b7aca92249c19096bf129be6fab1be08a5357a..08e1438d4f1946fb41f614b0e94c0ce6f1611fd5 100644 --- a/bridges/modules/relayers/Cargo.toml +++ b/bridges/modules/relayers/Cargo.toml @@ -11,7 +11,7 @@ repository.workspace = true workspace = true [dependencies] -codec = { package = "parity-scale-codec", version = "3.6.1", default-features = false } +codec = { package = "parity-scale-codec", version = "3.6.12", default-features = false } log = { workspace = true } scale-info = { version = "2.11.1", default-features = false, features = ["derive"] } diff --git a/bridges/modules/xcm-bridge-hub-router/Cargo.toml b/bridges/modules/xcm-bridge-hub-router/Cargo.toml index 06f2a339bed9d07b5615ca047177228d6585cfc2..b80240c974de9f5874e2825f5506885fea11ef3a 100644 --- a/bridges/modules/xcm-bridge-hub-router/Cargo.toml +++ b/bridges/modules/xcm-bridge-hub-router/Cargo.toml @@ -11,7 +11,7 @@ repository.workspace = true workspace = true [dependencies] -codec = { package = "parity-scale-codec", version = "3.6.1", default-features = false } +codec = { package = "parity-scale-codec", version = "3.6.12", default-features = false } log = { workspace = true } scale-info = { version = "2.11.1", default-features = false, features = ["bit-vec", "derive", "serde"] } diff --git a/bridges/modules/xcm-bridge-hub-router/src/lib.rs b/bridges/modules/xcm-bridge-hub-router/src/lib.rs index c6008802ae9a50c02ec54d981e5bd503ff659816..607394603466e6cb60d20dbefa4aa47580b54c42 100644 --- a/bridges/modules/xcm-bridge-hub-router/src/lib.rs +++ b/bridges/modules/xcm-bridge-hub-router/src/lib.rs @@ -37,8 +37,9 @@ use codec::Encode; use frame_support::traits::Get; use sp_core::H256; use sp_runtime::{FixedPointNumber, FixedU128, Saturating}; +use sp_std::vec::Vec; use xcm::prelude::*; -use xcm_builder::{ExporterFor, SovereignPaidRemoteExporter}; +use xcm_builder::{ExporterFor, InspectMessageQueues, SovereignPaidRemoteExporter}; pub use pallet::*; pub use weights::WeightInfo; @@ -95,7 +96,7 @@ pub mod pallet { /// Origin of the sibling bridge hub that is allowed to report bridge status. type BridgeHubOrigin: EnsureOrigin; /// Actual message sender (`HRMP` or `DMP`) to the sibling bridge hub location. - type ToBridgeHubSender: SendXcm; + type ToBridgeHubSender: SendXcm + InspectMessageQueues; /// Underlying channel with the sibling bridge hub. It must match the channel, used /// by the `Self::ToBridgeHubSender`. type WithBridgeHubChannel: XcmChannelStatusProvider; @@ -328,40 +329,58 @@ impl, I: 'static> SendXcm for Pallet { xcm: &mut Option>, ) -> SendResult { log::trace!(target: LOG_TARGET, "validate - msg: {xcm:?}, destination: {dest:?}"); - // `dest` and `xcm` are required here - let dest_ref = dest.as_ref().ok_or(SendError::MissingArgument)?; - let xcm_ref = xcm.as_ref().ok_or(SendError::MissingArgument)?; - - // we won't have an access to `dest` and `xcm` in the `deliver` method, so precompute - // everything required here - let message_size = xcm_ref.encoded_size() as _; - - // bridge doesn't support oversized/overweight messages now. So it is better to drop such - // messages here than at the bridge hub. Let's check the message size. - if message_size > HARD_MESSAGE_SIZE_LIMIT { - return Err(SendError::ExceedsMaxMessageSize) - } - // We need to ensure that the known `dest`'s XCM version can comprehend the current `xcm` - // program. This may seem like an additional, unnecessary check, but it is not. A similar - // check is probably performed by the `ViaBridgeHubExporter`, which attempts to send a - // versioned message to the sibling bridge hub. However, the local bridge hub may have a - // higher XCM version than the remote `dest`. Once again, it is better to discard such - // messages here than at the bridge hub (e.g., to avoid losing funds). - let destination_version = T::DestinationVersion::get_version_for(dest_ref) - .ok_or(SendError::DestinationUnsupported)?; - let _ = VersionedXcm::from(xcm_ref.clone()) - .into_version(destination_version) - .map_err(|()| SendError::DestinationUnsupported)?; - - // just use exporter to validate destination and insert instructions to pay message fee - // at the sibling/child bridge hub - // - // the cost will include both cost of: (1) to-sibling bridge hub delivery (returned by - // the `Config::ToBridgeHubSender`) and (2) to-bridged bridge hub delivery (returned by - // `Self::exporter_for`) - ViaBridgeHubExporter::::validate(dest, xcm) - .map(|(ticket, cost)| ((message_size, ticket), cost)) + // In case of success, the `ViaBridgeHubExporter` can modify XCM instructions and consume + // `dest` / `xcm`, so we retain the clone of original message and the destination for later + // `DestinationVersion` validation. + let xcm_to_dest_clone = xcm.clone(); + let dest_clone = dest.clone(); + + // First, use the inner exporter to validate the destination to determine if it is even + // routable. If it is not, return an error. If it is, then the XCM is extended with + // instructions to pay the message fee at the sibling/child bridge hub. The cost will + // include both the cost of (1) delivery to the sibling bridge hub (returned by + // `Config::ToBridgeHubSender`) and (2) delivery to the bridged bridge hub (returned by + // `Self::exporter_for`). + match ViaBridgeHubExporter::::validate(dest, xcm) { + Ok((ticket, cost)) => { + // If the ticket is ok, it means we are routing with this router, so we need to + // apply more validations to the cloned `dest` and `xcm`, which are required here. + let xcm_to_dest_clone = xcm_to_dest_clone.ok_or(SendError::MissingArgument)?; + let dest_clone = dest_clone.ok_or(SendError::MissingArgument)?; + + // We won't have access to `dest` and `xcm` in the `deliver` method, so we need to + // precompute everything required here. However, `dest` and `xcm` were consumed by + // `ViaBridgeHubExporter`, so we need to use their clones. + let message_size = xcm_to_dest_clone.encoded_size() as _; + + // The bridge doesn't support oversized or overweight messages. Therefore, it's + // better to drop such messages here rather than at the bridge hub. Let's check the + // message size." + if message_size > HARD_MESSAGE_SIZE_LIMIT { + return Err(SendError::ExceedsMaxMessageSize) + } + + // We need to ensure that the known `dest`'s XCM version can comprehend the current + // `xcm` program. This may seem like an additional, unnecessary check, but it is + // not. A similar check is probably performed by the `ViaBridgeHubExporter`, which + // attempts to send a versioned message to the sibling bridge hub. However, the + // local bridge hub may have a higher XCM version than the remote `dest`. Once + // again, it is better to discard such messages here than at the bridge hub (e.g., + // to avoid losing funds). + let destination_version = T::DestinationVersion::get_version_for(&dest_clone) + .ok_or(SendError::DestinationUnsupported)?; + let _ = VersionedXcm::from(xcm_to_dest_clone) + .into_version(destination_version) + .map_err(|()| SendError::DestinationUnsupported)?; + + Ok(((message_size, ticket), cost)) + }, + Err(e) => { + log::trace!(target: LOG_TARGET, "validate - ViaBridgeHubExporter - error: {e:?}"); + Err(e) + }, + } } fn deliver(ticket: Self::Ticket) -> Result { @@ -378,6 +397,12 @@ impl, I: 'static> SendXcm for Pallet { } } +impl, I: 'static> InspectMessageQueues for Pallet { + fn get_messages() -> Vec<(VersionedLocation, Vec>)> { + ViaBridgeHubExporter::::get_messages() + } +} + #[cfg(test)] mod tests { use super::*; @@ -452,24 +477,51 @@ mod tests { #[test] fn not_applicable_if_destination_is_within_other_network() { run_test(|| { + // unroutable dest + let dest = Location::new(2, [GlobalConsensus(ByGenesis([0; 32])), Parachain(1000)]); + let xcm: Xcm<()> = vec![ClearOrigin].into(); + + // check that router does not consume when `NotApplicable` + let mut xcm_wrapper = Some(xcm.clone()); assert_eq!( - send_xcm::( - Location::new(2, [GlobalConsensus(Rococo), Parachain(1000)]), - vec![].into(), - ), + XcmBridgeHubRouter::validate(&mut Some(dest.clone()), &mut xcm_wrapper), Err(SendError::NotApplicable), ); + // XCM is NOT consumed and untouched + assert_eq!(Some(xcm.clone()), xcm_wrapper); + + // check the full `send_xcm` + assert_eq!(send_xcm::(dest, xcm,), Err(SendError::NotApplicable),); }); } #[test] fn exceeds_max_message_size_if_size_is_above_hard_limit() { run_test(|| { + // routable dest with XCM version + let dest = + Location::new(2, [GlobalConsensus(BridgedNetworkId::get()), Parachain(1000)]); + // oversized XCM + let xcm: Xcm<()> = vec![ClearOrigin; HARD_MESSAGE_SIZE_LIMIT as usize].into(); + + // dest is routable with the inner router + assert_ok!(ViaBridgeHubExporter::::validate( + &mut Some(dest.clone()), + &mut Some(xcm.clone()) + )); + + // check for oversized message + let mut xcm_wrapper = Some(xcm.clone()); + assert_eq!( + XcmBridgeHubRouter::validate(&mut Some(dest.clone()), &mut xcm_wrapper), + Err(SendError::ExceedsMaxMessageSize), + ); + // XCM is consumed by the inner router + assert!(xcm_wrapper.is_none()); + + // check the full `send_xcm` assert_eq!( - send_xcm::( - Location::new(2, [GlobalConsensus(Rococo), Parachain(1000)]), - vec![ClearOrigin; HARD_MESSAGE_SIZE_LIMIT as usize].into(), - ), + send_xcm::(dest, xcm,), Err(SendError::ExceedsMaxMessageSize), ); }); @@ -478,11 +530,28 @@ mod tests { #[test] fn destination_unsupported_if_wrap_version_fails() { run_test(|| { + // routable dest but we don't know XCM version + let dest = UnknownXcmVersionForRoutableLocation::get(); + let xcm: Xcm<()> = vec![ClearOrigin].into(); + + // dest is routable with the inner router + assert_ok!(ViaBridgeHubExporter::::validate( + &mut Some(dest.clone()), + &mut Some(xcm.clone()) + )); + + // check that it does not pass XCM version check + let mut xcm_wrapper = Some(xcm.clone()); + assert_eq!( + XcmBridgeHubRouter::validate(&mut Some(dest.clone()), &mut xcm_wrapper), + Err(SendError::DestinationUnsupported), + ); + // XCM is consumed by the inner router + assert!(xcm_wrapper.is_none()); + + // check the full `send_xcm` assert_eq!( - send_xcm::( - UnknownXcmVersionLocation::get(), - vec![ClearOrigin].into(), - ), + send_xcm::(dest, xcm,), Err(SendError::DestinationUnsupported), ); }); @@ -573,4 +642,36 @@ mod tests { ); }); } + + #[test] + fn get_messages_works() { + run_test(|| { + assert_ok!(send_xcm::( + (Parent, Parent, GlobalConsensus(BridgedNetworkId::get()), Parachain(1000)).into(), + vec![ClearOrigin].into() + )); + assert_eq!( + XcmBridgeHubRouter::get_messages(), + vec![( + VersionedLocation::V4((Parent, Parachain(1002)).into()), + vec![VersionedXcm::V4( + Xcm::builder() + .withdraw_asset((Parent, 1_002_000)) + .buy_execution((Parent, 1_002_000), Unlimited) + .set_appendix( + Xcm::builder_unsafe() + .deposit_asset(AllCounted(1), (Parent, Parachain(1000))) + .build() + ) + .export_message( + Kusama, + Parachain(1000), + Xcm::builder_unsafe().clear_origin().build() + ) + .build() + )], + ),], + ); + }); + } } diff --git a/bridges/modules/xcm-bridge-hub-router/src/mock.rs b/bridges/modules/xcm-bridge-hub-router/src/mock.rs index 54e10966d51b23e7be5010b39cb9cb7d6a3b0118..3e2c1bb369cb72439e53e492cf638a404caa99a3 100644 --- a/bridges/modules/xcm-bridge-hub-router/src/mock.rs +++ b/bridges/modules/xcm-bridge-hub-router/src/mock.rs @@ -19,14 +19,16 @@ use crate as pallet_xcm_bridge_hub_router; use bp_xcm_bridge_hub_router::XcmChannelStatusProvider; +use codec::Encode; use frame_support::{ construct_runtime, derive_impl, parameter_types, traits::{Contains, Equals}, }; use frame_system::EnsureRoot; use sp_runtime::{traits::ConstU128, BuildStorage}; +use sp_std::cell::RefCell; use xcm::prelude::*; -use xcm_builder::{NetworkExportTable, NetworkExportTableItem}; +use xcm_builder::{InspectMessageQueues, NetworkExportTable, NetworkExportTableItem}; pub type AccountId = u64; type Block = frame_system::mocking::MockBlock; @@ -61,7 +63,7 @@ parameter_types! { Some((BridgeFeeAsset::get(), BASE_FEE).into()) ) ]; - pub UnknownXcmVersionLocation: Location = Location::new(2, [GlobalConsensus(BridgedNetworkId::get()), Parachain(9999)]); + pub UnknownXcmVersionForRoutableLocation: Location = Location::new(2, [GlobalConsensus(BridgedNetworkId::get()), Parachain(9999)]); } #[derive_impl(frame_system::config_preludes::TestDefaultConfig)] @@ -76,7 +78,7 @@ impl pallet_xcm_bridge_hub_router::Config<()> for TestRuntime { type BridgedNetworkId = BridgedNetworkId; type Bridges = NetworkExportTable; type DestinationVersion = - LatestOrNoneForLocationVersionChecker>; + LatestOrNoneForLocationVersionChecker>; type BridgeHubOrigin = EnsureRoot; type ToBridgeHubSender = TestToBridgeHubSender; @@ -102,23 +104,46 @@ pub struct TestToBridgeHubSender; impl TestToBridgeHubSender { pub fn is_message_sent() -> bool { - frame_support::storage::unhashed::get_or_default(b"TestToBridgeHubSender.Sent") + !Self::get_messages().is_empty() } } +thread_local! { + pub static SENT_XCM: RefCell)>> = RefCell::new(Vec::new()); +} + impl SendXcm for TestToBridgeHubSender { - type Ticket = (); + type Ticket = (Location, Xcm<()>); fn validate( - _destination: &mut Option, - _message: &mut Option>, + destination: &mut Option, + message: &mut Option>, ) -> SendResult { - Ok(((), (BridgeFeeAsset::get(), HRMP_FEE).into())) + let pair = (destination.take().unwrap(), message.take().unwrap()); + Ok((pair, (BridgeFeeAsset::get(), HRMP_FEE).into())) } - fn deliver(_ticket: Self::Ticket) -> Result { - frame_support::storage::unhashed::put(b"TestToBridgeHubSender.Sent", &true); - Ok([0u8; 32]) + fn deliver(pair: Self::Ticket) -> Result { + let hash = fake_message_hash(&pair.1); + SENT_XCM.with(|q| q.borrow_mut().push(pair)); + Ok(hash) + } +} + +impl InspectMessageQueues for TestToBridgeHubSender { + fn get_messages() -> Vec<(VersionedLocation, Vec>)> { + SENT_XCM.with(|q| { + (*q.borrow()) + .clone() + .iter() + .map(|(location, message)| { + ( + VersionedLocation::V4(location.clone()), + vec![VersionedXcm::V4(message.clone())], + ) + }) + .collect() + }) } } @@ -146,3 +171,7 @@ pub fn new_test_ext() -> sp_io::TestExternalities { pub fn run_test(test: impl FnOnce() -> T) -> T { new_test_ext().execute_with(test) } + +pub(crate) fn fake_message_hash(message: &Xcm) -> XcmHash { + message.using_encoded(sp_io::hashing::blake2_256) +} diff --git a/bridges/modules/xcm-bridge-hub/Cargo.toml b/bridges/modules/xcm-bridge-hub/Cargo.toml index 4483a3790900f975030e8c820f9b42442a747262..9b22770061a9a9ffd981f186de9231d7ff41cde9 100644 --- a/bridges/modules/xcm-bridge-hub/Cargo.toml +++ b/bridges/modules/xcm-bridge-hub/Cargo.toml @@ -11,7 +11,7 @@ repository.workspace = true workspace = true [dependencies] -codec = { package = "parity-scale-codec", version = "3.6.1", default-features = false } +codec = { package = "parity-scale-codec", version = "3.6.12", default-features = false } log = { workspace = true } scale-info = { version = "2.11.1", default-features = false, features = ["derive"] } diff --git a/bridges/primitives/beefy/Cargo.toml b/bridges/primitives/beefy/Cargo.toml index 2a13685207cc633fe18633525231866511afd01e..bd68076ca48fc8ccc7bb8f48611083c0930731f7 100644 --- a/bridges/primitives/beefy/Cargo.toml +++ b/bridges/primitives/beefy/Cargo.toml @@ -12,7 +12,7 @@ publish = false workspace = true [dependencies] -codec = { package = "parity-scale-codec", version = "3.6.1", default-features = false, features = ["bit-vec", "derive"] } +codec = { package = "parity-scale-codec", version = "3.6.12", default-features = false, features = ["bit-vec", "derive"] } scale-info = { version = "2.11.1", default-features = false, features = ["bit-vec", "derive"] } serde = { default-features = false, features = ["alloc", "derive"], workspace = true } diff --git a/bridges/primitives/beefy/src/lib.rs b/bridges/primitives/beefy/src/lib.rs index 0441781e79a66f785b985047ad56da70c0f13d49..2494706818ef14c11a8193983164e65a510a80e6 100644 --- a/bridges/primitives/beefy/src/lib.rs +++ b/bridges/primitives/beefy/src/lib.rs @@ -22,7 +22,7 @@ pub use binary_merkle_tree::merkle_root; pub use pallet_beefy_mmr::BeefyEcdsaToEthereum; pub use pallet_mmr::{ - primitives::{DataOrHash as MmrDataOrHash, Proof as MmrProof}, + primitives::{DataOrHash as MmrDataOrHash, LeafProof as MmrProof}, verify_leaves_proof as verify_mmr_leaves_proof, }; pub use sp_consensus_beefy::{ diff --git a/bridges/primitives/header-chain/Cargo.toml b/bridges/primitives/header-chain/Cargo.toml index f7a61a9ff32bd42f4199859834b6296aeaa18f4a..def1f7ad4dfefb14c3f8459a3d2960c3890ddcf8 100644 --- a/bridges/primitives/header-chain/Cargo.toml +++ b/bridges/primitives/header-chain/Cargo.toml @@ -11,7 +11,7 @@ repository.workspace = true workspace = true [dependencies] -codec = { package = "parity-scale-codec", version = "3.6.1", default-features = false } +codec = { package = "parity-scale-codec", version = "3.6.12", default-features = false } finality-grandpa = { version = "0.16.2", default-features = false } scale-info = { version = "2.11.1", default-features = false, features = ["derive"] } serde = { features = ["alloc", "derive"], workspace = true } diff --git a/bridges/primitives/header-chain/src/lib.rs b/bridges/primitives/header-chain/src/lib.rs index 98fb9ff83d8335fc04fbce7f9e566c73d15752a8..ad496012c6a3f95d636a2c1ae52fcb5f4ec5434d 100644 --- a/bridges/primitives/header-chain/src/lib.rs +++ b/bridges/primitives/header-chain/src/lib.rs @@ -32,7 +32,9 @@ use core::{clone::Clone, cmp::Eq, default::Default, fmt::Debug}; use frame_support::PalletError; use scale_info::TypeInfo; use serde::{Deserialize, Serialize}; -use sp_consensus_grandpa::{AuthorityList, ConsensusLog, SetId, GRANDPA_ENGINE_ID}; +use sp_consensus_grandpa::{ + AuthorityList, ConsensusLog, ScheduledChange, SetId, GRANDPA_ENGINE_ID, +}; use sp_runtime::{traits::Header as HeaderT, Digest, RuntimeDebug}; use sp_std::{boxed::Box, vec::Vec}; @@ -147,24 +149,23 @@ pub struct GrandpaConsensusLogReader(sp_std::marker::PhantomData impl GrandpaConsensusLogReader { /// Find and return scheduled (regular) change digest item. - pub fn find_scheduled_change( - digest: &Digest, - ) -> Option> { + pub fn find_scheduled_change(digest: &Digest) -> Option> { + use sp_runtime::generic::OpaqueDigestItemId; + let id = OpaqueDigestItemId::Consensus(&GRANDPA_ENGINE_ID); + + let filter_log = |log: ConsensusLog| match log { + ConsensusLog::ScheduledChange(change) => Some(change), + _ => None, + }; + // find the first consensus digest with the right ID which converts to // the right kind of consensus log. - digest - .convert_first(|log| log.consensus_try_to(&GRANDPA_ENGINE_ID)) - .and_then(|log| match log { - ConsensusLog::ScheduledChange(change) => Some(change), - _ => None, - }) + digest.convert_first(|l| l.try_to(id).and_then(filter_log)) } /// Find and return forced change digest item. Or light client can't do anything /// with forced changes, so we can't accept header with the forced change digest. - pub fn find_forced_change( - digest: &Digest, - ) -> Option<(Number, sp_consensus_grandpa::ScheduledChange)> { + pub fn find_forced_change(digest: &Digest) -> Option<(Number, ScheduledChange)> { // find the first consensus digest with the right ID which converts to // the right kind of consensus log. digest @@ -346,7 +347,7 @@ mod tests { use super::*; use bp_runtime::ChainId; use frame_support::weights::Weight; - use sp_runtime::{testing::H256, traits::BlakeTwo256, MultiSignature}; + use sp_runtime::{testing::H256, traits::BlakeTwo256, DigestItem, MultiSignature}; struct TestChain; @@ -385,4 +386,35 @@ mod tests { max_expected_submit_finality_proof_arguments_size::(false, 100), ); } + + #[test] + fn find_scheduled_change_works() { + let scheduled_change = ScheduledChange { next_authorities: vec![], delay: 0 }; + + // first + let mut digest = Digest::default(); + digest.push(DigestItem::Consensus( + GRANDPA_ENGINE_ID, + ConsensusLog::ScheduledChange(scheduled_change.clone()).encode(), + )); + assert_eq!( + GrandpaConsensusLogReader::find_scheduled_change(&digest), + Some(scheduled_change.clone()) + ); + + // not first + let mut digest = Digest::default(); + digest.push(DigestItem::Consensus( + GRANDPA_ENGINE_ID, + ConsensusLog::::OnDisabled(0).encode(), + )); + digest.push(DigestItem::Consensus( + GRANDPA_ENGINE_ID, + ConsensusLog::ScheduledChange(scheduled_change.clone()).encode(), + )); + assert_eq!( + GrandpaConsensusLogReader::find_scheduled_change(&digest), + Some(scheduled_change.clone()) + ); + } } diff --git a/bridges/primitives/messages/Cargo.toml b/bridges/primitives/messages/Cargo.toml index d41acfb9d32863d14e56e095755791a420fd3ce6..20337873c2e6abac5872807adf67557be60a46e8 100644 --- a/bridges/primitives/messages/Cargo.toml +++ b/bridges/primitives/messages/Cargo.toml @@ -11,7 +11,7 @@ repository.workspace = true workspace = true [dependencies] -codec = { package = "parity-scale-codec", version = "3.6.1", default-features = false, features = ["bit-vec", "derive"] } +codec = { package = "parity-scale-codec", version = "3.6.12", default-features = false, features = ["bit-vec", "derive"] } scale-info = { version = "2.11.1", default-features = false, features = ["bit-vec", "derive"] } serde = { features = ["alloc", "derive"], workspace = true } diff --git a/bridges/primitives/parachains/Cargo.toml b/bridges/primitives/parachains/Cargo.toml index 2e7000b86a5e4ba21ccadf74b1c2d5374db5c545..a6e71876cefbb3963ef1923469d641281cda00dc 100644 --- a/bridges/primitives/parachains/Cargo.toml +++ b/bridges/primitives/parachains/Cargo.toml @@ -11,7 +11,7 @@ repository.workspace = true workspace = true [dependencies] -codec = { package = "parity-scale-codec", version = "3.6.1", default-features = false, features = ["derive"] } +codec = { package = "parity-scale-codec", version = "3.6.12", default-features = false, features = ["derive"] } impl-trait-for-tuples = "0.2" scale-info = { version = "2.11.1", default-features = false, features = ["derive"] } diff --git a/bridges/primitives/parachains/src/lib.rs b/bridges/primitives/parachains/src/lib.rs index 692bbd99ecef38535bb65a18dac09a77f1f1eca2..142c6e9b08923fdd2934fb7f3b9c2d12788fc8b9 100644 --- a/bridges/primitives/parachains/src/lib.rs +++ b/bridges/primitives/parachains/src/lib.rs @@ -116,6 +116,10 @@ impl ParaStoredHeaderData { /// Stored parachain head data builder. pub trait ParaStoredHeaderDataBuilder { + /// Maximal parachain head size that we may accept for free. All heads above + /// this limit are submitted for a regular fee. + fn max_free_head_size() -> u32; + /// Return number of parachains that are supported by this builder. fn supported_parachains() -> u32; @@ -127,6 +131,10 @@ pub trait ParaStoredHeaderDataBuilder { pub struct SingleParaStoredHeaderDataBuilder(PhantomData); impl ParaStoredHeaderDataBuilder for SingleParaStoredHeaderDataBuilder { + fn max_free_head_size() -> u32 { + C::MAX_HEADER_SIZE + } + fn supported_parachains() -> u32 { 1 } @@ -147,6 +155,17 @@ impl ParaStoredHeaderDataBuilder for SingleParaStoredHeaderDataBui #[impl_trait_for_tuples::impl_for_tuples(1, 30)] #[tuple_types_custom_trait_bound(Parachain)] impl ParaStoredHeaderDataBuilder for C { + fn max_free_head_size() -> u32 { + let mut result = 0_u32; + for_tuples!( #( + result = sp_std::cmp::max( + result, + SingleParaStoredHeaderDataBuilder::::max_free_head_size(), + ); + )* ); + result + } + fn supported_parachains() -> u32 { let mut result = 0; for_tuples!( #( diff --git a/bridges/primitives/polkadot-core/Cargo.toml b/bridges/primitives/polkadot-core/Cargo.toml index 53b1e574cb1997e556f17b7f21f6a28d9eb84400..d4b2f503e9e2ca92c095649f8aa36741d02c8037 100644 --- a/bridges/primitives/polkadot-core/Cargo.toml +++ b/bridges/primitives/polkadot-core/Cargo.toml @@ -11,7 +11,7 @@ repository.workspace = true workspace = true [dependencies] -codec = { package = "parity-scale-codec", version = "3.6.1", default-features = false, features = ["derive"] } +codec = { package = "parity-scale-codec", version = "3.6.12", default-features = false, features = ["derive"] } parity-util-mem = { version = "0.12.0", optional = true } scale-info = { version = "2.11.1", default-features = false, features = ["derive"] } serde = { optional = true, features = ["derive"], workspace = true, default-features = true } diff --git a/bridges/primitives/relayers/Cargo.toml b/bridges/primitives/relayers/Cargo.toml index 1be7f1dc6ebd38061e98865b45d4f85d8f3f7448..5081dddce1e61eccbae540f665257e122d777dd6 100644 --- a/bridges/primitives/relayers/Cargo.toml +++ b/bridges/primitives/relayers/Cargo.toml @@ -11,7 +11,7 @@ repository.workspace = true workspace = true [dependencies] -codec = { package = "parity-scale-codec", version = "3.6.1", default-features = false, features = ["bit-vec", "derive"] } +codec = { package = "parity-scale-codec", version = "3.6.12", default-features = false, features = ["bit-vec", "derive"] } scale-info = { version = "2.11.1", default-features = false, features = ["bit-vec", "derive"] } # Bridge Dependencies diff --git a/bridges/primitives/runtime/Cargo.toml b/bridges/primitives/runtime/Cargo.toml index 9a9b0291687d19ac0b5698ce3ef6a591da9f86c9..ac65ad538b4988c71e59d081cba46d47ebdc7c39 100644 --- a/bridges/primitives/runtime/Cargo.toml +++ b/bridges/primitives/runtime/Cargo.toml @@ -11,7 +11,7 @@ repository.workspace = true workspace = true [dependencies] -codec = { package = "parity-scale-codec", version = "3.6.1", default-features = false } +codec = { package = "parity-scale-codec", version = "3.6.12", default-features = false } hash-db = { version = "0.16.0", default-features = false } impl-trait-for-tuples = "0.2.2" log = { workspace = true } diff --git a/bridges/primitives/runtime/src/chain.rs b/bridges/primitives/runtime/src/chain.rs index 4ec5a001a99ecad21617ed0afc57d3edac383d0d..369386e41b0cf9f2d911ca40fc9e6ccfb3de6e52 100644 --- a/bridges/primitives/runtime/src/chain.rs +++ b/bridges/primitives/runtime/src/chain.rs @@ -26,7 +26,7 @@ use sp_runtime::{ }, FixedPointOperand, }; -use sp_std::{convert::TryFrom, fmt::Debug, hash::Hash, str::FromStr, vec, vec::Vec}; +use sp_std::{fmt::Debug, hash::Hash, str::FromStr, vec, vec::Vec}; /// Chain call, that is either SCALE-encoded, or decoded. #[derive(Debug, Clone, PartialEq)] @@ -236,6 +236,12 @@ where pub trait Parachain: Chain { /// Parachain identifier. const PARACHAIN_ID: u32; + /// Maximal size of the parachain header. + /// + /// This isn't a strict limit. The relayer may submit larger headers and the + /// pallet will accept the call. The limit is only used to compute whether + /// the refund can be made. + const MAX_HEADER_SIZE: u32; } impl Parachain for T @@ -244,6 +250,8 @@ where ::Chain: Parachain, { const PARACHAIN_ID: u32 = <::Chain as Parachain>::PARACHAIN_ID; + const MAX_HEADER_SIZE: u32 = + <::Chain as Parachain>::MAX_HEADER_SIZE; } /// Adapter for `Get` to access `PARACHAIN_ID` from `trait Parachain` @@ -306,6 +314,11 @@ macro_rules! decl_bridge_finality_runtime_apis { pub const []: &str = stringify!([<$chain:camel FinalityApi_best_finalized>]); + /// Name of the `FinalityApi::free_headers_interval` runtime method. + pub const []: &str = + stringify!([<$chain:camel FinalityApi_free_headers_interval>]); + + $( /// Name of the `FinalityApi::accepted__finality_proofs` /// runtime method. @@ -322,6 +335,13 @@ macro_rules! decl_bridge_finality_runtime_apis { /// Returns number and hash of the best finalized header known to the bridge module. fn best_finalized() -> Option>; + /// Returns free headers interval, if it is configured in the runtime. + /// The caller expects that if his transaction improves best known header + /// at least by the free_headers_interval`, it will be fee-free. + /// + /// See [`pallet_bridge_grandpa::Config::FreeHeadersInterval`] for details. + fn free_headers_interval() -> Option; + $( /// Returns the justifications accepted in the current block. fn []( diff --git a/bridges/primitives/runtime/src/lib.rs b/bridges/primitives/runtime/src/lib.rs index c9c5c9412913b0470024e9e1473e5d69ff184f25..5daba0351ad48f0ae39b870990b6f5ccea1bec1e 100644 --- a/bridges/primitives/runtime/src/lib.rs +++ b/bridges/primitives/runtime/src/lib.rs @@ -31,7 +31,7 @@ use sp_runtime::{ traits::{BadOrigin, Header as HeaderT, UniqueSaturatedInto}, RuntimeDebug, }; -use sp_std::{convert::TryFrom, fmt::Debug, ops::RangeInclusive, vec, vec::Vec}; +use sp_std::{fmt::Debug, ops::RangeInclusive, vec, vec::Vec}; pub use chain::{ AccountIdOf, AccountPublicOf, BalanceOf, BlockNumberOf, Chain, EncodedOrDecodedCall, HashOf, diff --git a/bridges/primitives/test-utils/Cargo.toml b/bridges/primitives/test-utils/Cargo.toml index d314c38683cdbc8b40cfda3a14c64f91854e5d7f..99f5ee0d1aee4528f64028bbb4ce089cfb6f4c44 100644 --- a/bridges/primitives/test-utils/Cargo.toml +++ b/bridges/primitives/test-utils/Cargo.toml @@ -15,7 +15,7 @@ bp-header-chain = { path = "../header-chain", default-features = false } bp-parachains = { path = "../parachains", default-features = false } bp-polkadot-core = { path = "../polkadot-core", default-features = false } bp-runtime = { path = "../runtime", default-features = false } -codec = { package = "parity-scale-codec", version = "3.6.1", default-features = false } +codec = { package = "parity-scale-codec", version = "3.6.12", default-features = false } ed25519-dalek = { version = "2.1", default-features = false } finality-grandpa = { version = "0.16.2", default-features = false } sp-application-crypto = { path = "../../../substrate/primitives/application-crypto", default-features = false } diff --git a/bridges/primitives/xcm-bridge-hub-router/Cargo.toml b/bridges/primitives/xcm-bridge-hub-router/Cargo.toml index 94eece16d5797eb23dd12af5b8b5aeb7d283d862..b94e722024562e526c33d2bf1efe9b89f1a035aa 100644 --- a/bridges/primitives/xcm-bridge-hub-router/Cargo.toml +++ b/bridges/primitives/xcm-bridge-hub-router/Cargo.toml @@ -11,7 +11,7 @@ repository.workspace = true workspace = true [dependencies] -codec = { package = "parity-scale-codec", version = "3.6.1", default-features = false, features = ["bit-vec", "derive"] } +codec = { package = "parity-scale-codec", version = "3.6.12", default-features = false, features = ["bit-vec", "derive"] } scale-info = { version = "2.11.1", default-features = false, features = ["bit-vec", "derive"] } # Substrate Dependencies diff --git a/bridges/relays/client-substrate/Cargo.toml b/bridges/relays/client-substrate/Cargo.toml index 2c98441fc3017e8bcd4a213b27d5f5d2fee3223d..cb7eae4f340c7375ad69b111f6b561c84bc57144 100644 --- a/bridges/relays/client-substrate/Cargo.toml +++ b/bridges/relays/client-substrate/Cargo.toml @@ -13,7 +13,7 @@ workspace = true [dependencies] async-std = { version = "1.9.0", features = ["attributes"] } async-trait = "0.1.79" -codec = { package = "parity-scale-codec", version = "3.6.1" } +codec = { package = "parity-scale-codec", version = "3.6.12" } futures = "0.3.30" jsonrpsee = { version = "0.22", features = ["macros", "ws-client"] } log = { workspace = true } diff --git a/bridges/relays/client-substrate/src/chain.rs b/bridges/relays/client-substrate/src/chain.rs index 2aba5f5674d97b2bcf8b3e2633c36b6bee52d98a..40269fe64c879249e9f0ed5ffe070d9fc606bdb6 100644 --- a/bridges/relays/client-substrate/src/chain.rs +++ b/bridges/relays/client-substrate/src/chain.rs @@ -46,6 +46,12 @@ pub trait Chain: ChainBase + Clone { /// Keep in mind that this method is normally provided by the other chain, which is /// bridged with this chain. const BEST_FINALIZED_HEADER_ID_METHOD: &'static str; + /// Name of the runtime API method that is returning interval between source chain + /// headers that may be submitted for free to the target chain. + /// + /// Keep in mind that this method is normally provided by the other chain, which is + /// bridged with this chain. + const FREE_HEADERS_INTERVAL_METHOD: &'static str; /// Average block interval. /// @@ -75,6 +81,9 @@ pub trait ChainWithRuntimeVersion: Chain { pub trait RelayChain: Chain { /// Name of the `runtime_parachains::paras` pallet in the runtime of this chain. const PARAS_PALLET_NAME: &'static str; + /// Name of the `pallet-bridge-parachains`, deployed at the **bridged** chain to sync + /// parachains of **this** chain. + const WITH_CHAIN_BRIDGE_PARACHAINS_PALLET_NAME: &'static str; } /// Substrate-based chain that is using direct GRANDPA finality from minimal relay-client point of diff --git a/bridges/relays/client-substrate/src/client.rs b/bridges/relays/client-substrate/src/client.rs index afbda8599b2aa03c4ed4a7c33a93fdd429646516..2e7cb7455f76cceee1c63aae4efb4a5cfe9f2a69 100644 --- a/bridges/relays/client-substrate/src/client.rs +++ b/bridges/relays/client-substrate/src/client.rs @@ -77,7 +77,12 @@ pub fn is_ancient_block + PartialOrd + Saturating>(block: N, best: } /// Opaque justifications subscription type. -pub struct Subscription(pub(crate) Mutex>>); +pub struct Subscription( + pub(crate) Mutex>>, + // The following field is not explicitly used by the code. But when it is dropped, + // the bakground task receives a shutdown signal. + #[allow(dead_code)] pub(crate) futures::channel::oneshot::Sender<()>, +); /// Opaque GRANDPA authorities set. pub type OpaqueGrandpaAuthoritiesSet = Vec; @@ -621,6 +626,7 @@ impl Client { e })??; + let (cancel_sender, cancel_receiver) = futures::channel::oneshot::channel(); let (sender, receiver) = futures::channel::mpsc::channel(MAX_SUBSCRIPTION_CAPACITY); let (tracker, subscription) = self .jsonrpsee_execute(move |client| async move { @@ -639,7 +645,7 @@ impl Client { self_clone, stall_timeout, tx_hash, - Subscription(Mutex::new(receiver)), + Subscription(Mutex::new(receiver), cancel_sender), ); Ok((tracker, subscription)) }) @@ -649,6 +655,7 @@ impl Client { "extrinsic".into(), subscription, sender, + cancel_receiver, )); Ok(tracker) } @@ -790,14 +797,16 @@ impl Client { Ok(FC::subscribe_justifications(&client).await?) }) .await?; + let (cancel_sender, cancel_receiver) = futures::channel::oneshot::channel(); let (sender, receiver) = futures::channel::mpsc::channel(MAX_SUBSCRIPTION_CAPACITY); self.data.read().await.tokio.spawn(Subscription::background_worker( C::NAME.into(), "justification".into(), subscription, sender, + cancel_receiver, )); - Ok(Subscription(Mutex::new(receiver))) + Ok(Subscription(Mutex::new(receiver), cancel_sender)) } /// Generates a proof of key ownership for the given authority in the given set. @@ -843,9 +852,17 @@ impl Client { impl Subscription { /// Consumes subscription and returns future statuses stream. pub fn into_stream(self) -> impl futures::Stream { - futures::stream::unfold(self, |this| async { + futures::stream::unfold(Some(self), |mut this| async move { + let Some(this) = this.take() else { return None }; let item = this.0.lock().await.next().await.unwrap_or(None); - item.map(|i| (i, this)) + match item { + Some(item) => Some((item, Some(this))), + None => { + // let's make it explicit here + let _ = this.1.send(()); + None + }, + } }) } @@ -860,19 +877,35 @@ impl Subscription { async fn background_worker( chain_name: String, item_type: String, - mut subscription: jsonrpsee::core::client::Subscription, + subscription: jsonrpsee::core::client::Subscription, mut sender: futures::channel::mpsc::Sender>, + cancel_receiver: futures::channel::oneshot::Receiver<()>, ) { + log::trace!( + target: "bridge", + "Starting background worker for {} {} subscription stream.", + chain_name, + item_type, + ); + + futures::pin_mut!(subscription, cancel_receiver); loop { - match subscription.next().await { - Some(Ok(item)) => + match futures::future::select(subscription.next(), &mut cancel_receiver).await { + futures::future::Either::Left((Some(Ok(item)), _)) => if sender.send(Some(item)).await.is_err() { + log::trace!( + target: "bridge", + "{} {} subscription stream: no listener. Stopping background worker.", + chain_name, + item_type, + ); + break }, - Some(Err(e)) => { + futures::future::Either::Left((Some(Err(e)), _)) => { log::trace!( target: "bridge", - "{} {} subscription stream has returned '{:?}'. Stream needs to be restarted.", + "{} {} subscription stream has returned '{:?}'. Stream needs to be restarted. Stopping background worker.", chain_name, item_type, e, @@ -880,16 +913,25 @@ impl Subscription { let _ = sender.send(None).await; break }, - None => { + futures::future::Either::Left((None, _)) => { log::trace!( target: "bridge", - "{} {} subscription stream has returned None. Stream needs to be restarted.", + "{} {} subscription stream has returned None. Stream needs to be restarted. Stopping background worker.", chain_name, item_type, ); let _ = sender.send(None).await; break }, + futures::future::Either::Right((_, _)) => { + log::trace!( + target: "bridge", + "{} {} subscription stream: listener has been dropped. Stopping background worker.", + chain_name, + item_type, + ); + break; + }, } } } diff --git a/bridges/relays/client-substrate/src/test_chain.rs b/bridges/relays/client-substrate/src/test_chain.rs index 77240d15884f4512458772b16f14f27b44f57f39..cfd241c022a269da799e8e03c4398566d98a14a0 100644 --- a/bridges/relays/client-substrate/src/test_chain.rs +++ b/bridges/relays/client-substrate/src/test_chain.rs @@ -56,6 +56,7 @@ impl bp_runtime::Chain for TestChain { impl Chain for TestChain { const NAME: &'static str = "Test"; const BEST_FINALIZED_HEADER_ID_METHOD: &'static str = "TestMethod"; + const FREE_HEADERS_INTERVAL_METHOD: &'static str = "TestMethod"; const AVERAGE_BLOCK_INTERVAL: Duration = Duration::from_millis(0); type SignedBlock = sp_runtime::generic::SignedBlock< @@ -110,6 +111,7 @@ impl bp_runtime::Chain for TestParachainBase { impl bp_runtime::Parachain for TestParachainBase { const PARACHAIN_ID: u32 = 1000; + const MAX_HEADER_SIZE: u32 = 1_024; } /// Parachain that may be used in tests. @@ -123,6 +125,7 @@ impl bp_runtime::UnderlyingChainProvider for TestParachain { impl Chain for TestParachain { const NAME: &'static str = "TestParachain"; const BEST_FINALIZED_HEADER_ID_METHOD: &'static str = "TestParachainMethod"; + const FREE_HEADERS_INTERVAL_METHOD: &'static str = "TestParachainMethod"; const AVERAGE_BLOCK_INTERVAL: Duration = Duration::from_millis(0); type SignedBlock = sp_runtime::generic::SignedBlock< diff --git a/bridges/relays/client-substrate/src/transaction_tracker.rs b/bridges/relays/client-substrate/src/transaction_tracker.rs index 00375768c45c27c23dfccb7730668108a6fab788..b181a945c2c15393daf821901b298e81214f85e3 100644 --- a/bridges/relays/client-substrate/src/transaction_tracker.rs +++ b/bridges/relays/client-substrate/src/transaction_tracker.rs @@ -306,12 +306,13 @@ mod tests { TrackedTransactionStatus>, InvalidationStatus>, )> { + let (cancel_sender, _cancel_receiver) = futures::channel::oneshot::channel(); let (mut sender, receiver) = futures::channel::mpsc::channel(1); let tx_tracker = TransactionTracker::::new( TestEnvironment(Ok(HeaderId(0, Default::default()))), Duration::from_secs(0), Default::default(), - Subscription(async_std::sync::Mutex::new(receiver)), + Subscription(async_std::sync::Mutex::new(receiver), cancel_sender), ); let wait_for_stall_timeout = futures::future::pending(); @@ -428,12 +429,13 @@ mod tests { #[async_std::test] async fn lost_on_timeout_when_waiting_for_invalidation_status() { + let (cancel_sender, _cancel_receiver) = futures::channel::oneshot::channel(); let (_sender, receiver) = futures::channel::mpsc::channel(1); let tx_tracker = TransactionTracker::::new( TestEnvironment(Ok(HeaderId(0, Default::default()))), Duration::from_secs(0), Default::default(), - Subscription(async_std::sync::Mutex::new(receiver)), + Subscription(async_std::sync::Mutex::new(receiver), cancel_sender), ); let wait_for_stall_timeout = futures::future::ready(()).shared(); diff --git a/bridges/relays/finality/README.md b/bridges/relays/finality/README.md index 92e765cea0e505be7854e17a9b91df520bba32b0..89b9d1399584a8575f2ae47cda7c8ee064314697 100644 --- a/bridges/relays/finality/README.md +++ b/bridges/relays/finality/README.md @@ -33,7 +33,9 @@ node. The transaction is then tracked by the relay until it is mined and finaliz The main entrypoint for the crate is the [`run` function](./src/finality_loop.rs), which takes source and target clients and [`FinalitySyncParams`](./src/finality_loop.rs) parameters. The most important parameter is the `only_mandatory_headers` - it is set to `true`, the relay will only submit mandatory headers. Since transactions -with mandatory headers are fee-free, the cost of running such relay is zero (in terms of fees). +with mandatory headers are fee-free, the cost of running such relay is zero (in terms of fees). If a similar, +`only_free_headers` parameter, is set to `true`, then free headers (if configured in the runtime) are also +relayed. ## Finality Relay Metrics diff --git a/bridges/relays/finality/src/finality_loop.rs b/bridges/relays/finality/src/finality_loop.rs index e31d8a708122db84c4c87f257edee7ee4ba616bb..8b3def868a453703600850a463cf2f07988811df 100644 --- a/bridges/relays/finality/src/finality_loop.rs +++ b/bridges/relays/finality/src/finality_loop.rs @@ -29,7 +29,7 @@ use crate::{ use async_trait::async_trait; use backoff::{backoff::Backoff, ExponentialBackoff}; use futures::{future::Fuse, select, Future, FutureExt}; -use num_traits::Saturating; +use num_traits::{Saturating, Zero}; use relay_utils::{ metrics::MetricsParams, relay_loop::Client as RelayClient, retry_backoff, FailedClient, HeaderId, MaybeConnectionError, TrackedTransactionStatus, TransactionTracker, @@ -39,6 +39,17 @@ use std::{ time::{Duration, Instant}, }; +/// Type of headers that we relay. +#[derive(Debug, Clone, Copy, PartialEq)] +pub enum HeadersToRelay { + /// Relay all headers. + All, + /// Relay only mandatory headers. + Mandatory, + /// Relay only free (including mandatory) headers. + Free, +} + /// Finality proof synchronization loop parameters. #[derive(Debug, Clone)] pub struct FinalitySyncParams { @@ -63,7 +74,7 @@ pub struct FinalitySyncParams { /// Timeout before we treat our transactions as lost and restart the whole sync process. pub stall_timeout: Duration, /// If true, only mandatory headers are relayed. - pub only_mandatory_headers: bool, + pub headers_to_relay: HeadersToRelay, } /// Source client used in finality synchronization loop. @@ -90,11 +101,16 @@ pub trait TargetClient: RelayClient { &self, ) -> Result, Self::Error>; + /// Get free source headers submission interval, if it is configured in the + /// target runtime. + async fn free_source_headers_interval(&self) -> Result, Self::Error>; + /// Submit header finality proof. async fn submit_finality_proof( &self, header: P::Header, proof: P::FinalityProof, + is_free_execution_expected: bool, ) -> Result; } @@ -104,9 +120,13 @@ pub fn metrics_prefix() -> String { format!("{}_to_{}_Sync", P::SOURCE_NAME, P::TARGET_NAME) } +/// Finality sync information. pub struct SyncInfo { + /// Best finalized header at the source client. pub best_number_at_source: P::Number, + /// Best source header, known to the target client. pub best_number_at_target: P::Number, + /// Whether the target client follows the same fork as the source client do. pub is_using_same_fork: bool, } @@ -183,6 +203,7 @@ impl Transaction Result { let header_number = header.number(); log::debug!( @@ -193,7 +214,9 @@ impl Transaction, TC: TargetClient

> Finality pub async fn select_header_to_submit( &mut self, info: &SyncInfo

, + free_headers_interval: Option, ) -> Result>, Error> { // to see that the loop is progressing log::trace!( @@ -302,9 +326,15 @@ impl, TC: TargetClient

> Finality ); // read missing headers - let selector = JustifiedHeaderSelector::new::(&self.source_client, info).await?; + let selector = JustifiedHeaderSelector::new::( + &self.source_client, + info, + self.sync_params.headers_to_relay, + free_headers_interval, + ) + .await?; // if we see that the header schedules GRANDPA change, we need to submit it - if self.sync_params.only_mandatory_headers { + if self.sync_params.headers_to_relay == HeadersToRelay::Mandatory { return Ok(selector.select_mandatory()) } @@ -312,7 +342,12 @@ impl, TC: TargetClient

> Finality // => even if we have already selected some header and its persistent finality proof, // we may try to select better header by reading non-persistent proofs from the stream self.finality_proofs_buf.fill(&mut self.finality_proofs_stream); - let maybe_justified_header = selector.select(&self.finality_proofs_buf); + let maybe_justified_header = selector.select( + info, + self.sync_params.headers_to_relay, + free_headers_interval, + &self.finality_proofs_buf, + ); // remove obsolete 'recent' finality proofs + keep its size under certain limit let oldest_finality_proof_to_keep = maybe_justified_header @@ -329,6 +364,7 @@ impl, TC: TargetClient

> Finality pub async fn run_iteration( &mut self, + free_headers_interval: Option, ) -> Result< Option>, Error, @@ -345,12 +381,16 @@ impl, TC: TargetClient

> Finality } // submit new header if we have something new - match self.select_header_to_submit(&info).await? { + match self.select_header_to_submit(&info, free_headers_interval).await? { Some(header) => { - let transaction = - Transaction::submit(&self.target_client, header.header, header.proof) - .await - .map_err(Error::Target)?; + let transaction = Transaction::submit( + &self.target_client, + header.header, + header.proof, + self.sync_params.headers_to_relay == HeadersToRelay::Free, + ) + .await + .map_err(Error::Target)?; self.best_submitted_number = Some(transaction.header_number); Ok(Some(transaction)) }, @@ -378,9 +418,11 @@ impl, TC: TargetClient

> Finality let exit_signal = exit_signal.fuse(); futures::pin_mut!(exit_signal, proof_submission_tx_tracker); + let free_headers_interval = free_headers_interval(&self.target_client).await?; + loop { // run loop iteration - let next_tick = match self.run_iteration().await { + let next_tick = match self.run_iteration(free_headers_interval).await { Ok(Some(tx)) => { proof_submission_tx_tracker .set(tx.track::(self.target_client.clone()).fuse()); @@ -433,6 +475,52 @@ impl, TC: TargetClient

> Finality } } +async fn free_headers_interval( + target_client: &impl TargetClient

, +) -> Result, FailedClient> { + match target_client.free_source_headers_interval().await { + Ok(Some(free_headers_interval)) if !free_headers_interval.is_zero() => { + log::trace!( + target: "bridge", + "Free headers interval for {} headers at {} is: {:?}", + P::SOURCE_NAME, + P::TARGET_NAME, + free_headers_interval, + ); + Ok(Some(free_headers_interval)) + }, + Ok(Some(_free_headers_interval)) => { + log::trace!( + target: "bridge", + "Free headers interval for {} headers at {} is zero. Not submitting any free headers", + P::SOURCE_NAME, + P::TARGET_NAME, + ); + Ok(None) + }, + Ok(None) => { + log::trace!( + target: "bridge", + "Free headers interval for {} headers at {} is None. Not submitting any free headers", + P::SOURCE_NAME, + P::TARGET_NAME, + ); + + Ok(None) + }, + Err(e) => { + log::error!( + target: "bridge", + "Failed to read free headers interval for {} headers at {}: {:?}", + P::SOURCE_NAME, + P::TARGET_NAME, + e, + ); + Err(FailedClient::Target) + }, + } +} + /// Run finality proofs synchronization loop. pub async fn run( source_client: impl SourceClient

, @@ -509,7 +597,7 @@ mod tests { tick: Duration::from_secs(0), recent_finality_proofs_limit: 1024, stall_timeout: Duration::from_secs(1), - only_mandatory_headers: false, + headers_to_relay: HeadersToRelay::All, } } @@ -593,8 +681,8 @@ mod tests { ); } - fn run_only_mandatory_headers_mode_test( - only_mandatory_headers: bool, + fn run_headers_to_relay_mode_test( + headers_to_relay: HeadersToRelay, has_mandatory_headers: bool, ) -> Option> { let (exit_sender, _) = futures::channel::mpsc::unbounded(); @@ -619,7 +707,7 @@ mod tests { tick: Duration::from_secs(0), recent_finality_proofs_limit: 0, stall_timeout: Duration::from_secs(0), - only_mandatory_headers, + headers_to_relay, }, None, ); @@ -628,16 +716,22 @@ mod tests { best_number_at_target: 5, is_using_same_fork: true, }; - finality_loop.select_header_to_submit(&info).await.unwrap() + finality_loop.select_header_to_submit(&info, Some(3)).await.unwrap() }) } #[test] - fn select_header_to_submit_skips_non_mandatory_headers_when_only_mandatory_headers_are_required( - ) { - assert_eq!(run_only_mandatory_headers_mode_test(true, false), None); + fn select_header_to_submit_may_select_non_mandatory_header() { + assert_eq!(run_headers_to_relay_mode_test(HeadersToRelay::Mandatory, false), None); assert_eq!( - run_only_mandatory_headers_mode_test(false, false), + run_headers_to_relay_mode_test(HeadersToRelay::Free, false), + Some(JustifiedHeader { + header: TestSourceHeader(false, 10, 10), + proof: TestFinalityProof(10) + }), + ); + assert_eq!( + run_headers_to_relay_mode_test(HeadersToRelay::All, false), Some(JustifiedHeader { header: TestSourceHeader(false, 10, 10), proof: TestFinalityProof(10) @@ -646,17 +740,23 @@ mod tests { } #[test] - fn select_header_to_submit_selects_mandatory_headers_when_only_mandatory_headers_are_required() - { + fn select_header_to_submit_may_select_mandatory_header() { + assert_eq!( + run_headers_to_relay_mode_test(HeadersToRelay::Mandatory, true), + Some(JustifiedHeader { + header: TestSourceHeader(true, 8, 8), + proof: TestFinalityProof(8) + }), + ); assert_eq!( - run_only_mandatory_headers_mode_test(true, true), + run_headers_to_relay_mode_test(HeadersToRelay::Free, true), Some(JustifiedHeader { header: TestSourceHeader(true, 8, 8), proof: TestFinalityProof(8) }), ); assert_eq!( - run_only_mandatory_headers_mode_test(false, true), + run_headers_to_relay_mode_test(HeadersToRelay::All, true), Some(JustifiedHeader { header: TestSourceHeader(true, 8, 8), proof: TestFinalityProof(8) @@ -690,7 +790,7 @@ mod tests { test_sync_params(), Some(metrics_sync.clone()), ); - finality_loop.run_iteration().await.unwrap() + finality_loop.run_iteration(None).await.unwrap() }); assert!(!metrics_sync.is_using_same_fork()); diff --git a/bridges/relays/finality/src/headers.rs b/bridges/relays/finality/src/headers.rs index 91f7cd0378ecd9ac8a0ee558266d993cc2253c9e..5bba4a384562d1f97334cd809ba47267698308f9 100644 --- a/bridges/relays/finality/src/headers.rs +++ b/bridges/relays/finality/src/headers.rs @@ -16,10 +16,11 @@ use crate::{ finality_loop::SyncInfo, finality_proofs::FinalityProofsBuf, Error, FinalitySyncPipeline, - SourceClient, SourceHeader, TargetClient, + HeadersToRelay, SourceClient, SourceHeader, TargetClient, }; use bp_header_chain::FinalityProof; +use num_traits::Saturating; use std::cmp::Ordering; /// Unjustified headers container. Ordered by header number. @@ -50,9 +51,13 @@ pub enum JustifiedHeaderSelector { } impl JustifiedHeaderSelector

{ + /// Selects last header with persistent justification, missing from the target and matching + /// the `headers_to_relay` criteria. pub(crate) async fn new, TC: TargetClient

>( source_client: &SC, info: &SyncInfo

, + headers_to_relay: HeadersToRelay, + free_headers_interval: Option, ) -> Result> { let mut unjustified_headers = Vec::new(); let mut maybe_justified_header = None; @@ -70,12 +75,19 @@ impl JustifiedHeaderSelector

{ return Ok(Self::Mandatory(JustifiedHeader { header, proof })) }, (true, None) => return Err(Error::MissingMandatoryFinalityProof(header.number())), - (false, Some(proof)) => { + (false, Some(proof)) + if need_to_relay::

( + info, + headers_to_relay, + free_headers_interval, + &header, + ) => + { log::trace!(target: "bridge", "Header {:?} has persistent finality proof", header_number); unjustified_headers.clear(); maybe_justified_header = Some(JustifiedHeader { header, proof }); }, - (false, None) => { + _ => { unjustified_headers.push(header); }, } @@ -97,6 +109,7 @@ impl JustifiedHeaderSelector

{ }) } + /// Returns selected mandatory header if we have seen one. Otherwise returns `None`. pub fn select_mandatory(self) -> Option> { match self { JustifiedHeaderSelector::Mandatory(header) => Some(header), @@ -104,7 +117,15 @@ impl JustifiedHeaderSelector

{ } } - pub fn select(self, buf: &FinalityProofsBuf

) -> Option> { + /// Tries to improve previously selected header using ephemeral + /// justifications stream. + pub fn select( + self, + info: &SyncInfo

, + headers_to_relay: HeadersToRelay, + free_headers_interval: Option, + buf: &FinalityProofsBuf

, + ) -> Option> { let (unjustified_headers, maybe_justified_header) = match self { JustifiedHeaderSelector::Mandatory(justified_header) => return Some(justified_header), JustifiedHeaderSelector::Regular(unjustified_headers, justified_header) => @@ -122,7 +143,14 @@ impl JustifiedHeaderSelector

{ (maybe_finality_proof, maybe_unjustified_header) { match finality_proof.target_header_number().cmp(&unjustified_header.number()) { - Ordering::Equal => { + Ordering::Equal + if need_to_relay::

( + info, + headers_to_relay, + free_headers_interval, + &unjustified_header, + ) => + { log::trace!( target: "bridge", "Managed to improve selected {} finality proof {:?} to {:?}.", @@ -135,6 +163,10 @@ impl JustifiedHeaderSelector

{ proof: finality_proof.clone(), }) }, + Ordering::Equal => { + maybe_finality_proof = finality_proofs_iter.next(); + maybe_unjustified_header = unjustified_headers_iter.next(); + }, Ordering::Less => maybe_unjustified_header = unjustified_headers_iter.next(), Ordering::Greater => { maybe_finality_proof = finality_proofs_iter.next(); @@ -152,6 +184,27 @@ impl JustifiedHeaderSelector

{ } } +/// Returns true if we want to relay header `header_number`. +fn need_to_relay( + info: &SyncInfo

, + headers_to_relay: HeadersToRelay, + free_headers_interval: Option, + header: &P::Header, +) -> bool { + match headers_to_relay { + HeadersToRelay::All => true, + HeadersToRelay::Mandatory => header.is_mandatory(), + HeadersToRelay::Free => + header.is_mandatory() || + free_headers_interval + .map(|free_headers_interval| { + header.number().saturating_sub(info.best_number_at_target) >= + free_headers_interval + }) + .unwrap_or(false), + } +} + #[cfg(test)] mod tests { use super::*; @@ -159,13 +212,22 @@ mod tests { #[test] fn select_better_recent_finality_proof_works() { + let info = SyncInfo { + best_number_at_source: 10, + best_number_at_target: 5, + is_using_same_fork: true, + }; + // if there are no unjustified headers, nothing is changed let finality_proofs_buf = FinalityProofsBuf::::new(vec![TestFinalityProof(5)]); let justified_header = JustifiedHeader { header: TestSourceHeader(false, 2, 2), proof: TestFinalityProof(2) }; let selector = JustifiedHeaderSelector::Regular(vec![], justified_header.clone()); - assert_eq!(selector.select(&finality_proofs_buf), Some(justified_header)); + assert_eq!( + selector.select(&info, HeadersToRelay::All, None, &finality_proofs_buf), + Some(justified_header) + ); // if there are no buffered finality proofs, nothing is changed let finality_proofs_buf = FinalityProofsBuf::::new(vec![]); @@ -175,7 +237,10 @@ mod tests { vec![TestSourceHeader(false, 5, 5)], justified_header.clone(), ); - assert_eq!(selector.select(&finality_proofs_buf), Some(justified_header)); + assert_eq!( + selector.select(&info, HeadersToRelay::All, None, &finality_proofs_buf), + Some(justified_header) + ); // if there's no intersection between recent finality proofs and unjustified headers, // nothing is changed @@ -189,7 +254,10 @@ mod tests { vec![TestSourceHeader(false, 9, 9), TestSourceHeader(false, 10, 10)], justified_header.clone(), ); - assert_eq!(selector.select(&finality_proofs_buf), Some(justified_header)); + assert_eq!( + selector.select(&info, HeadersToRelay::All, None, &finality_proofs_buf), + Some(justified_header) + ); // if there's intersection between recent finality proofs and unjustified headers, but there // are no proofs in this intersection, nothing is changed @@ -207,7 +275,10 @@ mod tests { ], justified_header.clone(), ); - assert_eq!(selector.select(&finality_proofs_buf), Some(justified_header)); + assert_eq!( + selector.select(&info, HeadersToRelay::All, None, &finality_proofs_buf), + Some(justified_header) + ); // if there's intersection between recent finality proofs and unjustified headers and // there's a proof in this intersection: @@ -228,11 +299,63 @@ mod tests { justified_header, ); assert_eq!( - selector.select(&finality_proofs_buf), + selector.select(&info, HeadersToRelay::All, None, &finality_proofs_buf), Some(JustifiedHeader { header: TestSourceHeader(false, 9, 9), proof: TestFinalityProof(9) }) ); + + // when only free headers needs to be relayed and there are no free headers + let finality_proofs_buf = FinalityProofsBuf::::new(vec![ + TestFinalityProof(7), + TestFinalityProof(9), + ]); + let selector = JustifiedHeaderSelector::None(vec![ + TestSourceHeader(false, 8, 8), + TestSourceHeader(false, 9, 9), + TestSourceHeader(false, 10, 10), + ]); + assert_eq!( + selector.select(&info, HeadersToRelay::Free, Some(7), &finality_proofs_buf), + None, + ); + + // when only free headers needs to be relayed, mandatory header may be selected + let finality_proofs_buf = FinalityProofsBuf::::new(vec![ + TestFinalityProof(6), + TestFinalityProof(9), + ]); + let selector = JustifiedHeaderSelector::None(vec![ + TestSourceHeader(false, 8, 8), + TestSourceHeader(true, 9, 9), + TestSourceHeader(false, 10, 10), + ]); + assert_eq!( + selector.select(&info, HeadersToRelay::Free, Some(7), &finality_proofs_buf), + Some(JustifiedHeader { + header: TestSourceHeader(true, 9, 9), + proof: TestFinalityProof(9) + }) + ); + + // when only free headers needs to be relayed and there is free header + let finality_proofs_buf = FinalityProofsBuf::::new(vec![ + TestFinalityProof(7), + TestFinalityProof(9), + TestFinalityProof(14), + ]); + let selector = JustifiedHeaderSelector::None(vec![ + TestSourceHeader(false, 7, 7), + TestSourceHeader(false, 10, 10), + TestSourceHeader(false, 14, 14), + ]); + assert_eq!( + selector.select(&info, HeadersToRelay::Free, Some(7), &finality_proofs_buf), + Some(JustifiedHeader { + header: TestSourceHeader(false, 14, 14), + proof: TestFinalityProof(14) + }) + ); } } diff --git a/bridges/relays/finality/src/lib.rs b/bridges/relays/finality/src/lib.rs index 3579e68e1ef9c686575e3ddba239bead7bd9312f..4346f96674b4c43c153ad8bf55cb5ee963871849 100644 --- a/bridges/relays/finality/src/lib.rs +++ b/bridges/relays/finality/src/lib.rs @@ -21,7 +21,9 @@ pub use crate::{ base::{FinalityPipeline, SourceClientBase}, - finality_loop::{metrics_prefix, run, FinalitySyncParams, SourceClient, TargetClient}, + finality_loop::{ + metrics_prefix, run, FinalitySyncParams, HeadersToRelay, SourceClient, TargetClient, + }, finality_proofs::{FinalityProofsBuf, FinalityProofsStream}, sync_loop_metrics::SyncLoopMetrics, }; diff --git a/bridges/relays/finality/src/mock.rs b/bridges/relays/finality/src/mock.rs index e3ec4e4d0d47a04ce5a22ee75374ebe08064df5e..69357f71ce27d54a2ca4866e3fd6db0a73fb44e2 100644 --- a/bridges/relays/finality/src/mock.rs +++ b/bridges/relays/finality/src/mock.rs @@ -198,10 +198,15 @@ impl TargetClient for TestTargetClient { Ok(data.target_best_block_id) } + async fn free_source_headers_interval(&self) -> Result, TestError> { + Ok(Some(3)) + } + async fn submit_finality_proof( &self, header: TestSourceHeader, proof: TestFinalityProof, + _is_free_execution_expected: bool, ) -> Result { let mut data = self.data.lock(); (self.on_method_call)(&mut data); diff --git a/bridges/relays/lib-substrate-relay/Cargo.toml b/bridges/relays/lib-substrate-relay/Cargo.toml index 3f657645b591c51ab74c5b6b64bfdd8ca04e7b18..077d1b1ff356a871364d45c1251aec0af7680cdd 100644 --- a/bridges/relays/lib-substrate-relay/Cargo.toml +++ b/bridges/relays/lib-substrate-relay/Cargo.toml @@ -14,7 +14,7 @@ workspace = true anyhow = "1.0" async-std = "1.9.0" async-trait = "0.1.79" -codec = { package = "parity-scale-codec", version = "3.6.1" } +codec = { package = "parity-scale-codec", version = "3.6.12" } futures = "0.3.30" hex = "0.4" log = { workspace = true } diff --git a/bridges/relays/lib-substrate-relay/src/cli/relay_headers.rs b/bridges/relays/lib-substrate-relay/src/cli/relay_headers.rs index 90558ed46138366221c1f9834d21060e7e54e66b..093f98ef21ed24b40a0c2d8f217d84b841137a69 100644 --- a/bridges/relays/lib-substrate-relay/src/cli/relay_headers.rs +++ b/bridges/relays/lib-substrate-relay/src/cli/relay_headers.rs @@ -19,11 +19,15 @@ use async_trait::async_trait; use structopt::StructOpt; -use relay_utils::metrics::{GlobalMetrics, StandaloneMetric}; +use relay_utils::{ + metrics::{GlobalMetrics, StandaloneMetric}, + UniqueSaturatedInto, +}; use crate::{ cli::{bridge::*, chain_schema::*, PrometheusParams}, finality::SubstrateFinalitySyncPipeline, + HeadersToRelay, }; /// Chain headers relaying params. @@ -33,6 +37,10 @@ pub struct RelayHeadersParams { /// are relayed. #[structopt(long)] only_mandatory_headers: bool, + /// If passed, only free headers (mandatory and every Nth header, if configured in runtime) + /// are relayed. Overrides `only_mandatory_headers`. + #[structopt(long)] + only_free_headers: bool, #[structopt(flatten)] source: SourceConnectionParams, #[structopt(flatten)] @@ -43,11 +51,37 @@ pub struct RelayHeadersParams { prometheus_params: PrometheusParams, } +/// Single header relaying params. +#[derive(StructOpt)] +pub struct RelayHeaderParams { + #[structopt(flatten)] + source: SourceConnectionParams, + #[structopt(flatten)] + target: TargetConnectionParams, + #[structopt(flatten)] + target_sign: TargetSigningParams, + /// Number of the source chain header that we want to relay. It must have a persistent + /// storage proof at the [`Self::source`] node, otherwise the command will fail. + #[structopt(long)] + number: u128, +} + +impl RelayHeadersParams { + fn headers_to_relay(&self) -> HeadersToRelay { + match (self.only_mandatory_headers, self.only_free_headers) { + (_, true) => HeadersToRelay::Free, + (true, false) => HeadersToRelay::Mandatory, + _ => HeadersToRelay::All, + } + } +} + /// Trait used for relaying headers between 2 chains. #[async_trait] pub trait HeadersRelayer: RelayToRelayHeadersCliBridge { /// Relay headers. async fn relay_headers(data: RelayHeadersParams) -> anyhow::Result<()> { + let headers_to_relay = data.headers_to_relay(); let source_client = data.source.into_client::().await?; let target_client = data.target.into_client::().await?; let target_transactions_mortality = data.target_sign.target_transactions_mortality; @@ -67,10 +101,29 @@ pub trait HeadersRelayer: RelayToRelayHeadersCliBridge { crate::finality::run::( source_client, target_client, - data.only_mandatory_headers, + headers_to_relay, target_transactions_params, metrics_params, ) .await } + + /// Relay single header. No checks are made to ensure that transaction will succeed. + async fn relay_header(data: RelayHeaderParams) -> anyhow::Result<()> { + let source_client = data.source.into_client::().await?; + let target_client = data.target.into_client::().await?; + let target_transactions_mortality = data.target_sign.target_transactions_mortality; + let target_sign = data.target_sign.to_keypair::()?; + + crate::finality::relay_single_header::( + source_client, + target_client, + crate::TransactionParams { + signer: target_sign, + mortality: target_transactions_mortality, + }, + data.number.unique_saturated_into(), + ) + .await + } } diff --git a/bridges/relays/lib-substrate-relay/src/cli/relay_headers_and_messages/mod.rs b/bridges/relays/lib-substrate-relay/src/cli/relay_headers_and_messages/mod.rs index 27e9f1c21ba0dae1480ef8128afdfd635a1d22c2..a796df6721b8c8afd7f401f92e2fca6afcb41b02 100644 --- a/bridges/relays/lib-substrate-relay/src/cli/relay_headers_and_messages/mod.rs +++ b/bridges/relays/lib-substrate-relay/src/cli/relay_headers_and_messages/mod.rs @@ -40,7 +40,7 @@ use crate::{ cli::{bridge::MessagesCliBridge, HexLaneId, PrometheusParams}, messages_lane::{MessagesRelayLimits, MessagesRelayParams}, on_demand::OnDemandRelay, - TaggedAccount, TransactionParams, + HeadersToRelay, TaggedAccount, TransactionParams, }; use bp_messages::LaneId; use bp_runtime::BalanceOf; @@ -61,11 +61,25 @@ pub struct HeadersAndMessagesSharedParams { /// are relayed. #[structopt(long)] pub only_mandatory_headers: bool, + /// If passed, only free headers (mandatory and every Nth header, if configured in runtime) + /// are relayed. Overrides `only_mandatory_headers`. + #[structopt(long)] + pub only_free_headers: bool, #[structopt(flatten)] /// Prometheus metrics params. pub prometheus_params: PrometheusParams, } +impl HeadersAndMessagesSharedParams { + fn headers_to_relay(&self) -> HeadersToRelay { + match (self.only_mandatory_headers, self.only_free_headers) { + (_, true) => HeadersToRelay::Free, + (true, false) => HeadersToRelay::Mandatory, + _ => HeadersToRelay::All, + } + } +} + /// Bridge parameters, shared by all bridge types. pub struct Full2WayBridgeCommonParams< Left: ChainWithTransactions + ChainWithRuntimeVersion, @@ -418,6 +432,7 @@ mod tests { shared: HeadersAndMessagesSharedParams { lane: vec![HexLaneId([0x00, 0x00, 0x00, 0x00])], only_mandatory_headers: false, + only_free_headers: false, prometheus_params: PrometheusParams { no_prometheus: false, prometheus_host: "0.0.0.0".into(), diff --git a/bridges/relays/lib-substrate-relay/src/cli/relay_headers_and_messages/parachain_to_parachain.rs b/bridges/relays/lib-substrate-relay/src/cli/relay_headers_and_messages/parachain_to_parachain.rs index 76accfa29050613070c6579103d4e41f6084eea6..7f6f40777823679c97577f1244eb9a860948d267 100644 --- a/bridges/relays/lib-substrate-relay/src/cli/relay_headers_and_messages/parachain_to_parachain.rs +++ b/bridges/relays/lib-substrate-relay/src/cli/relay_headers_and_messages/parachain_to_parachain.rs @@ -180,7 +180,7 @@ where self.left_relay.clone(), self.common.right.client.clone(), self.common.right.tx_params.clone(), - self.common.shared.only_mandatory_headers, + self.common.shared.headers_to_relay(), Some(self.common.metrics_params.clone()), ); let right_relay_to_left_on_demand_headers = @@ -188,7 +188,7 @@ where self.right_relay.clone(), self.common.left.client.clone(), self.common.left.tx_params.clone(), - self.common.shared.only_mandatory_headers, + self.common.shared.headers_to_relay(), Some(self.common.metrics_params.clone()), ); diff --git a/bridges/relays/lib-substrate-relay/src/cli/relay_headers_and_messages/relay_to_parachain.rs b/bridges/relays/lib-substrate-relay/src/cli/relay_headers_and_messages/relay_to_parachain.rs index b75ac3e60c26934c7dda603a2c7a91649d17eb52..5911fe49df4adfc955cbab4d142998fbc7ed4d22 100644 --- a/bridges/relays/lib-substrate-relay/src/cli/relay_headers_and_messages/relay_to_parachain.rs +++ b/bridges/relays/lib-substrate-relay/src/cli/relay_headers_and_messages/relay_to_parachain.rs @@ -171,7 +171,7 @@ where self.common.left.client.clone(), self.common.right.client.clone(), self.common.right.tx_params.clone(), - self.common.shared.only_mandatory_headers, + self.common.shared.headers_to_relay(), None, ); let right_relay_to_left_on_demand_headers = @@ -179,7 +179,7 @@ where self.right_relay.clone(), self.common.left.client.clone(), self.common.left.tx_params.clone(), - self.common.shared.only_mandatory_headers, + self.common.shared.headers_to_relay(), Some(self.common.metrics_params.clone()), ); let right_to_left_on_demand_parachains = OnDemandParachainsRelay::< diff --git a/bridges/relays/lib-substrate-relay/src/cli/relay_headers_and_messages/relay_to_relay.rs b/bridges/relays/lib-substrate-relay/src/cli/relay_headers_and_messages/relay_to_relay.rs index b397ff50a20a62833d96a3687c8d3c3494efc5c2..832df4ae4003ced1715d7b9d495989d9163417d5 100644 --- a/bridges/relays/lib-substrate-relay/src/cli/relay_headers_and_messages/relay_to_relay.rs +++ b/bridges/relays/lib-substrate-relay/src/cli/relay_headers_and_messages/relay_to_relay.rs @@ -152,7 +152,7 @@ where self.common.left.client.clone(), self.common.right.client.clone(), self.common.right.tx_params.clone(), - self.common.shared.only_mandatory_headers, + self.common.shared.headers_to_relay(), None, ); let right_to_left_on_demand_headers = @@ -160,7 +160,7 @@ where self.common.right.client.clone(), self.common.left.client.clone(), self.common.left.tx_params.clone(), - self.common.shared.only_mandatory_headers, + self.common.shared.headers_to_relay(), None, ); diff --git a/bridges/relays/lib-substrate-relay/src/cli/relay_messages.rs b/bridges/relays/lib-substrate-relay/src/cli/relay_messages.rs index b672bd4f9b86812c87532012debb89e0a601451f..e5b07b241581e07d0a2b4c839f3dc6accf7bb523 100644 --- a/bridges/relays/lib-substrate-relay/src/cli/relay_messages.rs +++ b/bridges/relays/lib-substrate-relay/src/cli/relay_messages.rs @@ -26,9 +26,12 @@ use async_trait::async_trait; use sp_core::Pair; use structopt::StructOpt; +use bp_messages::MessageNonce; +use bp_runtime::HeaderIdProvider; use relay_substrate_client::{ - AccountIdOf, AccountKeyPairOf, BalanceOf, ChainWithRuntimeVersion, ChainWithTransactions, + AccountIdOf, AccountKeyPairOf, BalanceOf, Chain, ChainWithRuntimeVersion, ChainWithTransactions, }; +use relay_utils::UniqueSaturatedInto; /// Messages relaying params. #[derive(StructOpt)] @@ -48,6 +51,35 @@ pub struct RelayMessagesParams { prometheus_params: PrometheusParams, } +/// Messages range relaying params. +#[derive(StructOpt)] +pub struct RelayMessagesRangeParams { + /// Number of the source chain header that we will use to prepare a messages proof. + /// This header must be previously proved to the target chain. + #[structopt(long)] + at_source_block: u128, + /// Hex-encoded lane id that should be served by the relay. Defaults to `00000000`. + #[structopt(long, default_value = "00000000")] + lane: HexLaneId, + /// Nonce (inclusive) of the first message to relay. + #[structopt(long)] + messages_start: MessageNonce, + /// Nonce (inclusive) of the last message to relay. + #[structopt(long)] + messages_end: MessageNonce, + /// Whether the outbound lane state proof should be included into transaction. + #[structopt(long)] + outbound_state_proof_required: bool, + #[structopt(flatten)] + source: SourceConnectionParams, + #[structopt(flatten)] + source_sign: SourceSigningParams, + #[structopt(flatten)] + target: TargetConnectionParams, + #[structopt(flatten)] + target_sign: TargetSigningParams, +} + /// Trait used for relaying messages between 2 chains. #[async_trait] pub trait MessagesRelayer: MessagesCliBridge @@ -86,4 +118,40 @@ where .await .map_err(|e| anyhow::format_err!("{}", e)) } + + /// Relay a consequitive range of messages. + async fn relay_messages_range(data: RelayMessagesRangeParams) -> anyhow::Result<()> { + let source_client = data.source.into_client::().await?; + let target_client = data.target.into_client::().await?; + let source_sign = data.source_sign.to_keypair::()?; + let source_transactions_mortality = data.source_sign.transactions_mortality()?; + let target_sign = data.target_sign.to_keypair::()?; + let target_transactions_mortality = data.target_sign.transactions_mortality()?; + + let at_source_block = source_client + .header_by_number(data.at_source_block.unique_saturated_into()) + .await + .map_err(|e| { + log::trace!( + target: "bridge", + "Failed to read {} header with number {}: {e:?}", + Self::Source::NAME, + data.at_source_block, + ); + anyhow::format_err!("The command has failed") + })? + .id(); + + crate::messages_lane::relay_messages_range::( + source_client, + target_client, + TransactionParams { signer: source_sign, mortality: source_transactions_mortality }, + TransactionParams { signer: target_sign, mortality: target_transactions_mortality }, + at_source_block, + data.lane.into(), + data.messages_start..=data.messages_end, + data.outbound_state_proof_required, + ) + .await + } } diff --git a/bridges/relays/lib-substrate-relay/src/cli/relay_parachains.rs b/bridges/relays/lib-substrate-relay/src/cli/relay_parachains.rs index e5a52349469bbdf36c7de228078d8d10b0e882f0..00f8cf79ef1fb54577954cf198e7296819591a43 100644 --- a/bridges/relays/lib-substrate-relay/src/cli/relay_parachains.rs +++ b/bridges/relays/lib-substrate-relay/src/cli/relay_parachains.rs @@ -18,6 +18,8 @@ use async_std::sync::Mutex; use async_trait::async_trait; +use bp_polkadot_core::BlockNumber as RelayBlockNumber; +use bp_runtime::HeaderIdProvider; use parachains_relay::parachains_loop::{AvailableHeader, SourceClient, TargetClient}; use relay_substrate_client::Parachain; use relay_utils::metrics::{GlobalMetrics, StandaloneMetric}; @@ -43,10 +45,29 @@ pub struct RelayParachainsParams { target: TargetConnectionParams, #[structopt(flatten)] target_sign: TargetSigningParams, + /// If passed, only free headers (those, available at "free" relay chain headers) + /// are relayed. + #[structopt(long)] + only_free_headers: bool, #[structopt(flatten)] prometheus_params: PrometheusParams, } +/// Single parachains head relaying params. +#[derive(StructOpt)] +pub struct RelayParachainHeadParams { + #[structopt(flatten)] + source: SourceConnectionParams, + #[structopt(flatten)] + target: TargetConnectionParams, + #[structopt(flatten)] + target_sign: TargetSigningParams, + /// Prove parachain head at that relay block number. This relay header must be previously + /// proved to the target chain. + #[structopt(long)] + at_relay_block: RelayBlockNumber, +} + /// Trait used for relaying parachains finality between 2 chains. #[async_trait] pub trait ParachainsRelayer: ParachainToRelayHeadersCliBridge @@ -59,9 +80,9 @@ where { /// Start relaying parachains finality. async fn relay_parachains(data: RelayParachainsParams) -> anyhow::Result<()> { - let source_client = data.source.into_client::().await?; + let source_chain_client = data.source.into_client::().await?; let source_client = ParachainsSource::::new( - source_client, + source_chain_client.clone(), Arc::new(Mutex::new(AvailableHeader::Missing)), ); @@ -69,9 +90,10 @@ where signer: data.target_sign.to_keypair::()?, mortality: data.target_sign.target_transactions_mortality, }; - let target_client = data.target.into_client::().await?; + let target_chain_client = data.target.into_client::().await?; let target_client = ParachainsTarget::::new( - target_client.clone(), + source_chain_client, + target_chain_client, target_transaction_params, ); @@ -83,9 +105,44 @@ where source_client, target_client, metrics_params, + data.only_free_headers, futures::future::pending(), ) .await .map_err(|e| anyhow::format_err!("{}", e)) } + + /// Relay single parachain head. No checks are made to ensure that transaction will succeed. + async fn relay_parachain_head(data: RelayParachainHeadParams) -> anyhow::Result<()> { + let source_chain_client = data.source.into_client::().await?; + let at_relay_block = source_chain_client + .header_by_number(data.at_relay_block) + .await + .map_err(|e| anyhow::format_err!("{}", e))? + .id(); + + let source_client = ParachainsSource::::new( + source_chain_client.clone(), + Arc::new(Mutex::new(AvailableHeader::Missing)), + ); + + let target_transaction_params = TransactionParams { + signer: data.target_sign.to_keypair::()?, + mortality: data.target_sign.target_transactions_mortality, + }; + let target_chain_client = data.target.into_client::().await?; + let target_client = ParachainsTarget::::new( + source_chain_client, + target_chain_client, + target_transaction_params, + ); + + parachains_relay::parachains_loop::relay_single_head( + source_client, + target_client, + at_relay_block, + ) + .await + .map_err(|_| anyhow::format_err!("The command has failed")) + } } diff --git a/bridges/relays/lib-substrate-relay/src/finality/mod.rs b/bridges/relays/lib-substrate-relay/src/finality/mod.rs index 206f628b143b8a085dec9a0ef5de929c178c25f6..0293e1da224a6323fed59f7f727b5d5263391bb8 100644 --- a/bridges/relays/lib-substrate-relay/src/finality/mod.rs +++ b/bridges/relays/lib-substrate-relay/src/finality/mod.rs @@ -25,13 +25,15 @@ use crate::{ use async_trait::async_trait; use bp_header_chain::justification::{GrandpaJustification, JustificationVerificationContext}; -use finality_relay::{FinalityPipeline, FinalitySyncPipeline}; +use finality_relay::{ + FinalityPipeline, FinalitySyncPipeline, HeadersToRelay, SourceClient, TargetClient, +}; use pallet_bridge_grandpa::{Call as BridgeGrandpaCall, Config as BridgeGrandpaConfig}; use relay_substrate_client::{ transaction_stall_timeout, AccountIdOf, AccountKeyPairOf, BlockNumberOf, CallOf, Chain, ChainWithTransactions, Client, HashOf, HeaderOf, SyncHeader, }; -use relay_utils::metrics::MetricsParams; +use relay_utils::{metrics::MetricsParams, TrackedTransactionStatus, TransactionTracker}; use sp_core::Pair; use std::{fmt::Debug, marker::PhantomData}; @@ -115,6 +117,7 @@ pub trait SubmitFinalityProofCallBuilder { fn build_submit_finality_proof_call( header: SyncHeader>, proof: SubstrateFinalityProof

, + is_free_execution_expected: bool, context: <

::FinalityEngine as Engine>::FinalityVerificationContext, ) -> CallOf; } @@ -142,6 +145,7 @@ where fn build_submit_finality_proof_call( header: SyncHeader>, proof: GrandpaJustification>, + _is_free_execution_expected: bool, _context: JustificationVerificationContext, ) -> CallOf { BridgeGrandpaCall::::submit_finality_proof { @@ -176,6 +180,7 @@ macro_rules! generate_submit_finality_proof_call_builder { <$pipeline as $crate::finality_base::SubstrateFinalityPipeline>::SourceChain > >, + _is_free_execution_expected: bool, _context: bp_header_chain::justification::JustificationVerificationContext, ) -> relay_substrate_client::CallOf< <$pipeline as $crate::finality_base::SubstrateFinalityPipeline>::TargetChain @@ -215,6 +220,7 @@ macro_rules! generate_submit_finality_proof_ex_call_builder { <$pipeline as $crate::finality_base::SubstrateFinalityPipeline>::SourceChain > >, + is_free_execution_expected: bool, context: bp_header_chain::justification::JustificationVerificationContext, ) -> relay_substrate_client::CallOf< <$pipeline as $crate::finality_base::SubstrateFinalityPipeline>::TargetChain @@ -223,7 +229,8 @@ macro_rules! generate_submit_finality_proof_ex_call_builder { $bridge_grandpa($submit_finality_proof { finality_target: Box::new(header.into_inner()), justification: proof, - current_set_id: context.authority_set_id + current_set_id: context.authority_set_id, + is_free_execution_expected, }) } } @@ -235,15 +242,16 @@ macro_rules! generate_submit_finality_proof_ex_call_builder { pub async fn run( source_client: Client, target_client: Client, - only_mandatory_headers: bool, + headers_to_relay: HeadersToRelay, transaction_params: TransactionParams>, metrics_params: MetricsParams, ) -> anyhow::Result<()> { log::info!( target: "bridge", - "Starting {} -> {} finality proof relay", + "Starting {} -> {} finality proof relay: relaying {:?} headers", P::SourceChain::NAME, P::TargetChain::NAME, + headers_to_relay, ); finality_relay::run( @@ -260,7 +268,7 @@ pub async fn run( P::TargetChain::AVERAGE_BLOCK_INTERVAL, relay_utils::STALL_TIMEOUT, ), - only_mandatory_headers, + headers_to_relay, }, metrics_params, futures::future::pending(), @@ -268,3 +276,34 @@ pub async fn run( .await .map_err(|e| anyhow::format_err!("{}", e)) } + +/// Relay single header. No checks are made to ensure that transaction will succeed. +pub async fn relay_single_header( + source_client: Client, + target_client: Client, + transaction_params: TransactionParams>, + header_number: BlockNumberOf, +) -> anyhow::Result<()> { + let finality_source = SubstrateFinalitySource::

::new(source_client, None); + let (header, proof) = finality_source.header_and_finality_proof(header_number).await?; + let Some(proof) = proof else { + return Err(anyhow::format_err!( + "Unable to submit {} header #{} to {}: no finality proof", + P::SourceChain::NAME, + header_number, + P::TargetChain::NAME, + )); + }; + + let finality_target = SubstrateFinalityTarget::

::new(target_client, transaction_params); + let tx_tracker = finality_target.submit_finality_proof(header, proof, false).await?; + match tx_tracker.wait().await { + TrackedTransactionStatus::Finalized(_) => Ok(()), + TrackedTransactionStatus::Lost => Err(anyhow::format_err!( + "Transaction with {} header #{} is considered lost at {}", + P::SourceChain::NAME, + header_number, + P::TargetChain::NAME, + )), + } +} diff --git a/bridges/relays/lib-substrate-relay/src/finality/target.rs b/bridges/relays/lib-substrate-relay/src/finality/target.rs index 18464d523f4f6cf4c9c165af82f6b7c2c2504070..0874fa53549c59f413a2f3f0c4f3dbc582fe0090 100644 --- a/bridges/relays/lib-substrate-relay/src/finality/target.rs +++ b/bridges/relays/lib-substrate-relay/src/finality/target.rs @@ -25,9 +25,10 @@ use crate::{ }; use async_trait::async_trait; +use bp_runtime::BlockNumberOf; use finality_relay::TargetClient; use relay_substrate_client::{ - AccountKeyPairOf, Client, Error, HeaderIdOf, HeaderOf, SyncHeader, TransactionEra, + AccountKeyPairOf, Chain, Client, Error, HeaderIdOf, HeaderOf, SyncHeader, TransactionEra, TransactionTracker, UnsignedTransaction, }; use relay_utils::relay_loop::Client as RelayClient; @@ -103,10 +104,34 @@ impl TargetClient Result>, Self::Error> { + Ok(self + .client + .typed_state_call( + P::SourceChain::FREE_HEADERS_INTERVAL_METHOD.into(), + (), + Some(self.client.best_header().await?.hash()), + ) + .await + .unwrap_or_else(|e| { + log::info!( + target: "bridge", + "Call of {} at {} has failed with an error: {:?}. Treating as `None`", + P::SourceChain::FREE_HEADERS_INTERVAL_METHOD, + P::TargetChain::NAME, + e, + ); + None + })) + } + async fn submit_finality_proof( &self, header: SyncHeader>, mut proof: SubstrateFinalityProof

, + is_free_execution_expected: bool, ) -> Result { // verify and runtime module at target chain may require optimized finality proof let context = @@ -115,7 +140,10 @@ impl TargetClient Substrate messages synchronization pipeline. pub trait SubstrateMessageLane: 'static + Clone + Debug + Send + Sync { @@ -275,6 +275,49 @@ where .map_err(Into::into) } +/// Deliver range of Substrate-to-Substrate messages. No checks are made to ensure that transaction +/// will succeed. +pub async fn relay_messages_range( + source_client: Client, + target_client: Client, + source_transaction_params: TransactionParams>, + target_transaction_params: TransactionParams>, + at_source_block: HeaderIdOf, + lane_id: LaneId, + range: RangeInclusive, + outbound_state_proof_required: bool, +) -> anyhow::Result<()> +where + AccountIdOf: From< as Pair>::Public>, + AccountIdOf: From< as Pair>::Public>, + BalanceOf: TryFrom>, +{ + let relayer_id_at_source: AccountIdOf = + source_transaction_params.signer.public().into(); + messages_relay::relay_messages_range( + SubstrateMessagesSource::

::new( + source_client.clone(), + target_client.clone(), + lane_id, + source_transaction_params, + None, + ), + SubstrateMessagesTarget::

::new( + target_client, + source_client, + lane_id, + relayer_id_at_source, + target_transaction_params, + None, + ), + at_source_block, + range, + outbound_state_proof_required, + ) + .await + .map_err(|_| anyhow::format_err!("The command has failed")) +} + /// Different ways of building `receive_messages_proof` calls. pub trait ReceiveMessagesProofCallBuilder { /// Given messages proof, build call of `receive_messages_proof` function of bridge diff --git a/bridges/relays/lib-substrate-relay/src/messages_metrics.rs b/bridges/relays/lib-substrate-relay/src/messages_metrics.rs index 27bf6186c3ba0d0db6552128574c8759d45d220c..b30e75bd8bacbbd25c056eb7d499cc18d040f991 100644 --- a/bridges/relays/lib-substrate-relay/src/messages_metrics.rs +++ b/bridges/relays/lib-substrate-relay/src/messages_metrics.rs @@ -32,7 +32,7 @@ use relay_substrate_client::{ use relay_utils::metrics::{MetricsParams, StandaloneMetric}; use sp_core::storage::StorageData; use sp_runtime::{FixedPointNumber, FixedU128}; -use std::{convert::TryFrom, fmt::Debug, marker::PhantomData}; +use std::{fmt::Debug, marker::PhantomData}; /// Add relay accounts balance metrics. pub async fn add_relay_balances_metrics( diff --git a/bridges/relays/lib-substrate-relay/src/messages_target.rs b/bridges/relays/lib-substrate-relay/src/messages_target.rs index 9396e785530d2ec5855e332e8db3dd7836938f25..633b11f0b8028636fdb8c9c6b4f1ec5fa42ccf33 100644 --- a/bridges/relays/lib-substrate-relay/src/messages_target.rs +++ b/bridges/relays/lib-substrate-relay/src/messages_target.rs @@ -45,7 +45,7 @@ use relay_substrate_client::{ }; use relay_utils::relay_loop::Client as RelayClient; use sp_core::Pair; -use std::{convert::TryFrom, ops::RangeInclusive}; +use std::ops::RangeInclusive; /// Message receiving proof returned by the target Substrate node. pub type SubstrateMessagesDeliveryProof = diff --git a/bridges/relays/lib-substrate-relay/src/on_demand/headers.rs b/bridges/relays/lib-substrate-relay/src/on_demand/headers.rs index e8a2a3c6c58aaedeb55da67871d0ddb51830338d..74f3a70c5e81bbc1d27162a74fb8dadab46a6d09 100644 --- a/bridges/relays/lib-substrate-relay/src/on_demand/headers.rs +++ b/bridges/relays/lib-substrate-relay/src/on_demand/headers.rs @@ -28,7 +28,7 @@ use futures::{select, FutureExt}; use num_traits::{One, Saturating, Zero}; use sp_runtime::traits::Header; -use finality_relay::{FinalitySyncParams, TargetClient as FinalityTargetClient}; +use finality_relay::{FinalitySyncParams, HeadersToRelay, TargetClient as FinalityTargetClient}; use relay_substrate_client::{ AccountIdOf, AccountKeyPairOf, BlockNumberOf, CallOf, Chain, Client, Error as SubstrateError, HeaderIdOf, @@ -75,7 +75,7 @@ impl OnDemandHeadersRelay

{ source_client: Client, target_client: Client, target_transaction_params: TransactionParams>, - only_mandatory_headers: bool, + headers_to_relay: HeadersToRelay, metrics_params: Option, ) -> Self where @@ -94,7 +94,7 @@ impl OnDemandHeadersRelay

{ source_client, target_client, target_transaction_params, - only_mandatory_headers, + headers_to_relay, required_header_number, metrics_params, ) @@ -191,7 +191,7 @@ impl OnDemandRelay( source_client: Client, target_client: Client, target_transaction_params: TransactionParams>, - only_mandatory_headers: bool, + headers_to_relay: HeadersToRelay, required_header_number: RequiredHeaderNumberRef, metrics_params: Option, ) where @@ -346,11 +346,11 @@ async fn background_task( log::info!( target: "bridge", "[{}] Starting on-demand headers relay task\n\t\ - Only mandatory headers: {}\n\t\ + Headers to relay: {:?}\n\t\ Tx mortality: {:?} (~{}m)\n\t\ Stall timeout: {:?}", relay_task_name, - only_mandatory_headers, + headers_to_relay, target_transactions_mortality, stall_timeout.as_secs_f64() / 60.0f64, stall_timeout, @@ -367,7 +367,7 @@ async fn background_task( ), recent_finality_proofs_limit: RECENT_FINALITY_PROOFS_LIMIT, stall_timeout, - only_mandatory_headers, + headers_to_relay, }, metrics_params.clone().unwrap_or_else(MetricsParams::disabled), futures::future::pending(), diff --git a/bridges/relays/lib-substrate-relay/src/on_demand/parachains.rs b/bridges/relays/lib-substrate-relay/src/on_demand/parachains.rs index f67c002bba7f9c61925cb83e96433dbd40db7d4b..966bdc3107203a61cf405adba2cf09124330954e 100644 --- a/bridges/relays/lib-substrate-relay/src/on_demand/parachains.rs +++ b/bridges/relays/lib-substrate-relay/src/on_demand/parachains.rs @@ -222,6 +222,7 @@ where proved_relay_block, vec![(para_id, para_hash)], para_proof, + false, )); Ok((proved_parachain_block, calls)) @@ -256,8 +257,11 @@ async fn background_task( let mut parachains_source = ParachainsSource::

::new(source_relay_client.clone(), required_para_header_ref.clone()); - let mut parachains_target = - ParachainsTarget::

::new(target_client.clone(), target_transaction_params.clone()); + let mut parachains_target = ParachainsTarget::

::new( + source_relay_client.clone(), + target_client.clone(), + target_transaction_params.clone(), + ); loop { select! { @@ -392,6 +396,8 @@ async fn background_task( parachains_source.clone(), parachains_target.clone(), MetricsParams::disabled(), + // we do not support free parachain headers relay in on-demand relays + false, futures::future::pending(), ) .fuse(), @@ -481,7 +487,7 @@ where let para_header_at_target = best_finalized_peer_header_at_self::< P::TargetChain, P::SourceParachain, - >(target.client(), best_target_block_hash) + >(target.target_client(), best_target_block_hash) .await; // if there are no parachain heads at the target (`NoParachainHeadAtTarget`), we'll need to // submit at least one. Otherwise the pallet will be treated as uninitialized and messages @@ -504,7 +510,7 @@ where let relay_header_at_target = best_finalized_peer_header_at_self::< P::TargetChain, P::SourceRelayChain, - >(target.client(), best_target_block_hash) + >(target.target_client(), best_target_block_hash) .await .map_err(map_target_err)?; diff --git a/bridges/relays/lib-substrate-relay/src/parachains/mod.rs b/bridges/relays/lib-substrate-relay/src/parachains/mod.rs index 722f9b61f9f08d87dac3bd95a0780d8422097a38..8b128bb770dd7a05d28ad46d4561f4d859b1deb6 100644 --- a/bridges/relays/lib-substrate-relay/src/parachains/mod.rs +++ b/bridges/relays/lib-substrate-relay/src/parachains/mod.rs @@ -71,6 +71,7 @@ pub trait SubmitParachainHeadsCallBuilder: at_relay_block: HeaderIdOf, parachains: Vec<(ParaId, ParaHash)>, parachain_heads_proof: ParaHeadsProof, + is_free_execution_expected: bool, ) -> CallOf; } @@ -97,6 +98,7 @@ where at_relay_block: HeaderIdOf, parachains: Vec<(ParaId, ParaHash)>, parachain_heads_proof: ParaHeadsProof, + _is_free_execution_expected: bool, ) -> CallOf { BridgeParachainsCall::::submit_parachain_heads { at_relay_block: (at_relay_block.0, at_relay_block.1), diff --git a/bridges/relays/lib-substrate-relay/src/parachains/target.rs b/bridges/relays/lib-substrate-relay/src/parachains/target.rs index 6df7bc0a742a9f6693a422b994c7a9203f3c8b74..531d55b53223609c523d521f43a38336353c597f 100644 --- a/bridges/relays/lib-substrate-relay/src/parachains/target.rs +++ b/bridges/relays/lib-substrate-relay/src/parachains/target.rs @@ -24,42 +24,53 @@ use crate::{ }; use async_trait::async_trait; -use bp_polkadot_core::parachains::{ParaHash, ParaHeadsProof, ParaId}; -use bp_runtime::HeaderIdProvider; -use codec::Decode; +use bp_parachains::{ + ImportedParaHeadsKeyProvider, ParaInfo, ParaStoredHeaderData, ParasInfoKeyProvider, +}; +use bp_polkadot_core::{ + parachains::{ParaHash, ParaHeadsProof, ParaId}, + BlockNumber as RelayBlockNumber, +}; +use bp_runtime::{ + Chain as ChainBase, HeaderId, HeaderIdProvider, StorageDoubleMapKeyProvider, + StorageMapKeyProvider, +}; use parachains_relay::parachains_loop::TargetClient; use relay_substrate_client::{ - AccountIdOf, AccountKeyPairOf, Chain, Client, Error as SubstrateError, HeaderIdOf, - ParachainBase, TransactionEra, TransactionTracker, UnsignedTransaction, + AccountIdOf, AccountKeyPairOf, BlockNumberOf, Chain, Client, Error as SubstrateError, + HeaderIdOf, ParachainBase, RelayChain, TransactionEra, TransactionTracker, UnsignedTransaction, }; use relay_utils::relay_loop::Client as RelayClient; -use sp_core::{Bytes, Pair}; +use sp_core::Pair; /// Substrate client as parachain heads source. pub struct ParachainsTarget { - client: Client, + source_client: Client, + target_client: Client, transaction_params: TransactionParams>, } impl ParachainsTarget

{ /// Creates new parachains target client. pub fn new( - client: Client, + source_client: Client, + target_client: Client, transaction_params: TransactionParams>, ) -> Self { - ParachainsTarget { client, transaction_params } + ParachainsTarget { source_client, target_client, transaction_params } } /// Returns reference to the underlying RPC client. - pub fn client(&self) -> &Client { - &self.client + pub fn target_client(&self) -> &Client { + &self.target_client } } impl Clone for ParachainsTarget

{ fn clone(&self) -> Self { ParachainsTarget { - client: self.client.clone(), + source_client: self.source_client.clone(), + target_client: self.target_client.clone(), transaction_params: self.transaction_params.clone(), } } @@ -70,7 +81,9 @@ impl RelayClient for ParachainsTarget

{ type Error = SubstrateError; async fn reconnect(&mut self) -> Result<(), SubstrateError> { - self.client.reconnect().await + self.target_client.reconnect().await?; + self.source_client.reconnect().await?; + Ok(()) } } @@ -79,11 +92,13 @@ impl

TargetClient> for ParachainsTarget

where P: SubstrateParachainsPipeline, AccountIdOf: From< as Pair>::Public>, + P::SourceParachain: ChainBase, + P::SourceRelayChain: ChainBase, { type TransactionTracker = TransactionTracker>; async fn best_block(&self) -> Result, Self::Error> { - let best_header = self.client.best_header().await?; + let best_header = self.target_client.best_header().await?; let best_id = best_header.id(); Ok(best_id) @@ -93,7 +108,7 @@ where &self, at_block: &HeaderIdOf, ) -> Result, Self::Error> { - self.client + self.target_client .typed_state_call::<_, Option>>( P::SourceRelayChain::BEST_FINALIZED_HEADER_ID_METHOD.into(), (), @@ -104,23 +119,68 @@ where .unwrap_or(Err(SubstrateError::BridgePalletIsNotInitialized)) } + async fn free_source_relay_headers_interval( + &self, + ) -> Result>, Self::Error> { + Ok(self + .target_client + .typed_state_call(P::SourceRelayChain::FREE_HEADERS_INTERVAL_METHOD.into(), (), None) + .await + .unwrap_or_else(|e| { + log::info!( + target: "bridge", + "Call of {} at {} has failed with an error: {:?}. Treating as `None`", + P::SourceRelayChain::FREE_HEADERS_INTERVAL_METHOD, + P::TargetChain::NAME, + e, + ); + None + })) + } + async fn parachain_head( &self, at_block: HeaderIdOf, - ) -> Result>, Self::Error> { - let encoded_best_finalized_source_para_block = self - .client - .state_call( - P::SourceParachain::BEST_FINALIZED_HEADER_ID_METHOD.into(), - Bytes(Vec::new()), - Some(at_block.1), - ) - .await?; + ) -> Result< + Option<(HeaderIdOf, HeaderIdOf)>, + Self::Error, + > { + // read best parachain head from the target bridge-parachains pallet + let storage_key = ParasInfoKeyProvider::final_key( + P::SourceRelayChain::WITH_CHAIN_BRIDGE_PARACHAINS_PALLET_NAME, + &P::SourceParachain::PARACHAIN_ID.into(), + ); + let storage_value: Option = + self.target_client.storage_value(storage_key, Some(at_block.hash())).await?; + let para_info = match storage_value { + Some(para_info) => para_info, + None => return Ok(None), + }; + + // now we need to get full header ids. For source relay chain it is simple, because we + // are connected + let relay_header_id = self + .source_client + .header_by_number(para_info.best_head_hash.at_relay_block_number) + .await? + .id(); - Ok(Option::>::decode( - &mut &encoded_best_finalized_source_para_block.0[..], - ) - .map_err(SubstrateError::ResponseParseFailed)?) + // for parachain, we need to read from the target chain runtime storage + let storage_key = ImportedParaHeadsKeyProvider::final_key( + P::SourceRelayChain::WITH_CHAIN_BRIDGE_PARACHAINS_PALLET_NAME, + &P::SourceParachain::PARACHAIN_ID.into(), + ¶_info.best_head_hash.head_hash, + ); + let storage_value: Option = + self.target_client.storage_value(storage_key, Some(at_block.hash())).await?; + let para_head_number = match storage_value { + Some(para_head_data) => + para_head_data.decode_parachain_head_data::()?.number, + None => return Ok(None), + }; + + let para_head_id = HeaderId(para_head_number, para_info.best_head_hash.head_hash); + Ok(Some((relay_header_id, para_head_id))) } async fn submit_parachain_head_proof( @@ -128,14 +188,16 @@ where at_relay_block: HeaderIdOf, updated_head_hash: ParaHash, proof: ParaHeadsProof, + is_free_execution_expected: bool, ) -> Result { let transaction_params = self.transaction_params.clone(); let call = P::SubmitParachainHeadsCallBuilder::build_submit_parachain_heads_call( at_relay_block, vec![(ParaId(P::SourceParachain::PARACHAIN_ID), updated_head_hash)], proof, + is_free_execution_expected, ); - self.client + self.target_client .submit_and_watch_signed_extrinsic( &transaction_params.signer, move |best_block_id, transaction_nonce| { diff --git a/bridges/relays/messages/src/lib.rs b/bridges/relays/messages/src/lib.rs index 9c62cee5ee3db1e0b8825d2893d53422bf44a33c..7c18b6b148f3427b6a3b9c545d2fb5dcbecc5cd3 100644 --- a/bridges/relays/messages/src/lib.rs +++ b/bridges/relays/messages/src/lib.rs @@ -35,3 +35,5 @@ mod message_race_limits; mod message_race_loop; mod message_race_receiving; mod message_race_strategy; + +pub use message_race_delivery::relay_messages_range; diff --git a/bridges/relays/messages/src/message_race_delivery.rs b/bridges/relays/messages/src/message_race_delivery.rs index f18c43cc7f0e084100d8096432dccafbd61301be..cbb89baabcc5ab38f164189066e225ad1e8f9240 100644 --- a/bridges/relays/messages/src/message_race_delivery.rs +++ b/bridges/relays/messages/src/message_race_delivery.rs @@ -19,7 +19,7 @@ use async_trait::async_trait; use futures::stream::FusedStream; use bp_messages::{MessageNonce, UnrewardedRelayersState, Weight}; -use relay_utils::FailedClient; +use relay_utils::{FailedClient, TrackedTransactionStatus, TransactionTracker}; use crate::{ message_lane::{MessageLane, SourceHeaderIdOf, TargetHeaderIdOf}, @@ -77,6 +77,69 @@ pub async fn run( .await } +/// Relay range of messages. +pub async fn relay_messages_range( + source_client: impl MessageLaneSourceClient

, + target_client: impl MessageLaneTargetClient

, + at: SourceHeaderIdOf

, + range: RangeInclusive, + outbound_state_proof_required: bool, +) -> Result<(), ()> { + // compute cumulative dispatch weight of all messages in given range + let dispatch_weight = source_client + .generated_message_details(at.clone(), range.clone()) + .await + .map_err(|e| { + log::error!( + target: "bridge", + "Failed to get generated message details at {:?} for messages {:?}: {:?}", + at, + range, + e, + ); + })? + .values() + .fold(Weight::zero(), |total, details| total.saturating_add(details.dispatch_weight)); + // prepare messages proof + let (at, range, proof) = source_client + .prove_messages( + at.clone(), + range.clone(), + MessageProofParameters { outbound_state_proof_required, dispatch_weight }, + ) + .await + .map_err(|e| { + log::error!( + target: "bridge", + "Failed to generate messages proof at {:?} for messages {:?}: {:?}", + at, + range, + e, + ); + })?; + // submit messages proof to the target node + let tx_tracker = target_client + .submit_messages_proof(None, at, range.clone(), proof) + .await + .map_err(|e| { + log::error!( + target: "bridge", + "Failed to submit messages proof for messages {:?}: {:?}", + range, + e, + ); + })? + .tx_tracker; + + match tx_tracker.wait().await { + TrackedTransactionStatus::Finalized(_) => Ok(()), + TrackedTransactionStatus::Lost => { + log::error!("Transaction with messages {:?} is considered lost", range,); + Err(()) + }, + } +} + /// Message delivery race. struct MessageDeliveryRace

(std::marker::PhantomData

); diff --git a/bridges/relays/parachains/Cargo.toml b/bridges/relays/parachains/Cargo.toml index a73a2f5b31c1aca5d93bf0b871b79b5e279da6ff..8d38e4e6bd07c2420adcf233729c1bac9bb77c37 100644 --- a/bridges/relays/parachains/Cargo.toml +++ b/bridges/relays/parachains/Cargo.toml @@ -23,6 +23,6 @@ bp-polkadot-core = { path = "../../primitives/polkadot-core" } relay-substrate-client = { path = "../client-substrate" } [dev-dependencies] -codec = { package = "parity-scale-codec", version = "3.6.1" } +codec = { package = "parity-scale-codec", version = "3.6.12" } relay-substrate-client = { path = "../client-substrate", features = ["test-helpers"] } sp-core = { path = "../../../substrate/primitives/core" } diff --git a/bridges/relays/parachains/src/parachains_loop.rs b/bridges/relays/parachains/src/parachains_loop.rs index 41ebbf5aadede2b4a1f0c9dcde73ee83bd5b0766..fd73ca2d46c00f8e05bb05a14a7fa4104ef898c4 100644 --- a/bridges/relays/parachains/src/parachains_loop.rs +++ b/bridges/relays/parachains/src/parachains_loop.rs @@ -25,7 +25,7 @@ use futures::{ future::{FutureExt, Shared}, poll, select_biased, }; -use relay_substrate_client::{Chain, HeaderIdOf, ParachainBase}; +use relay_substrate_client::{BlockNumberOf, Chain, HeaderIdOf, ParachainBase}; use relay_utils::{ metrics::MetricsParams, relay_loop::Client as RelayClient, FailedClient, TrackedTransactionStatus, TransactionTracker, @@ -96,17 +96,27 @@ pub trait TargetClient: RelayClient { /// Get best block id. async fn best_block(&self) -> Result, Self::Error>; - /// Get best finalized source relay chain block id. + /// Get best finalized source relay chain block id. If `free_source_relay_headers_interval` + /// is `Some(_)`, the returned async fn best_finalized_source_relay_chain_block( &self, at_block: &HeaderIdOf, ) -> Result, Self::Error>; + /// Get free source **relay** headers submission interval, if it is configured in the + /// target runtime. We assume that the target chain will accept parachain header, proved + /// at such relay header for free. + async fn free_source_relay_headers_interval( + &self, + ) -> Result>, Self::Error>; /// Get parachain head id at given block. async fn parachain_head( &self, at_block: HeaderIdOf, - ) -> Result>, Self::Error>; + ) -> Result< + Option<(HeaderIdOf, HeaderIdOf)>, + Self::Error, + >; /// Submit parachain heads proof. async fn submit_parachain_head_proof( @@ -114,6 +124,7 @@ pub trait TargetClient: RelayClient { at_source_block: HeaderIdOf, para_head_hash: ParaHash, proof: ParaHeadsProof, + is_free_execution_expected: bool, ) -> Result; } @@ -128,11 +139,39 @@ pub fn metrics_prefix() -> String { ) } +/// Relay single parachain head. +pub async fn relay_single_head( + source_client: impl SourceClient

, + target_client: impl TargetClient

, + at_relay_block: HeaderIdOf, +) -> Result<(), ()> +where + P::SourceRelayChain: Chain, +{ + let tx_tracker = + submit_selected_head::(&source_client, &target_client, at_relay_block, false) + .await + .map_err(drop)?; + match tx_tracker.wait().await { + TrackedTransactionStatus::Finalized(_) => Ok(()), + TrackedTransactionStatus::Lost => { + log::error!( + "Transaction with {} header at relay header {:?} is considered lost at {}", + P::SourceParachain::NAME, + at_relay_block, + P::TargetChain::NAME, + ); + Err(()) + }, + } +} + /// Run parachain heads synchronization. pub async fn run( source_client: impl SourceClient

, target_client: impl TargetClient

, metrics_params: MetricsParams, + only_free_headers: bool, exit_signal: impl Future + 'static + Send, ) -> Result<(), relay_utils::Error> where @@ -145,7 +184,13 @@ where .expose() .await? .run(metrics_prefix::

(), move |source_client, target_client, metrics| { - run_until_connection_lost(source_client, target_client, metrics, exit_signal.clone()) + run_until_connection_lost( + source_client, + target_client, + metrics, + only_free_headers, + exit_signal.clone(), + ) }) .await } @@ -155,6 +200,7 @@ async fn run_until_connection_lost( source_client: impl SourceClient

, target_client: impl TargetClient

, metrics: Option, + only_free_headers: bool, exit_signal: impl Future + Send, ) -> Result<(), FailedClient> where @@ -166,6 +212,47 @@ where P::TargetChain::AVERAGE_BLOCK_INTERVAL, ); + // free parachain header = header, available (proved) at free relay chain block. Let's + // read interval of free source relay chain blocks from target client + let free_source_relay_headers_interval = if only_free_headers { + let free_source_relay_headers_interval = + target_client.free_source_relay_headers_interval().await.map_err(|e| { + log::warn!( + target: "bridge", + "Failed to read free {} headers interval at {}: {:?}", + P::SourceRelayChain::NAME, + P::TargetChain::NAME, + e, + ); + FailedClient::Target + })?; + match free_source_relay_headers_interval { + Some(free_source_relay_headers_interval) if free_source_relay_headers_interval != 0 => { + log::trace!( + target: "bridge", + "Free {} headers interval at {}: {:?}", + P::SourceRelayChain::NAME, + P::TargetChain::NAME, + free_source_relay_headers_interval, + ); + free_source_relay_headers_interval + }, + _ => { + log::warn!( + target: "bridge", + "Invalid free {} headers interval at {}: {:?}", + P::SourceRelayChain::NAME, + P::TargetChain::NAME, + free_source_relay_headers_interval, + ); + return Err(FailedClient::Target) + }, + } + } else { + // ignore - we don't need it + 0 + }; + let mut submitted_heads_tracker: Option> = None; futures::pin_mut!(exit_signal); @@ -211,7 +298,7 @@ where log::warn!(target: "bridge", "Failed to read best {} block: {:?}", P::SourceRelayChain::NAME, e); FailedClient::Target })?; - let head_at_target = + let (relay_of_head_at_target, head_at_target) = read_head_at_target(&target_client, metrics.as_ref(), &best_target_block).await?; // check if our transaction has been mined @@ -238,9 +325,9 @@ where } } - // we have no active transaction and may need to update heads, but do we have something for - // update? - let best_finalized_relay_block = target_client + // in all-headers strategy we'll be submitting para head, available at + // `best_finalized_relay_block_at_target` + let best_finalized_relay_block_at_target = target_client .best_finalized_source_relay_chain_block(&best_target_block) .await .map_err(|e| { @@ -253,65 +340,116 @@ where ); FailedClient::Target })?; + + // ..but if we only need to submit free headers, we need to submit para + // head, available at best free source relay chain header, known to the + // target chain + let prove_at_relay_block = if only_free_headers { + match relay_of_head_at_target { + Some(relay_of_head_at_target) => { + // find last free relay chain header in the range that we are interested in + let scan_range_begin = relay_of_head_at_target.number(); + let scan_range_end = best_finalized_relay_block_at_target.number(); + if scan_range_end.saturating_sub(scan_range_begin) < + free_source_relay_headers_interval + { + // there are no new **free** relay chain headers in the range + log::trace!( + target: "bridge", + "Waiting for new free {} headers at {}: scanned {:?}..={:?}", + P::SourceRelayChain::NAME, + P::TargetChain::NAME, + scan_range_begin, + scan_range_end, + ); + continue; + } + + // we may submit new parachain head for free + best_finalized_relay_block_at_target + }, + None => { + // no parachain head at target => let's submit first one + best_finalized_relay_block_at_target + }, + } + } else { + best_finalized_relay_block_at_target + }; + + // now let's check if we need to update parachain head at all let head_at_source = - read_head_at_source(&source_client, metrics.as_ref(), &best_finalized_relay_block) - .await?; + read_head_at_source(&source_client, metrics.as_ref(), &prove_at_relay_block).await?; let is_update_required = is_update_required::

( head_at_source, head_at_target, - best_finalized_relay_block, + prove_at_relay_block, best_target_block, ); if is_update_required { - let (head_proof, head_hash) = source_client - .prove_parachain_head(best_finalized_relay_block) - .await - .map_err(|e| { - log::warn!( - target: "bridge", - "Failed to prove {} parachain ParaId({}) heads: {:?}", - P::SourceRelayChain::NAME, - P::SourceParachain::PARACHAIN_ID, - e, - ); - FailedClient::Source - })?; - log::info!( + let transaction_tracker = submit_selected_head::( + &source_client, + &target_client, + prove_at_relay_block, + only_free_headers, + ) + .await?; + submitted_heads_tracker = + Some(SubmittedHeadsTracker::

::new(head_at_source, transaction_tracker)); + } + } +} + +/// Prove and submit parachain head at given relay chain block. +async fn submit_selected_head>( + source_client: &impl SourceClient

, + target_client: &TC, + prove_at_relay_block: HeaderIdOf, + only_free_headers: bool, +) -> Result { + let (head_proof, head_hash) = + source_client.prove_parachain_head(prove_at_relay_block).await.map_err(|e| { + log::warn!( target: "bridge", - "Submitting {} parachain ParaId({}) head update transaction to {}. Para hash at source relay {:?}: {:?}", + "Failed to prove {} parachain ParaId({}) heads: {:?}", P::SourceRelayChain::NAME, P::SourceParachain::PARACHAIN_ID, - P::TargetChain::NAME, - best_finalized_relay_block, - head_hash, + e, ); + FailedClient::Source + })?; + log::info!( + target: "bridge", + "Submitting {} parachain ParaId({}) head update transaction to {}. Para hash at source relay {:?}: {:?}", + P::SourceRelayChain::NAME, + P::SourceParachain::PARACHAIN_ID, + P::TargetChain::NAME, + prove_at_relay_block, + head_hash, + ); - let transaction_tracker = target_client - .submit_parachain_head_proof(best_finalized_relay_block, head_hash, head_proof) - .await - .map_err(|e| { - log::warn!( - target: "bridge", - "Failed to submit {} parachain ParaId({}) heads proof to {}: {:?}", - P::SourceRelayChain::NAME, - P::SourceParachain::PARACHAIN_ID, - P::TargetChain::NAME, - e, - ); - FailedClient::Target - })?; - submitted_heads_tracker = - Some(SubmittedHeadsTracker::

::new(head_at_source, transaction_tracker)); - } - } + target_client + .submit_parachain_head_proof(prove_at_relay_block, head_hash, head_proof, only_free_headers) + .await + .map_err(|e| { + log::warn!( + target: "bridge", + "Failed to submit {} parachain ParaId({}) heads proof to {}: {:?}", + P::SourceRelayChain::NAME, + P::SourceParachain::PARACHAIN_ID, + P::TargetChain::NAME, + e, + ); + FailedClient::Target + }) } /// Returns `true` if we need to submit parachain-head-update transaction. fn is_update_required( head_at_source: AvailableHeader>, head_at_target: Option>, - best_finalized_relay_block_at_source: HeaderIdOf, + prove_at_relay_block: HeaderIdOf, best_target_block: HeaderIdOf, ) -> bool where @@ -326,7 +464,7 @@ where P::SourceParachain::PARACHAIN_ID, P::TargetChain::NAME, P::SourceRelayChain::NAME, - best_finalized_relay_block_at_source, + prove_at_relay_block, head_at_source, P::TargetChain::NAME, best_target_block, @@ -413,24 +551,28 @@ async fn read_head_at_source( } } -/// Reads parachain head from the target client. +/// Reads parachain head from the target client. Also returns source relay chain header +/// that has been used to prove that head. async fn read_head_at_target( target_client: &impl TargetClient

, metrics: Option<&ParachainsLoopMetrics>, at_block: &HeaderIdOf, -) -> Result>, FailedClient> { +) -> Result< + (Option>, Option>), + FailedClient, +> { let para_head_id = target_client.parachain_head(*at_block).await; match para_head_id { - Ok(Some(para_head_id)) => { + Ok(Some((relay_header_id, para_head_id))) => { if let Some(metrics) = metrics { metrics.update_best_parachain_block_at_target( ParaId(P::SourceParachain::PARACHAIN_ID), para_head_id.number(), ); } - Ok(Some(para_head_id)) + Ok((Some(relay_header_id), Some(para_head_id))) }, - Ok(None) => Ok(None), + Ok(None) => Ok((None, None)), Err(e) => { log::warn!( target: "bridge", @@ -543,6 +685,7 @@ mod tests { use relay_substrate_client::test_chain::{TestChain, TestParachain}; use relay_utils::{HeaderId, MaybeConnectionError}; use sp_core::H256; + use std::collections::HashMap; const PARA_10_HASH: ParaHash = H256([10u8; 32]); const PARA_20_HASH: ParaHash = H256([20u8; 32]); @@ -590,14 +733,21 @@ mod tests { #[derive(Clone, Debug)] struct TestClientData { source_sync_status: Result, - source_head: Result>, TestError>, + source_head: HashMap< + BlockNumberOf, + Result>, TestError>, + >, source_proof: Result<(), TestError>, + target_free_source_relay_headers_interval: + Result>, TestError>, target_best_block: Result, TestError>, target_best_finalized_source_block: Result, TestError>, - target_head: Result>, TestError>, + #[allow(clippy::type_complexity)] + target_head: Result, HeaderIdOf)>, TestError>, target_submit_result: Result<(), TestError>, + submitted_proof_at_source_relay_block: Option>, exit_signal_sender: Option>>, } @@ -605,14 +755,18 @@ mod tests { pub fn minimal() -> Self { TestClientData { source_sync_status: Ok(true), - source_head: Ok(AvailableHeader::Available(HeaderId(0, PARA_20_HASH))), + source_head: vec![(0, Ok(AvailableHeader::Available(HeaderId(0, PARA_20_HASH))))] + .into_iter() + .collect(), source_proof: Ok(()), + target_free_source_relay_headers_interval: Ok(None), target_best_block: Ok(HeaderId(0, Default::default())), target_best_finalized_source_block: Ok(HeaderId(0, Default::default())), target_head: Ok(None), target_submit_result: Ok(()), + submitted_proof_at_source_relay_block: None, exit_signal_sender: None, } } @@ -649,16 +803,24 @@ mod tests { async fn parachain_head( &self, - _at_block: HeaderIdOf, + at_block: HeaderIdOf, ) -> Result>, TestError> { - self.data.lock().await.source_head.clone() + self.data + .lock() + .await + .source_head + .get(&at_block.0) + .expect(&format!("SourceClient::parachain_head({})", at_block.0)) + .clone() } async fn prove_parachain_head( &self, - _at_block: HeaderIdOf, + at_block: HeaderIdOf, ) -> Result<(ParaHeadsProof, ParaHash), TestError> { - let head = *self.data.lock().await.source_head.clone()?.as_available().unwrap(); + let head_result = + SourceClient::::parachain_head(self, at_block).await?; + let head = head_result.as_available().unwrap(); let storage_proof = vec![head.hash().encode()]; let proof = (ParaHeadsProof { storage_proof }, head.hash()); self.data.lock().await.source_proof.clone().map(|_| proof) @@ -680,21 +842,29 @@ mod tests { self.data.lock().await.target_best_finalized_source_block.clone() } + async fn free_source_relay_headers_interval( + &self, + ) -> Result>, TestError> { + self.data.lock().await.target_free_source_relay_headers_interval.clone() + } + async fn parachain_head( &self, _at_block: HeaderIdOf, - ) -> Result>, TestError> { + ) -> Result, HeaderIdOf)>, TestError> { self.data.lock().await.target_head.clone() } async fn submit_parachain_head_proof( &self, - _at_source_block: HeaderIdOf, + at_source_block: HeaderIdOf, _updated_parachain_head: ParaHash, _proof: ParaHeadsProof, + _is_free_execution_expected: bool, ) -> Result { let mut data = self.data.lock().await; data.target_submit_result.clone()?; + data.submitted_proof_at_source_relay_block = Some(at_source_block); if let Some(mut exit_signal_sender) = data.exit_signal_sender.take() { exit_signal_sender.send(()).await.unwrap(); @@ -715,6 +885,7 @@ mod tests { TestClient::from(test_source_client), TestClient::from(TestClientData::minimal()), None, + false, futures::future::pending(), )), Err(FailedClient::Source), @@ -731,6 +902,7 @@ mod tests { TestClient::from(TestClientData::minimal()), TestClient::from(test_target_client), None, + false, futures::future::pending(), )), Err(FailedClient::Target), @@ -747,6 +919,7 @@ mod tests { TestClient::from(TestClientData::minimal()), TestClient::from(test_target_client), None, + false, futures::future::pending(), )), Err(FailedClient::Target), @@ -763,6 +936,7 @@ mod tests { TestClient::from(TestClientData::minimal()), TestClient::from(test_target_client), None, + false, futures::future::pending(), )), Err(FailedClient::Target), @@ -772,13 +946,14 @@ mod tests { #[test] fn when_source_client_fails_to_read_heads() { let mut test_source_client = TestClientData::minimal(); - test_source_client.source_head = Err(TestError::Error); + test_source_client.source_head.insert(0, Err(TestError::Error)); assert_eq!( async_std::task::block_on(run_until_connection_lost( TestClient::from(test_source_client), TestClient::from(TestClientData::minimal()), None, + false, futures::future::pending(), )), Err(FailedClient::Source), @@ -795,6 +970,7 @@ mod tests { TestClient::from(test_source_client), TestClient::from(TestClientData::minimal()), None, + false, futures::future::pending(), )), Err(FailedClient::Source), @@ -811,6 +987,7 @@ mod tests { TestClient::from(TestClientData::minimal()), TestClient::from(test_target_client), None, + false, futures::future::pending(), )), Err(FailedClient::Target), @@ -825,12 +1002,108 @@ mod tests { TestClient::from(TestClientData::minimal()), TestClient::from(TestClientData::with_exit_signal_sender(exit_signal_sender)), None, + false, exit_signal.into_future().map(|(_, _)| ()), )), Ok(()), ); } + #[async_std::test] + async fn free_headers_are_relayed() { + // prepare following case: + // 1) best source relay at target: 95 + // 2) best source parachain at target: 5 at relay 50 + // 3) free headers interval: 10 + // 4) at source relay chain block 90 source parachain block is 9 + // + + // 5) best finalized source relay chain block is 95 + // 6) at source relay chain block 95 source parachain block is 42 + // => + // parachain block 42 would have been relayed, because 95 - 50 > 10 + let (exit_signal_sender, exit_signal) = futures::channel::mpsc::unbounded(); + let clients_data = TestClientData { + source_sync_status: Ok(true), + source_head: vec![ + (90, Ok(AvailableHeader::Available(HeaderId(9, [9u8; 32].into())))), + (95, Ok(AvailableHeader::Available(HeaderId(42, [42u8; 32].into())))), + ] + .into_iter() + .collect(), + source_proof: Ok(()), + + target_free_source_relay_headers_interval: Ok(Some(10)), + target_best_block: Ok(HeaderId(200, [200u8; 32].into())), + target_best_finalized_source_block: Ok(HeaderId(95, [95u8; 32].into())), + target_head: Ok(Some((HeaderId(50, [50u8; 32].into()), HeaderId(5, [5u8; 32].into())))), + target_submit_result: Ok(()), + + submitted_proof_at_source_relay_block: None, + exit_signal_sender: Some(Box::new(exit_signal_sender)), + }; + + let source_client = TestClient::from(clients_data.clone()); + let target_client = TestClient::from(clients_data); + assert_eq!( + run_until_connection_lost( + source_client, + target_client.clone(), + None, + true, + exit_signal.into_future().map(|(_, _)| ()), + ) + .await, + Ok(()), + ); + + assert_eq!( + target_client + .data + .lock() + .await + .submitted_proof_at_source_relay_block + .map(|id| id.0), + Some(95) + ); + + // now source relay block chain 104 is mined with parachain head #84 + // => since 104 - 95 < 10, there are no free headers + // => nothing is submitted + let mut clients_data: TestClientData = target_client.data.lock().await.clone(); + clients_data + .source_head + .insert(104, Ok(AvailableHeader::Available(HeaderId(84, [84u8; 32].into())))); + clients_data.target_best_finalized_source_block = Ok(HeaderId(104, [104u8; 32].into())); + clients_data.target_head = + Ok(Some((HeaderId(95, [95u8; 32].into()), HeaderId(42, [42u8; 32].into())))); + clients_data.target_best_block = Ok(HeaderId(255, [255u8; 32].into())); + clients_data.exit_signal_sender = None; + + let source_client = TestClient::from(clients_data.clone()); + let target_client = TestClient::from(clients_data); + assert_eq!( + run_until_connection_lost( + source_client, + target_client.clone(), + None, + true, + async_std::task::sleep(std::time::Duration::from_millis(100)), + ) + .await, + Ok(()), + ); + + assert_eq!( + target_client + .data + .lock() + .await + .submitted_proof_at_source_relay_block + .map(|id| id.0), + Some(95) + ); + } + fn test_tx_tracker() -> SubmittedHeadsTracker { SubmittedHeadsTracker::new( AvailableHeader::Available(HeaderId(20, PARA_20_HASH)), diff --git a/bridges/snowbridge/pallets/ethereum-client/Cargo.toml b/bridges/snowbridge/pallets/ethereum-client/Cargo.toml index 0e15304ff11234d6c1871511fc8c3237830fe9a4..e60934e34740600e78b9973d66ce648751a55138 100644 --- a/bridges/snowbridge/pallets/ethereum-client/Cargo.toml +++ b/bridges/snowbridge/pallets/ethereum-client/Cargo.toml @@ -17,7 +17,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] serde = { optional = true, workspace = true, default-features = true } serde_json = { optional = true, workspace = true, default-features = true } -codec = { version = "3.6.1", package = "parity-scale-codec", default-features = false, features = ["derive"] } +codec = { version = "3.6.12", 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 = { workspace = true } diff --git a/bridges/snowbridge/pallets/ethereum-client/src/lib.rs b/bridges/snowbridge/pallets/ethereum-client/src/lib.rs index c1b9e19729bc47588ad179db0c9c280a05834bc1..0ba1b8df4654972a09b5ac2c725b91bc0a84f9f6 100644 --- a/bridges/snowbridge/pallets/ethereum-client/src/lib.rs +++ b/bridges/snowbridge/pallets/ethereum-client/src/lib.rs @@ -104,6 +104,7 @@ pub mod pallet { #[pallet::error] pub enum Error { SkippedSyncCommitteePeriod, + SyncCommitteeUpdateRequired, /// Attested header is older than latest finalized header. IrrelevantUpdate, NotBootstrapped, @@ -320,6 +321,7 @@ pub mod pallet { // Verify update is relevant. let update_attested_period = compute_period(update.attested_header.slot); + let update_finalized_period = compute_period(update.finalized_header.slot); let update_has_next_sync_committee = !>::exists() && (update.next_sync_committee_update.is_some() && update_attested_period == store_period); @@ -395,6 +397,11 @@ pub mod pallet { ), Error::::InvalidSyncCommitteeMerkleProof ); + } else { + ensure!( + update_finalized_period == store_period, + Error::::SyncCommitteeUpdateRequired + ); } // Verify sync committee aggregate signature. diff --git a/bridges/snowbridge/pallets/ethereum-client/src/tests.rs b/bridges/snowbridge/pallets/ethereum-client/src/tests.rs index 765958c128212ee279bf547eb864335c7921e2eb..da762dc2fd8071969a1f68c707a0145aa0803852 100644 --- a/bridges/snowbridge/pallets/ethereum-client/src/tests.rs +++ b/bridges/snowbridge/pallets/ethereum-client/src/tests.rs @@ -362,13 +362,14 @@ fn submit_update_with_sync_committee_in_current_period() { } #[test] -fn submit_update_in_next_period() { +fn reject_submit_update_in_next_period() { let checkpoint = Box::new(load_checkpoint_update_fixture()); let sync_committee_update = Box::new(load_sync_committee_update_fixture()); let update = Box::new(load_next_finalized_header_update_fixture()); let sync_committee_period = compute_period(sync_committee_update.finalized_header.slot); let next_sync_committee_period = compute_period(update.finalized_header.slot); assert_eq!(sync_committee_period + 1, next_sync_committee_period); + let next_sync_committee_update = Box::new(load_next_sync_committee_update_fixture()); new_tester().execute_with(|| { assert_ok!(EthereumBeaconClient::process_checkpoint_update(&checkpoint)); @@ -376,6 +377,17 @@ fn submit_update_in_next_period() { RuntimeOrigin::signed(1), sync_committee_update.clone() )); + // check an update in the next period is rejected + assert_err!( + EthereumBeaconClient::submit(RuntimeOrigin::signed(1), update.clone()), + Error::::SyncCommitteeUpdateRequired + ); + // submit update with next sync committee + assert_ok!(EthereumBeaconClient::submit( + RuntimeOrigin::signed(1), + next_sync_committee_update + )); + // check same header in the next period can now be submitted successfully assert_ok!(EthereumBeaconClient::submit(RuntimeOrigin::signed(1), update.clone())); let block_root: H256 = update.finalized_header.clone().hash_tree_root().unwrap(); assert!(>::contains_key(block_root)); diff --git a/bridges/snowbridge/pallets/inbound-queue/Cargo.toml b/bridges/snowbridge/pallets/inbound-queue/Cargo.toml index 71d49e684e0b9379778f45743f6427a41796fd8a..d63398770f207051ebb5adb72f4f574c767e8770 100644 --- a/bridges/snowbridge/pallets/inbound-queue/Cargo.toml +++ b/bridges/snowbridge/pallets/inbound-queue/Cargo.toml @@ -16,7 +16,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] serde = { optional = true, workspace = true, default-features = true } -codec = { version = "3.6.1", package = "parity-scale-codec", default-features = false, features = ["derive"] } +codec = { version = "3.6.12", 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 = { workspace = true } diff --git a/bridges/snowbridge/pallets/inbound-queue/src/envelope.rs b/bridges/snowbridge/pallets/inbound-queue/src/envelope.rs index 826d535c2cb922610ba4811d607a9024de8d33ab..31a8992442d83b789849bdd99bedef31109ecc5a 100644 --- a/bridges/snowbridge/pallets/inbound-queue/src/envelope.rs +++ b/bridges/snowbridge/pallets/inbound-queue/src/envelope.rs @@ -3,7 +3,7 @@ use snowbridge_core::{inbound::Log, ChannelId}; use sp_core::{RuntimeDebug, H160, H256}; -use sp_std::{convert::TryFrom, prelude::*}; +use sp_std::prelude::*; use alloy_primitives::B256; use alloy_sol_types::{sol, SolEvent}; diff --git a/bridges/snowbridge/pallets/inbound-queue/src/lib.rs b/bridges/snowbridge/pallets/inbound-queue/src/lib.rs index 8acbb0c2916e704930268835e12bd14972737114..4a1486204eb08a43846bafaacfa05c465d8dc5fd 100644 --- a/bridges/snowbridge/pallets/inbound-queue/src/lib.rs +++ b/bridges/snowbridge/pallets/inbound-queue/src/lib.rs @@ -50,7 +50,7 @@ use frame_system::ensure_signed; use scale_info::TypeInfo; use sp_core::{H160, H256}; use sp_runtime::traits::Zero; -use sp_std::{convert::TryFrom, vec}; +use sp_std::vec; use xcm::prelude::{ send_xcm, Instruction::SetTopic, Junction::*, Location, SendError as XcmpSendError, SendXcm, Xcm, XcmContext, XcmHash, diff --git a/bridges/snowbridge/pallets/outbound-queue/Cargo.toml b/bridges/snowbridge/pallets/outbound-queue/Cargo.toml index 387491abae0f652d63c55d50279d4145dc03b18d..15c6c3a5b32b0fc2bd1a95fd842bab78f07a697a 100644 --- a/bridges/snowbridge/pallets/outbound-queue/Cargo.toml +++ b/bridges/snowbridge/pallets/outbound-queue/Cargo.toml @@ -16,7 +16,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] serde = { features = ["alloc", "derive"], workspace = true } -codec = { version = "3.6.1", package = "parity-scale-codec", default-features = false, features = ["derive"] } +codec = { version = "3.6.12", package = "parity-scale-codec", default-features = false, features = ["derive"] } scale-info = { version = "2.9.0", default-features = false, features = ["derive"] } frame-benchmarking = { path = "../../../../substrate/frame/benchmarking", default-features = false, 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 5315d6b4adbc1618720c7e0c781c65353c0ca4d6..1b1a9905928f8b5ea8eaccc15d18813f87406494 100644 --- a/bridges/snowbridge/pallets/outbound-queue/merkle-tree/Cargo.toml +++ b/bridges/snowbridge/pallets/outbound-queue/merkle-tree/Cargo.toml @@ -15,7 +15,7 @@ workspace = true targets = ["x86_64-unknown-linux-gnu"] [dependencies] -codec = { version = "3.1.5", package = "parity-scale-codec", default-features = false, features = ["derive"] } +codec = { version = "3.6.12", package = "parity-scale-codec", default-features = false, features = ["derive"] } scale-info = { version = "2.7.0", default-features = false, features = ["derive"] } sp-core = { path = "../../../../../substrate/primitives/core", default-features = false } @@ -25,7 +25,7 @@ sp-runtime = { path = "../../../../../substrate/primitives/runtime", default-fea hex-literal = { version = "0.4.1" } env_logger = "0.11" hex = "0.4" -array-bytes = "4.1" +array-bytes = "6.2.2" sp-crypto-hashing = { path = "../../../../../substrate/primitives/crypto/hashing" } [features] diff --git a/bridges/snowbridge/pallets/outbound-queue/runtime-api/Cargo.toml b/bridges/snowbridge/pallets/outbound-queue/runtime-api/Cargo.toml index fa49cc0f29a0a161838ab62a1210e33a79f32c59..b8d704f1cb92d570ea8e8b06cd00410bea7746bb 100644 --- a/bridges/snowbridge/pallets/outbound-queue/runtime-api/Cargo.toml +++ b/bridges/snowbridge/pallets/outbound-queue/runtime-api/Cargo.toml @@ -15,7 +15,7 @@ workspace = true targets = ["x86_64-unknown-linux-gnu"] [dependencies] -codec = { version = "3.1.5", package = "parity-scale-codec", features = ["derive"], default-features = false } +codec = { version = "3.6.12", package = "parity-scale-codec", features = ["derive"], default-features = false } sp-std = { path = "../../../../../substrate/primitives/std", default-features = false } sp-api = { path = "../../../../../substrate/primitives/api", default-features = false } frame-support = { path = "../../../../../substrate/frame/support", default-features = false } diff --git a/bridges/snowbridge/pallets/system/Cargo.toml b/bridges/snowbridge/pallets/system/Cargo.toml index c1ee44214c84a81dd9c4727bf81be93d5375c50c..5bbbb1d9310da4c3617ec4b03ea63620c30feb20 100644 --- a/bridges/snowbridge/pallets/system/Cargo.toml +++ b/bridges/snowbridge/pallets/system/Cargo.toml @@ -15,7 +15,7 @@ workspace = true targets = ["x86_64-unknown-linux-gnu"] [dependencies] -codec = { package = "parity-scale-codec", version = "3.6.1", default-features = false, features = [ +codec = { package = "parity-scale-codec", version = "3.6.12", default-features = false, features = [ "derive", ] } scale-info = { version = "2.9.0", default-features = false, features = ["derive"] } diff --git a/bridges/snowbridge/pallets/system/runtime-api/Cargo.toml b/bridges/snowbridge/pallets/system/runtime-api/Cargo.toml index 4073dc0f71c2096edce47a0857cd70cf969affed..42df5edfb7b2d4e5abaf0e30850ecbd3ebd04b98 100644 --- a/bridges/snowbridge/pallets/system/runtime-api/Cargo.toml +++ b/bridges/snowbridge/pallets/system/runtime-api/Cargo.toml @@ -15,7 +15,7 @@ workspace = true targets = ["x86_64-unknown-linux-gnu"] [dependencies] -codec = { package = "parity-scale-codec", version = "3.6.1", default-features = false, features = [ +codec = { package = "parity-scale-codec", version = "3.6.12", default-features = false, features = [ "derive", ] } sp-std = { path = "../../../../../substrate/primitives/std", default-features = false } diff --git a/bridges/snowbridge/primitives/beacon/Cargo.toml b/bridges/snowbridge/primitives/beacon/Cargo.toml index 7d901bcdb04493ea3103150c7dfeff0a32814269..18123910c35b2e198ec03ca1aa01aef1ea0d96ca 100644 --- a/bridges/snowbridge/primitives/beacon/Cargo.toml +++ b/bridges/snowbridge/primitives/beacon/Cargo.toml @@ -14,7 +14,7 @@ workspace = true [dependencies] 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 } +codec = { package = "parity-scale-codec", version = "3.6.12", default-features = false } scale-info = { version = "2.9.0", default-features = false, features = ["derive"] } rlp = { version = "0.5", default-features = false } diff --git a/bridges/snowbridge/primitives/beacon/src/bits.rs b/bridges/snowbridge/primitives/beacon/src/bits.rs index 72b7135ee2939bdabb98c9c06df801c43c3db230..fb03588cf8b71bfa12530d46ddac353dac3c7e28 100644 --- a/bridges/snowbridge/primitives/beacon/src/bits.rs +++ b/bridges/snowbridge/primitives/beacon/src/bits.rs @@ -1,6 +1,6 @@ // SPDX-License-Identifier: Apache-2.0 // SPDX-FileCopyrightText: 2023 Snowfork -use sp_std::{convert::TryInto, prelude::*}; +use sp_std::prelude::*; use ssz_rs::{Bitvector, Deserialize}; pub fn decompress_sync_committee_bits< diff --git a/bridges/snowbridge/primitives/beacon/src/serde_utils.rs b/bridges/snowbridge/primitives/beacon/src/serde_utils.rs index 07f5cbe724ed92bbda1d0cc7ded1a60c92a38cf0..5e39ff91225774a6b201b05a6c1325964eb256db 100644 --- a/bridges/snowbridge/primitives/beacon/src/serde_utils.rs +++ b/bridges/snowbridge/primitives/beacon/src/serde_utils.rs @@ -7,7 +7,7 @@ use serde::{Deserialize, Deserializer}; // helper to deserialize arbitrary arrays like [T; N] pub mod arrays { - use std::{convert::TryInto, marker::PhantomData}; + use std::marker::PhantomData; use serde::{ de::{SeqAccess, Visitor}, diff --git a/bridges/snowbridge/primitives/core/Cargo.toml b/bridges/snowbridge/primitives/core/Cargo.toml index 9a299ad0ae92326a6d0bb0391baf81e6e5bad663..573ab6608e5f91c0333f5ee7288cb679d6c38fb6 100644 --- a/bridges/snowbridge/primitives/core/Cargo.toml +++ b/bridges/snowbridge/primitives/core/Cargo.toml @@ -13,7 +13,7 @@ workspace = true [dependencies] serde = { optional = true, features = ["alloc", "derive"], workspace = true } -codec = { package = "parity-scale-codec", version = "3.6.1", default-features = false } +codec = { package = "parity-scale-codec", version = "3.6.12", 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 d72cd2661733b516a6a9b8102782b4d8d5c40e36..fb0b6cbaf3c2fba82c709fbc84ca565c53e7505e 100644 --- a/bridges/snowbridge/primitives/ethereum/Cargo.toml +++ b/bridges/snowbridge/primitives/ethereum/Cargo.toml @@ -14,7 +14,7 @@ workspace = true [dependencies] 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"] } +codec = { package = "parity-scale-codec", version = "3.6.12", default-features = false, features = ["derive"] } scale-info = { version = "2.9.0", default-features = false, features = ["derive"] } ethbloom = { version = "0.13.0", default-features = false } ethereum-types = { version = "0.14.1", default-features = false, features = ["codec", "rlp", "serialize"] } diff --git a/bridges/snowbridge/primitives/ethereum/src/header.rs b/bridges/snowbridge/primitives/ethereum/src/header.rs index f0b51f8c79de8fa3f1b37205c38d8a8640771f0c..48fa179fe4fa8dee5db7ffc4d4b0704f8f8a5584 100644 --- a/bridges/snowbridge/primitives/ethereum/src/header.rs +++ b/bridges/snowbridge/primitives/ethereum/src/header.rs @@ -8,7 +8,7 @@ use rlp::RlpStream; use scale_info::TypeInfo; use sp_io::hashing::keccak_256; use sp_runtime::RuntimeDebug; -use sp_std::{convert::TryInto, prelude::*}; +use sp_std::prelude::*; #[cfg(feature = "std")] use serde::{Deserialize, Serialize}; diff --git a/bridges/snowbridge/primitives/ethereum/src/mpt.rs b/bridges/snowbridge/primitives/ethereum/src/mpt.rs index 9a2dae486dcc05ee5c078e0794ee2d27193eb207..0365f5e994feada7eadde9c908f962e47854c8dc 100644 --- a/bridges/snowbridge/primitives/ethereum/src/mpt.rs +++ b/bridges/snowbridge/primitives/ethereum/src/mpt.rs @@ -3,7 +3,7 @@ //! Helper types to work with Ethereum's Merkle Patricia Trie nodes use ethereum_types::H256; -use sp_std::{convert::TryFrom, prelude::*}; +use sp_std::prelude::*; pub trait Node { fn contains_hash(&self, hash: H256) -> bool; diff --git a/bridges/snowbridge/primitives/router/Cargo.toml b/bridges/snowbridge/primitives/router/Cargo.toml index 361b539af3e350a29871e82a76265de072bbf779..1d3fc43909df46a20f6e030985c2a7eea189fdc4 100644 --- a/bridges/snowbridge/primitives/router/Cargo.toml +++ b/bridges/snowbridge/primitives/router/Cargo.toml @@ -12,7 +12,7 @@ categories = ["cryptography::cryptocurrencies"] workspace = true [dependencies] -codec = { package = "parity-scale-codec", version = "3.6.1", default-features = false } +codec = { package = "parity-scale-codec", version = "3.6.12", default-features = false } scale-info = { version = "2.9.0", default-features = false, features = ["derive"] } log = { workspace = true } diff --git a/bridges/snowbridge/primitives/router/src/inbound/mod.rs b/bridges/snowbridge/primitives/router/src/inbound/mod.rs index c20554c6d184412f6bff0ec332a775ca37c16a6a..54e47a7a8b6af0a0dce1d54d52e3e0799e6f6e84 100644 --- a/bridges/snowbridge/primitives/router/src/inbound/mod.rs +++ b/bridges/snowbridge/primitives/router/src/inbound/mod.rs @@ -273,8 +273,10 @@ where }, None => { instructions.extend(vec![ - // Deposit asset to beneficiary. - DepositAsset { assets: Definite(asset.into()), beneficiary }, + // Deposit both asset and fees to beneficiary so the fees will not get + // trapped. Another benefit is when fees left more than ED on AssetHub could be + // used to create the beneficiary account in case it does not exist. + DepositAsset { assets: Wild(AllCounted(2)), beneficiary }, ]); }, } diff --git a/bridges/snowbridge/runtime/runtime-common/Cargo.toml b/bridges/snowbridge/runtime/runtime-common/Cargo.toml index 995475349e4cb62045c613596acaf659eabd7076..2372908b86ab5134f4ea0f8373ffe00cbcc2bd32 100644 --- a/bridges/snowbridge/runtime/runtime-common/Cargo.toml +++ b/bridges/snowbridge/runtime/runtime-common/Cargo.toml @@ -13,7 +13,7 @@ workspace = true [dependencies] log = { workspace = true } -codec = { package = "parity-scale-codec", version = "3.6.1", default-features = false } +codec = { package = "parity-scale-codec", version = "3.6.12", default-features = false } frame-support = { path = "../../../../substrate/frame/support", default-features = false } sp-std = { path = "../../../../substrate/primitives/std", default-features = false } sp-arithmetic = { path = "../../../../substrate/primitives/arithmetic", default-features = false } diff --git a/bridges/snowbridge/runtime/test-common/Cargo.toml b/bridges/snowbridge/runtime/test-common/Cargo.toml index 92970339fac03dd9209546c9319b899509faca2c..20c3fc012d01183c09ca2ad206d38b1d382255cc 100644 --- a/bridges/snowbridge/runtime/test-common/Cargo.toml +++ b/bridges/snowbridge/runtime/test-common/Cargo.toml @@ -3,7 +3,7 @@ name = "snowbridge-runtime-test-common" description = "Snowbridge Runtime Tests" version = "0.2.0" authors = ["Snowfork "] -edition = "2021" +edition.workspace = true license = "Apache-2.0" categories = ["cryptography::cryptocurrencies"] @@ -11,7 +11,7 @@ categories = ["cryptography::cryptocurrencies"] workspace = true [dependencies] -codec = { package = "parity-scale-codec", version = "3.6.1", default-features = false, features = ["derive"] } +codec = { package = "parity-scale-codec", version = "3.6.12", default-features = false, features = ["derive"] } # Substrate frame-support = { path = "../../../../substrate/frame/support", default-features = false } diff --git a/bridges/testing/environments/rococo-westend/bridge_hub_rococo_local_network.toml b/bridges/testing/environments/rococo-westend/bridge_hub_rococo_local_network.toml index 52271f9442131923f8a758b16df7610e73813d15..f59f689bf6b5c40a09854b93eb7927fc4b5929c9 100644 --- a/bridges/testing/environments/rococo-westend/bridge_hub_rococo_local_network.toml +++ b/bridges/testing/environments/rococo-westend/bridge_hub_rococo_local_network.toml @@ -40,7 +40,7 @@ cumulus_based = true 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" + "-lparachain=debug,runtime::bridge=trace,xcm=trace,txpool=trace" ] # run bob as parachain collator @@ -51,7 +51,7 @@ cumulus_based = true 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" + "-lparachain=debug,runtime::bridge=trace,xcm=trace,txpool=trace" ] [[parachains]] @@ -65,14 +65,14 @@ cumulus_based = true ws_port = 9910 command = "{{POLKADOT_PARACHAIN_BINARY}}" args = [ - "-lparachain=debug,xcm=trace,runtime::bridge-transfer=trace" + "-lparachain=debug,xcm=trace,runtime::bridge=trace,txpool=trace" ] [[parachains.collators]] name = "asset-hub-rococo-collator2" command = "{{POLKADOT_PARACHAIN_BINARY}}" args = [ - "-lparachain=debug,xcm=trace,runtime::bridge-transfer=trace" + "-lparachain=debug,xcm=trace,runtime::bridge=trace,txpool=trace" ] #[[hrmp_channels]] diff --git a/bridges/testing/environments/rococo-westend/bridge_hub_westend_local_network.toml b/bridges/testing/environments/rococo-westend/bridge_hub_westend_local_network.toml index f2550bcc9959638b21ea78043cca3bc12d3d23ea..6ab03ad5fe2c380ea4201bf8ef2a2cf405fe314b 100644 --- a/bridges/testing/environments/rococo-westend/bridge_hub_westend_local_network.toml +++ b/bridges/testing/environments/rococo-westend/bridge_hub_westend_local_network.toml @@ -40,7 +40,7 @@ cumulus_based = true 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" + "-lparachain=debug,runtime::bridge=trace,xcm=trace,txpool=trace" ] # run bob as parachain collator @@ -51,7 +51,7 @@ cumulus_based = true 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" + "-lparachain=debug,runtime::bridge=trace,xcm=trace,txpool=trace" ] [[parachains]] @@ -65,14 +65,14 @@ cumulus_based = true ws_port = 9010 command = "{{POLKADOT_PARACHAIN_BINARY}}" args = [ - "-lparachain=debug,xcm=trace,runtime::bridge-transfer=trace" + "-lparachain=debug,xcm=trace,runtime::bridge=trace,txpool=trace" ] [[parachains.collators]] name = "asset-hub-westend-collator2" command = "{{POLKADOT_PARACHAIN_BINARY}}" args = [ - "-lparachain=debug,xcm=trace,runtime::bridge-transfer=trace" + "-lparachain=debug,xcm=trace,runtime::bridge=trace,txpool=trace" ] #[[hrmp_channels]] diff --git a/bridges/testing/environments/rococo-westend/bridges_rococo_westend.sh b/bridges/testing/environments/rococo-westend/bridges_rococo_westend.sh index 41aa862be5764ea93fbe09fa706621486131d4c6..ef4a5597902fdc61caedd071f408f03a87a19ea0 100755 --- a/bridges/testing/environments/rococo-westend/bridges_rococo_westend.sh +++ b/bridges/testing/environments/rococo-westend/bridges_rococo_westend.sh @@ -169,12 +169,99 @@ function run_relay() { --lane "${LANE_ID}" } +function run_finality_relay() { + local relayer_path=$(ensure_relayer) + + RUST_LOG=runtime=trace,rpc=trace,bridge=trace \ + $relayer_path relay-headers rococo-to-bridge-hub-westend \ + --only-free-headers \ + --source-uri ws://localhost:9942 \ + --source-version-mode Auto \ + --target-uri ws://localhost:8945 \ + --target-version-mode Auto \ + --target-signer //Charlie \ + --target-transactions-mortality 4& + + RUST_LOG=runtime=trace,rpc=trace,bridge=trace \ + $relayer_path relay-headers westend-to-bridge-hub-rococo \ + --only-free-headers \ + --source-uri ws://localhost:9945 \ + --source-version-mode Auto \ + --target-uri ws://localhost:8943 \ + --target-version-mode Auto \ + --target-signer //Charlie \ + --target-transactions-mortality 4 +} + +function run_parachains_relay() { + local relayer_path=$(ensure_relayer) + + RUST_LOG=runtime=trace,rpc=trace,bridge=trace \ + $relayer_path relay-parachains rococo-to-bridge-hub-westend \ + --only-free-headers \ + --source-uri ws://localhost:9942 \ + --source-version-mode Auto \ + --target-uri ws://localhost:8945 \ + --target-version-mode Auto \ + --target-signer //Dave \ + --target-transactions-mortality 4& + + RUST_LOG=runtime=trace,rpc=trace,bridge=trace \ + $relayer_path relay-parachains westend-to-bridge-hub-rococo \ + --only-free-headers \ + --source-uri ws://localhost:9945 \ + --source-version-mode Auto \ + --target-uri ws://localhost:8943 \ + --target-version-mode Auto \ + --target-signer //Dave \ + --target-transactions-mortality 4 +} + +function run_messages_relay() { + local relayer_path=$(ensure_relayer) + + RUST_LOG=runtime=trace,rpc=trace,bridge=trace \ + $relayer_path relay-messages bridge-hub-rococo-to-bridge-hub-westend \ + --source-uri ws://localhost:8943 \ + --source-version-mode Auto \ + --source-signer //Eve \ + --source-transactions-mortality 4 \ + --target-uri ws://localhost:8945 \ + --target-version-mode Auto \ + --target-signer //Eve \ + --target-transactions-mortality 4 \ + --lane $LANE_ID& + + RUST_LOG=runtime=trace,rpc=trace,bridge=trace \ + $relayer_path relay-messages bridge-hub-westend-to-bridge-hub-rococo \ + --source-uri ws://localhost:8945 \ + --source-version-mode Auto \ + --source-signer //Ferdie \ + --source-transactions-mortality 4 \ + --target-uri ws://localhost:8943 \ + --target-version-mode Auto \ + --target-signer //Ferdie \ + --target-transactions-mortality 4 \ + --lane $LANE_ID +} + case "$1" in run-relay) init_wnd_ro init_ro_wnd run_relay ;; + run-finality-relay) + init_wnd_ro + init_ro_wnd + run_finality_relay + ;; + run-parachains-relay) + run_parachains_relay + ;; + run-messages-relay) + run_messages_relay + ;; init-asset-hub-rococo-local) ensure_polkadot_js_api # create foreign assets for native Westend token (governance call on Rococo) @@ -386,6 +473,9 @@ case "$1" in echo "A command is require. Supported commands for: Local (zombienet) run: - run-relay + - run-finality-relay + - run-parachains-relay + - run-messages-relay - init-asset-hub-rococo-local - init-bridge-hub-rococo-local - init-asset-hub-westend-local diff --git a/bridges/testing/environments/rococo-westend/explorers.sh b/bridges/testing/environments/rococo-westend/explorers.sh new file mode 100755 index 0000000000000000000000000000000000000000..fb137726c93cb789c6a03fb22d913b4ee5a822bd --- /dev/null +++ b/bridges/testing/environments/rococo-westend/explorers.sh @@ -0,0 +1,11 @@ +#!/bin/bash + +# Rococo AH +xdg-open https://polkadot.js.org/apps/?rpc=ws://127.0.0.1:9910#/explorer& +# Rococo BH +xdg-open https://polkadot.js.org/apps/?rpc=ws://127.0.0.1:8943#/explorer& + +# Westend BH +xdg-open https://polkadot.js.org/apps/?rpc=ws://127.0.0.1:8945#/explorer& +# Westend AH +xdg-open https://polkadot.js.org/apps/?rpc=ws://127.0.0.1:9010#/explorer& diff --git a/bridges/testing/environments/rococo-westend/helper.sh b/bridges/testing/environments/rococo-westend/helper.sh index 0a13ded213f5d3a0920cb466fc974c129e9ad79a..571c78fea584893b5c24c7f1b2b68335559bf26f 100755 --- a/bridges/testing/environments/rococo-westend/helper.sh +++ b/bridges/testing/environments/rococo-westend/helper.sh @@ -1,3 +1,9 @@ #!/bin/bash -$ENV_PATH/bridges_rococo_westend.sh "$@" +if [ $1 == "auto-log" ]; then + shift # ignore "auto-log" + log_name=$1 + $ENV_PATH/bridges_rococo_westend.sh "$@" >$TEST_DIR/logs/$log_name.log +else + $ENV_PATH/bridges_rococo_westend.sh "$@" +fi diff --git a/bridges/testing/environments/rococo-westend/spawn.sh b/bridges/testing/environments/rococo-westend/spawn.sh index cbd0b1bc623ab77876ed5ce3beefd7ab72db2d37..a0ab00be14448f92bf31f2eea2eba91c2ac5240e 100755 --- a/bridges/testing/environments/rococo-westend/spawn.sh +++ b/bridges/testing/environments/rococo-westend/spawn.sh @@ -59,12 +59,12 @@ if [[ $init -eq 1 ]]; then fi if [[ $start_relayer -eq 1 ]]; then - ${BASH_SOURCE%/*}/start_relayer.sh $rococo_dir $westend_dir relayer_pid + ${BASH_SOURCE%/*}/start_relayer.sh $rococo_dir $westend_dir finality_relayer_pid parachains_relayer_pid messages_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 +wait -n $rococo_pid $westend_pid $finality_relayer_pid $parachains_relayer_pid $messages_relayer_pid kill -9 -$$ diff --git a/bridges/testing/environments/rococo-westend/start_relayer.sh b/bridges/testing/environments/rococo-westend/start_relayer.sh index 7ddd312d395aa8733d2afea59277b48721c8a36b..9c57e4a6ab6e198e10e8c233c9c9e64a3499a0f4 100755 --- a/bridges/testing/environments/rococo-westend/start_relayer.sh +++ b/bridges/testing/environments/rococo-westend/start_relayer.sh @@ -7,17 +7,31 @@ source "$FRAMEWORK_PATH/utils/zombienet.sh" rococo_dir=$1 westend_dir=$2 -__relayer_pid=$3 +__finality_relayer_pid=$3 +__parachains_relayer_pid=$4 +__messages_relayer_pid=$5 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 +# start finality relayer +finality_relayer_log=$logs_dir/relayer_finality.log +echo -e "Starting rococo-westend finality relayer. Logs available at: $finality_relayer_log\n" +start_background_process "$helper_script run-finality-relay" $finality_relayer_log finality_relayer_pid + +# start parachains relayer +parachains_relayer_log=$logs_dir/relayer_parachains.log +echo -e "Starting rococo-westend parachains relayer. Logs available at: $parachains_relayer_log\n" +start_background_process "$helper_script run-parachains-relay" $parachains_relayer_log parachains_relayer_pid + +# start messages relayer +messages_relayer_log=$logs_dir/relayer_messages.log +echo -e "Starting rococo-westend messages relayer. Logs available at: $messages_relayer_log\n" +start_background_process "$helper_script run-messages-relay" $messages_relayer_log messages_relayer_pid run_zndsl ${BASH_SOURCE%/*}/rococo.zndsl $rococo_dir run_zndsl ${BASH_SOURCE%/*}/westend.zndsl $westend_dir -eval $__relayer_pid="'$relayer_pid'" - +eval $__finality_relayer_pid="'$finality_relayer_pid'" +eval $__parachains_relayer_pid="'$parachains_relayer_pid'" +eval $__messages_relayer_pid="'$messages_relayer_pid'" diff --git a/bridges/testing/framework/js-helpers/only-mandatory-headers-synced-when-idle.js b/bridges/testing/framework/js-helpers/multiple-headers-synced.js similarity index 61% rename from bridges/testing/framework/js-helpers/only-mandatory-headers-synced-when-idle.js rename to bridges/testing/framework/js-helpers/multiple-headers-synced.js index 979179245ebe9f5b250efca6f2e6199ef0ac86d7..a30efc821657c3b70b072ad2399db8a5cf3d6d76 100644 --- a/bridges/testing/framework/js-helpers/only-mandatory-headers-synced-when-idle.js +++ b/bridges/testing/framework/js-helpers/multiple-headers-synced.js @@ -10,33 +10,23 @@ async function run(nodeName, networkInfo, args) { // start listening to new blocks let totalGrandpaHeaders = 0; - let initialParachainHeaderImported = false; + let totalParachainHeaders = 0; api.rpc.chain.subscribeNewHeads(async function (header) { const apiAtParent = await api.at(header.parentHash); const apiAtCurrent = await api.at(header.hash); const currentEvents = await apiAtCurrent.query.system.events(); - totalGrandpaHeaders += await utils.ensureOnlyMandatoryGrandpaHeadersImported( - bridgedChain, - apiAtParent, - apiAtCurrent, - currentEvents, - ); - initialParachainHeaderImported = await utils.ensureOnlyInitialParachainHeaderImported( - bridgedChain, - apiAtParent, - apiAtCurrent, - currentEvents, - ); + totalGrandpaHeaders += await utils.countGrandpaHeaderImports(bridgedChain, currentEvents); + totalParachainHeaders += await utils.countParachainHeaderImports(bridgedChain, currentEvents); }); // wait given time await new Promise(resolve => setTimeout(resolve, exitAfterSeconds * 1000)); - // if we haven't seen any new GRANDPA or parachain headers => fail - if (totalGrandpaHeaders == 0) { + // if we haven't seen many (>1) new GRANDPA or parachain headers => fail + if (totalGrandpaHeaders <= 1) { throw new Error("No bridged relay chain headers imported"); } - if (!initialParachainHeaderImported) { + if (totalParachainHeaders <= 1) { throw new Error("No bridged parachain headers imported"); } } diff --git a/bridges/testing/framework/js-helpers/native-asset-balance.js b/bridges/testing/framework/js-helpers/native-asset-balance.js new file mode 100644 index 0000000000000000000000000000000000000000..4869eba35d8dd53278793f89b1fd38d2d703aa3b --- /dev/null +++ b/bridges/testing/framework/js-helpers/native-asset-balance.js @@ -0,0 +1,12 @@ +async function run(nodeName, networkInfo, args) { + const {wsUri, userDefinedTypes} = networkInfo.nodesByName[nodeName]; + const api = await zombie.connect(wsUri, userDefinedTypes); + + const accountAddress = args[0]; + const accountData = await api.query.system.account(accountAddress); + const accountBalance = accountData.data['free']; + console.log("Balance of " + accountAddress + ": " + accountBalance); + return accountBalance; +} + +module.exports = {run} diff --git a/bridges/testing/tests/0001-asset-transfer/roc-reaches-westend.zndsl b/bridges/testing/tests/0001-asset-transfer/roc-reaches-westend.zndsl index cdb7d28e940cf1ac90562e761cdbad00e95e1748..6e26632fd9f9cc30b108476ea414ef432254e32e 100644 --- a/bridges/testing/tests/0001-asset-transfer/roc-reaches-westend.zndsl +++ b/bridges/testing/tests/0001-asset-transfer/roc-reaches-westend.zndsl @@ -3,10 +3,10 @@ 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 +asset-hub-westend-collator1: run {{ENV_PATH}}/helper.sh with "auto-log reserve-transfer-assets-from-asset-hub-rococo-local 5000000000000" within 120 seconds # check that //Alice received at least 4.8 ROC on Westend AH asset-hub-westend-collator1: js-script {{FRAMEWORK_PATH}}/js-helpers/wrapped-assets-balance.js with "5GrwvaEF5zXb26Fz9rcQpDWS57CtERHpNehXCPcNoHGKutQY,4800000000000,Rococo" within 600 seconds -# 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 +# relayer //Ferdie is rewarded for delivering messages from Rococo BH +bridge-hub-westend-collator1: js-script {{FRAMEWORK_PATH}}/js-helpers/relayer-rewards.js with "5HGjWAeFDfFCWPsjFQdVV2Msvz2XtMktvgocEZcCj68kUMaw,0x00000002,0x6268726F,ThisChain,0" within 300 seconds diff --git a/bridges/testing/tests/0001-asset-transfer/roc-relayer-balance-does-not-change.zndsl b/bridges/testing/tests/0001-asset-transfer/roc-relayer-balance-does-not-change.zndsl new file mode 100644 index 0000000000000000000000000000000000000000..4839c19c0ff2b6343718711d117c86834f6fa6b8 --- /dev/null +++ b/bridges/testing/tests/0001-asset-transfer/roc-relayer-balance-does-not-change.zndsl @@ -0,0 +1,11 @@ +Description: Finality and parachain relays should have the constant balance, because their transactions are free +Network: {{ENV_PATH}}/bridge_hub_rococo_local_network.toml +Creds: config + +# local chain spec gives `1u64 << 60` tokens to every endowed account: if it'll ever +# change, it'd need to be fixed here as well + +# //Charlie only submits free and mandatory relay chain headers, so the balance should stay the same +bridge-hub-rococo-collator1: js-script {{FRAMEWORK_PATH}}/js-helpers/native-asset-balance.js with "5FLSigC9HGRKVhB9FiEo4Y3koPsNmBmLJbpXg2mp1hXcS59Y" return is 1152921504606846976 within 30 seconds +# //Dave only submits free parachain headers, so the balance should stay the same +bridge-hub-rococo-collator1: js-script {{FRAMEWORK_PATH}}/js-helpers/native-asset-balance.js with "5DAAnrj7VHTznn2AWBemMuyBwZWs6FNFjdyVXUeYum3PTXFy" return is 1152921504606846976 within 30 seconds diff --git a/bridges/testing/tests/0001-asset-transfer/run.sh b/bridges/testing/tests/0001-asset-transfer/run.sh index a7bb122919b40187c49e89c489d2271d646bff40..227069932f2d985da05c82b88247da0542e46c58 100755 --- a/bridges/testing/tests/0001-asset-transfer/run.sh +++ b/bridges/testing/tests/0001-asset-transfer/run.sh @@ -18,8 +18,14 @@ ensure_process_file $env_pid $TEST_DIR/westend.env 300 westend_dir=`cat $TEST_DIR/westend.env` echo +run_zndsl ${BASH_SOURCE%/*}/roc-relayer-balance-does-not-change.zndsl $rococo_dir +run_zndsl ${BASH_SOURCE%/*}/wnd-relayer-balance-does-not-change.zndsl $westend_dir + 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 + +run_zndsl ${BASH_SOURCE%/*}/roc-relayer-balance-does-not-change.zndsl $rococo_dir +run_zndsl ${BASH_SOURCE%/*}/wnd-relayer-balance-does-not-change.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 index dbc03864e2b6e5e10636532ad965860b381fa8f2..5a8d6dabc20e3060e92ef6feef8211b7353d23d1 100644 --- a/bridges/testing/tests/0001-asset-transfer/wnd-reaches-rococo.zndsl +++ b/bridges/testing/tests/0001-asset-transfer/wnd-reaches-rococo.zndsl @@ -3,10 +3,10 @@ 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 +asset-hub-rococo-collator1: run {{ENV_PATH}}/helper.sh with "auto-log reserve-transfer-assets-from-asset-hub-westend-local 5000000000000" within 120 seconds # check that //Alice received at least 4.8 WND on Rococo AH asset-hub-rococo-collator1: js-script {{FRAMEWORK_PATH}}/js-helpers/wrapped-assets-balance.js with "5GrwvaEF5zXb26Fz9rcQpDWS57CtERHpNehXCPcNoHGKutQY,4800000000000,Westend" within 600 seconds -# 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 +# relayer //Eve is rewarded for delivering messages from Westend BH +bridge-hub-rococo-collator1: js-script {{FRAMEWORK_PATH}}/js-helpers/relayer-rewards.js with "5CiPPseXPECbkjWCa6MnjNokrgYjMqmKndv2rSnekmSK2DjL,0x00000002,0x62687764,ThisChain,0" within 300 seconds diff --git a/bridges/testing/tests/0001-asset-transfer/wnd-relayer-balance-does-not-change.zndsl b/bridges/testing/tests/0001-asset-transfer/wnd-relayer-balance-does-not-change.zndsl new file mode 100644 index 0000000000000000000000000000000000000000..d2563e1807869754cbe3153d973467826b1c71fd --- /dev/null +++ b/bridges/testing/tests/0001-asset-transfer/wnd-relayer-balance-does-not-change.zndsl @@ -0,0 +1,11 @@ +Description: Finality and parachain relays should have the constant balance, because their transactions are free +Network: {{ENV_PATH}}/bridge_hub_westend_local_network.toml +Creds: config + +# local chain spec gives `1u64 << 60` tokens to every endowed account: if it'll ever +# change, it'd need to be fixed here as well + +# //Charlie only submits free and mandatory relay chain headers, so the balance should stay the same +bridge-hub-westend-collator1: js-script {{FRAMEWORK_PATH}}/js-helpers/native-asset-balance.js with "5FLSigC9HGRKVhB9FiEo4Y3koPsNmBmLJbpXg2mp1hXcS59Y" return is 1152921504606846976 within 30 seconds +# //Dave only submits free parachain headers, so the balance should stay the same +bridge-hub-westend-collator1: js-script {{FRAMEWORK_PATH}}/js-helpers/native-asset-balance.js with "5DAAnrj7VHTznn2AWBemMuyBwZWs6FNFjdyVXUeYum3PTXFy" return is 1152921504606846976 within 30 seconds diff --git a/bridges/testing/tests/0002-free-headers-synced-while-idle/rococo-to-westend.zndsl b/bridges/testing/tests/0002-free-headers-synced-while-idle/rococo-to-westend.zndsl new file mode 100644 index 0000000000000000000000000000000000000000..0f779caa87cd183901fe434f693950c0b3b48338 --- /dev/null +++ b/bridges/testing/tests/0002-free-headers-synced-while-idle/rococo-to-westend.zndsl @@ -0,0 +1,20 @@ +Description: While relayer is idle, we only sync free Rococo (and a single Rococo BH) headers to Westend BH. +Network: {{ENV_PATH}}/bridge_hub_westend_local_network.toml +Creds: config + +# local chain spec gives `1u64 << 60` tokens to every endowed account: if it'll ever +# change, it'd need to be fixed here as well + +# //Charlie only submits free and mandatory relay chain headers, so the balance should stay the same +bridge-hub-westend-collator1: js-script {{FRAMEWORK_PATH}}/js-helpers/native-asset-balance.js with "5FLSigC9HGRKVhB9FiEo4Y3koPsNmBmLJbpXg2mp1hXcS59Y" return is 1152921504606846976 within 30 seconds +# //Dave only submits free parachain headers, so the balance should stay the same +bridge-hub-westend-collator1: js-script {{FRAMEWORK_PATH}}/js-helpers/native-asset-balance.js with "5DAAnrj7VHTznn2AWBemMuyBwZWs6FNFjdyVXUeYum3PTXFy" return is 1152921504606846976 within 30 seconds + +# ensure that we have synced multiple relay and parachain 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/multiple-headers-synced.js with "300,rococo-at-westend" within 600 seconds + +# //Charlie only submits free and mandatory relay chain headers, so the balance should stay the same +bridge-hub-westend-collator1: js-script {{FRAMEWORK_PATH}}/js-helpers/native-asset-balance.js with "5FLSigC9HGRKVhB9FiEo4Y3koPsNmBmLJbpXg2mp1hXcS59Y" return is 1152921504606846976 within 30 seconds +# //Dave only submits free parachain headers, so the balance should stay the same +bridge-hub-westend-collator1: js-script {{FRAMEWORK_PATH}}/js-helpers/native-asset-balance.js with "5DAAnrj7VHTznn2AWBemMuyBwZWs6FNFjdyVXUeYum3PTXFy" return is 1152921504606846976 within 30 seconds diff --git a/bridges/testing/tests/0002-mandatory-headers-synced-while-idle/run.sh b/bridges/testing/tests/0002-free-headers-synced-while-idle/run.sh similarity index 90% rename from bridges/testing/tests/0002-mandatory-headers-synced-while-idle/run.sh rename to bridges/testing/tests/0002-free-headers-synced-while-idle/run.sh index 32419dc84f59e14d779eef30b26939b297240e55..9d19a9688f948e84004054400397566b7c8b8d94 100755 --- a/bridges/testing/tests/0002-mandatory-headers-synced-while-idle/run.sh +++ b/bridges/testing/tests/0002-free-headers-synced-while-idle/run.sh @@ -22,7 +22,7 @@ echo # 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 +${BASH_SOURCE%/*}/../../environments/rococo-westend/start_relayer.sh $rococo_dir $westend_dir finality_relayer_pid parachains_relayer_pid messages_relayer_pid 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-free-headers-synced-while-idle/westend-to-rococo.zndsl b/bridges/testing/tests/0002-free-headers-synced-while-idle/westend-to-rococo.zndsl new file mode 100644 index 0000000000000000000000000000000000000000..7a6f1ec379d2fc3f105725d0c4b2da69586a37ac --- /dev/null +++ b/bridges/testing/tests/0002-free-headers-synced-while-idle/westend-to-rococo.zndsl @@ -0,0 +1,20 @@ +Description: While relayer is idle, we only sync free Westend (and a single Westend BH) headers to Rococo BH. +Network: {{ENV_PATH}}/bridge_hub_rococo_local_network.toml +Creds: config + +# local chain spec gives `1u64 << 60` tokens to every endowed account: if it'll ever +# change, it'd need to be fixed here as well + +# //Charlie has inital balance +bridge-hub-rococo-collator1: js-script {{FRAMEWORK_PATH}}/js-helpers/native-asset-balance.js with "5FLSigC9HGRKVhB9FiEo4Y3koPsNmBmLJbpXg2mp1hXcS59Y" return is 1152921504606846976 within 30 seconds +# //Dave has inital balance +bridge-hub-rococo-collator1: js-script {{FRAMEWORK_PATH}}/js-helpers/native-asset-balance.js with "5DAAnrj7VHTznn2AWBemMuyBwZWs6FNFjdyVXUeYum3PTXFy" return is 1152921504606846976 within 30 seconds + +# ensure that we have synced multiple relay and parachain 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/multiple-headers-synced.js with "300,westend-at-rococo" within 600 seconds + +# //Charlie only submits free and mandatory relay chain headers, so the balance should stay the same +bridge-hub-rococo-collator1: js-script {{FRAMEWORK_PATH}}/js-helpers/native-asset-balance.js with "5FLSigC9HGRKVhB9FiEo4Y3koPsNmBmLJbpXg2mp1hXcS59Y" return is 1152921504606846976 within 30 seconds +# //Dave only submits free parachain headers, so the balance should stay the same +bridge-hub-rococo-collator1: js-script {{FRAMEWORK_PATH}}/js-helpers/native-asset-balance.js with "5DAAnrj7VHTznn2AWBemMuyBwZWs6FNFjdyVXUeYum3PTXFy" return is 1152921504606846976 within 30 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 deleted file mode 100644 index 6e381f5377329430c0d7a8723f9ea9081556bfeb..0000000000000000000000000000000000000000 --- a/bridges/testing/tests/0002-mandatory-headers-synced-while-idle/rococo-to-westend.zndsl +++ /dev/null @@ -1,8 +0,0 @@ -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/westend-to-rococo.zndsl b/bridges/testing/tests/0002-mandatory-headers-synced-while-idle/westend-to-rococo.zndsl deleted file mode 100644 index b4b3e43679162feb8c3c5253f3f963d950f31d55..0000000000000000000000000000000000000000 --- a/bridges/testing/tests/0002-mandatory-headers-synced-while-idle/westend-to-rococo.zndsl +++ /dev/null @@ -1,7 +0,0 @@ -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/cumulus/client/cli/Cargo.toml b/cumulus/client/cli/Cargo.toml index 0b2edb593c405bef266fa7e389a996fe3a2fcec1..410ac8b983d96f0a38633ac0199208a4e249e49b 100644 --- a/cumulus/client/cli/Cargo.toml +++ b/cumulus/client/cli/Cargo.toml @@ -11,7 +11,7 @@ workspace = true [dependencies] clap = { version = "4.5.3", features = ["derive"] } -codec = { package = "parity-scale-codec", version = "3.0.0" } +codec = { package = "parity-scale-codec", version = "3.6.12" } url = "2.4.0" # Substrate diff --git a/cumulus/client/collator/Cargo.toml b/cumulus/client/collator/Cargo.toml index 42f7342d1a5381a6174c15909b815485eb7c8a7e..39cedf87a0cb1b6fb8296c1a3bdec1483170af38 100644 --- a/cumulus/client/collator/Cargo.toml +++ b/cumulus/client/collator/Cargo.toml @@ -11,7 +11,7 @@ workspace = true [dependencies] parking_lot = "0.12.1" -codec = { package = "parity-scale-codec", version = "3.0.0", features = ["derive"] } +codec = { package = "parity-scale-codec", version = "3.6.12", features = ["derive"] } futures = "0.3.30" tracing = "0.1.25" diff --git a/cumulus/client/consensus/aura/Cargo.toml b/cumulus/client/consensus/aura/Cargo.toml index 70dd67cb9a00b2e7b0baf04dbfdaaff0386104e5..547137b7306460d91c10c3222c27d70f68d6e15d 100644 --- a/cumulus/client/consensus/aura/Cargo.toml +++ b/cumulus/client/consensus/aura/Cargo.toml @@ -11,7 +11,7 @@ workspace = true [dependencies] async-trait = "0.1.79" -codec = { package = "parity-scale-codec", version = "3.0.0", features = ["derive"] } +codec = { package = "parity-scale-codec", version = "3.6.12", features = ["derive"] } futures = "0.3.28" tracing = "0.1.37" schnellru = "0.2.1" diff --git a/cumulus/client/consensus/aura/src/collator.rs b/cumulus/client/consensus/aura/src/collator.rs index 5b7669c88f473b8765b6b343d1797aa707ed5916..776052215d9397c529699ed07040819f666e16b5 100644 --- a/cumulus/client/consensus/aura/src/collator.rs +++ b/cumulus/client/consensus/aura/src/collator.rs @@ -55,7 +55,7 @@ use sp_runtime::{ }; use sp_state_machine::StorageChanges; use sp_timestamp::Timestamp; -use std::{convert::TryFrom, error::Error, time::Duration}; +use std::{error::Error, time::Duration}; /// Parameters for instantiating a [`Collator`]. pub struct Params { diff --git a/cumulus/client/consensus/aura/src/collators/basic.rs b/cumulus/client/consensus/aura/src/collators/basic.rs index a4c22a45266cf53d2015b840a54a159492e87ba4..1047c6219ad132403014cacaf3d071d8009b9dbc 100644 --- a/cumulus/client/consensus/aura/src/collators/basic.rs +++ b/cumulus/client/consensus/aura/src/collators/basic.rs @@ -48,7 +48,7 @@ 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 std::{sync::Arc, time::Duration}; use crate::collator as collator_util; diff --git a/cumulus/client/consensus/aura/src/collators/lookahead.rs b/cumulus/client/consensus/aura/src/collators/lookahead.rs index 3fe87e94b7b97b6d839f3f723ebe22fb26e8760d..09416233ea9b39dfd4bd4126149d51f922d7b6e4 100644 --- a/cumulus/client/consensus/aura/src/collators/lookahead.rs +++ b/cumulus/client/consensus/aura/src/collators/lookahead.rs @@ -67,7 +67,7 @@ use sp_inherents::CreateInherentDataProviders; use sp_keystore::KeystorePtr; use sp_runtime::traits::{Block as BlockT, Header as HeaderT, Member}; use sp_timestamp::Timestamp; -use std::{convert::TryFrom, sync::Arc, time::Duration}; +use std::{sync::Arc, time::Duration}; use crate::collator::{self as collator_util, SlotClaim}; diff --git a/cumulus/client/consensus/common/Cargo.toml b/cumulus/client/consensus/common/Cargo.toml index fb4a85ad122637470a81371eb12352a14ac7c61e..3a7c6b57d6d931b8809e9be9fda4cf4e07e50b8c 100644 --- a/cumulus/client/consensus/common/Cargo.toml +++ b/cumulus/client/consensus/common/Cargo.toml @@ -11,7 +11,7 @@ workspace = true [dependencies] async-trait = "0.1.79" -codec = { package = "parity-scale-codec", version = "3.0.0", features = ["derive"] } +codec = { package = "parity-scale-codec", version = "3.6.12", features = ["derive"] } dyn-clone = "1.0.16" futures = "0.3.28" log = { workspace = true, default-features = true } diff --git a/cumulus/client/network/Cargo.toml b/cumulus/client/network/Cargo.toml index 1210975ef690c4d110a7f96b2e88e4d151edfa87..d4fc752872589fbfd361f5df49939874d208ab3d 100644 --- a/cumulus/client/network/Cargo.toml +++ b/cumulus/client/network/Cargo.toml @@ -11,7 +11,7 @@ workspace = true [dependencies] async-trait = "0.1.79" -codec = { package = "parity-scale-codec", version = "3.0.0", features = ["derive"] } +codec = { package = "parity-scale-codec", version = "3.6.12", features = ["derive"] } futures = "0.3.28" futures-timer = "3.0.2" parking_lot = "0.12.1" diff --git a/cumulus/client/network/src/lib.rs b/cumulus/client/network/src/lib.rs index ebd557b805c5d7ea4362632dac8bf0a59ddc6469..f442ed5840bddcd4a859d149635ff740e4d232f4 100644 --- a/cumulus/client/network/src/lib.rs +++ b/cumulus/client/network/src/lib.rs @@ -36,7 +36,7 @@ use polkadot_primitives::{ use codec::{Decode, DecodeAll, Encode}; use futures::{channel::oneshot, future::FutureExt, Future}; -use std::{convert::TryFrom, fmt, marker::PhantomData, pin::Pin, sync::Arc}; +use std::{fmt, marker::PhantomData, pin::Pin, sync::Arc}; #[cfg(test)] mod tests; diff --git a/cumulus/client/parachain-inherent/Cargo.toml b/cumulus/client/parachain-inherent/Cargo.toml index 6e9adab1ffc9e2bf9de9d8101eb38e4da8212b27..85619e8403458c0bfa3dae6dadc688f2cb895731 100644 --- a/cumulus/client/parachain-inherent/Cargo.toml +++ b/cumulus/client/parachain-inherent/Cargo.toml @@ -8,7 +8,7 @@ license = "Apache-2.0" [dependencies] async-trait = "0.1.79" -codec = { package = "parity-scale-codec", version = "3.0.0", features = ["derive"] } +codec = { package = "parity-scale-codec", version = "3.6.12", features = ["derive"] } scale-info = { version = "2.11.1", features = ["derive"] } tracing = { version = "0.1.37" } diff --git a/cumulus/client/parachain-inherent/src/mock.rs b/cumulus/client/parachain-inherent/src/mock.rs index 22691006f93ed264e3e7d37b7b2120ea576e9da3..896df7a724253993867fb30f3f225220b9b26137 100644 --- a/cumulus/client/parachain-inherent/src/mock.rs +++ b/cumulus/client/parachain-inherent/src/mock.rs @@ -28,6 +28,9 @@ use std::collections::BTreeMap; use cumulus_test_relay_sproof_builder::RelayStateSproofBuilder; +/// Relay chain slot duration, in milliseconds. +pub const RELAY_CHAIN_SLOT_DURATION_MILLIS: u32 = 6000; + /// Inherent data provider that supplies mocked validation data. /// /// This is useful when running a node that is not actually backed by any relay chain. @@ -45,6 +48,8 @@ use cumulus_test_relay_sproof_builder::RelayStateSproofBuilder; pub struct MockValidationDataInherentDataProvider { /// The current block number of the local block chain (the parachain) pub current_para_block: u32, + /// The current block head data of the local block chain (the parachain) + pub current_para_block_head: Option, /// The relay block in which this parachain appeared to start. This will be the relay block /// number in para block #P1 pub relay_offset: u32, @@ -159,14 +164,16 @@ impl> InherentDataProvider &self, inherent_data: &mut InherentData, ) -> Result<(), sp_inherents::Error> { - // Calculate the mocked relay block based on the current para block - let relay_parent_number = - self.relay_offset + self.relay_blocks_per_para_block * self.current_para_block; - // Use the "sproof" (spoof proof) builder to build valid mock state root and proof. let mut sproof_builder = RelayStateSproofBuilder { para_id: self.xcm_config.para_id, ..Default::default() }; + // Calculate the mocked relay block based on the current para block + let relay_parent_number = + self.relay_offset + self.relay_blocks_per_para_block * self.current_para_block; + sproof_builder.current_slot = + ((relay_parent_number / RELAY_CHAIN_SLOT_DURATION_MILLIS) as u64).into(); + // Process the downward messages and set up the correct head let mut downward_messages = Vec::new(); let mut dmq_mqc = MessageQueueChain::new(self.xcm_config.starting_dmq_mqc_head); @@ -217,6 +224,9 @@ impl> InherentDataProvider sproof_builder.additional_key_values = key_values.clone() } + // Inject current para block head, if any + sproof_builder.included_para_head = self.current_para_block_head.clone(); + let (relay_parent_storage_root, proof) = sproof_builder.into_state_root_and_proof(); inherent_data.put_data( diff --git a/cumulus/client/pov-recovery/Cargo.toml b/cumulus/client/pov-recovery/Cargo.toml index 571935620d6d90b3aa1157124a2bae6fd73a19c2..7afe7fae34bd799ed75d557ad5f0ca5067743f7f 100644 --- a/cumulus/client/pov-recovery/Cargo.toml +++ b/cumulus/client/pov-recovery/Cargo.toml @@ -10,7 +10,7 @@ license = "GPL-3.0-or-later WITH Classpath-exception-2.0" workspace = true [dependencies] -codec = { package = "parity-scale-codec", version = "3.0.0", features = ["derive"] } +codec = { package = "parity-scale-codec", version = "3.6.12", features = ["derive"] } futures = "0.3.28" futures-timer = "3.0.2" rand = "0.8.5" diff --git a/cumulus/client/relay-chain-inprocess-interface/src/lib.rs b/cumulus/client/relay-chain-inprocess-interface/src/lib.rs index 6ea02b2e7c1f6d9b5313459890dd2147015359e5..578b942776dcde99553e0a5af513b03acb3a80a1 100644 --- a/cumulus/client/relay-chain-inprocess-interface/src/lib.rs +++ b/cumulus/client/relay-chain-inprocess-interface/src/lib.rs @@ -312,6 +312,9 @@ fn build_polkadot_full_node( overseer_message_channel_capacity_override: None, malus_finality_delay: None, hwbench, + execute_workers_max_num: None, + prepare_workers_hard_max_num: None, + prepare_workers_soft_max_num: None, }, )?; diff --git a/cumulus/client/relay-chain-interface/Cargo.toml b/cumulus/client/relay-chain-interface/Cargo.toml index 6df9847252fecf8e4bdcdec0ff9f830d6530668b..5962c68bba7a561b05a1710c2477b31964bbfe07 100644 --- a/cumulus/client/relay-chain-interface/Cargo.toml +++ b/cumulus/client/relay-chain-interface/Cargo.toml @@ -23,4 +23,4 @@ futures = "0.3.28" async-trait = "0.1.79" thiserror = { workspace = true } jsonrpsee-core = "0.22" -parity-scale-codec = "3.6.4" +parity-scale-codec = "3.6.12" diff --git a/cumulus/client/relay-chain-minimal-node/Cargo.toml b/cumulus/client/relay-chain-minimal-node/Cargo.toml index 6860b42a5078d48e74bbbd7ee64fbab43e5d5e13..88673a8f08fe37e4c5688b6bbec40fb36903c6dd 100644 --- a/cumulus/client/relay-chain-minimal-node/Cargo.toml +++ b/cumulus/client/relay-chain-minimal-node/Cargo.toml @@ -47,7 +47,7 @@ cumulus-relay-chain-interface = { path = "../relay-chain-interface" } cumulus-relay-chain-rpc-interface = { path = "../relay-chain-rpc-interface" } cumulus-primitives-core = { path = "../../primitives/core" } -array-bytes = "6.1" +array-bytes = "6.2.2" tracing = "0.1.37" async-trait = "0.1.79" futures = "0.3.28" diff --git a/cumulus/client/relay-chain-rpc-interface/Cargo.toml b/cumulus/client/relay-chain-rpc-interface/Cargo.toml index 14981677289561040875b0951dbdbffb5854a439..2ec42ebca851e4d30a9ac17acd923f005956c287 100644 --- a/cumulus/client/relay-chain-rpc-interface/Cargo.toml +++ b/cumulus/client/relay-chain-rpc-interface/Cargo.toml @@ -32,7 +32,7 @@ tokio-util = { version = "0.7.8", features = ["compat"] } futures = "0.3.28" futures-timer = "3.0.2" -parity-scale-codec = "3.6.4" +parity-scale-codec = "3.6.12" jsonrpsee = { version = "0.22", features = ["ws-client"] } tracing = "0.1.37" async-trait = "0.1.79" diff --git a/cumulus/pallets/aura-ext/Cargo.toml b/cumulus/pallets/aura-ext/Cargo.toml index fe717596f9b307993f968ea0e7b58faef591dcf7..daff5ef8f482e82b80f341d5208cad51b23b7b1a 100644 --- a/cumulus/pallets/aura-ext/Cargo.toml +++ b/cumulus/pallets/aura-ext/Cargo.toml @@ -10,7 +10,7 @@ license = "Apache-2.0" workspace = true [dependencies] -codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = ["derive"] } +codec = { package = "parity-scale-codec", version = "3.6.12", default-features = false, features = ["derive"] } scale-info = { version = "2.11.1", default-features = false, features = ["derive"] } # Substrate diff --git a/cumulus/pallets/collator-selection/Cargo.toml b/cumulus/pallets/collator-selection/Cargo.toml index c04d9e1403ec0e3d527e06c7b0c7c5e6f64150ad..f30802fa5d82ecb93e8610e7c7bb17a2a83cacb4 100644 --- a/cumulus/pallets/collator-selection/Cargo.toml +++ b/cumulus/pallets/collator-selection/Cargo.toml @@ -17,7 +17,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] log = { workspace = true } -codec = { default-features = false, features = ["derive"], package = "parity-scale-codec", version = "3.0.0" } +codec = { default-features = false, features = ["derive"], package = "parity-scale-codec", version = "3.6.12" } rand = { version = "0.8.5", features = ["std_rng"], default-features = false } scale-info = { version = "2.11.1", default-features = false, features = ["derive"] } @@ -27,6 +27,7 @@ sp-staking = { path = "../../../substrate/primitives/staking", default-features frame-support = { path = "../../../substrate/frame/support", default-features = false } frame-system = { path = "../../../substrate/frame/system", default-features = false } pallet-authorship = { path = "../../../substrate/frame/authorship", default-features = false } +pallet-balances = { path = "../../../substrate/frame/balances", default-features = false } pallet-session = { path = "../../../substrate/frame/session", default-features = false } frame-benchmarking = { path = "../../../substrate/frame/benchmarking", default-features = false, optional = true } @@ -38,7 +39,6 @@ sp-tracing = { path = "../../../substrate/primitives/tracing" } sp-runtime = { path = "../../../substrate/primitives/runtime" } pallet-timestamp = { path = "../../../substrate/frame/timestamp" } sp-consensus-aura = { path = "../../../substrate/primitives/consensus/aura" } -pallet-balances = { path = "../../../substrate/frame/balances" } pallet-aura = { path = "../../../substrate/frame/aura" } [features] @@ -59,6 +59,7 @@ std = [ "frame-system/std", "log/std", "pallet-authorship/std", + "pallet-balances/std", "pallet-session/std", "rand/std", "scale-info/std", diff --git a/cumulus/pallets/collator-selection/src/lib.rs b/cumulus/pallets/collator-selection/src/lib.rs index 17bbe2591d48f767305adfe4c87237c926b83187..2fa384367528a1f1306a6c34c0c45d3ef94843a2 100644 --- a/cumulus/pallets/collator-selection/src/lib.rs +++ b/cumulus/pallets/collator-selection/src/lib.rs @@ -121,7 +121,7 @@ pub mod pallet { use sp_std::vec::Vec; /// The in-code storage version. - const STORAGE_VERSION: StorageVersion = StorageVersion::new(1); + const STORAGE_VERSION: StorageVersion = StorageVersion::new(2); type BalanceOf = <::Currency as Currency<::AccountId>>::Balance; diff --git a/cumulus/pallets/collator-selection/src/migration.rs b/cumulus/pallets/collator-selection/src/migration.rs index 5dc2fba4279a9b04dc9f1866fb2c36ea1abde80c..425acdd8bfb59768241399e3be5efb44a13c8a74 100644 --- a/cumulus/pallets/collator-selection/src/migration.rs +++ b/cumulus/pallets/collator-selection/src/migration.rs @@ -17,9 +17,107 @@ //! A module that is responsible for migration of storage for Collator Selection. use super::*; -use frame_support::traits::OnRuntimeUpgrade; +use frame_support::traits::{OnRuntimeUpgrade, UncheckedOnRuntimeUpgrade}; use log; +/// Migrate to v2. Should have been part of . +pub mod v2 { + use super::*; + use frame_support::{ + pallet_prelude::*, + storage_alias, + traits::{Currency, ReservableCurrency}, + }; + use sp_runtime::traits::{Saturating, Zero}; + #[cfg(feature = "try-runtime")] + use sp_std::vec::Vec; + + /// [`UncheckedMigrationToV2`] wrapped in a + /// [`VersionedMigration`](frame_support::migrations::VersionedMigration), ensuring the + /// migration is only performed when on-chain version is 1. + pub type MigrationToV2 = frame_support::migrations::VersionedMigration< + 1, + 2, + UncheckedMigrationToV2, + Pallet, + ::DbWeight, + >; + + #[storage_alias] + pub type Candidates = StorageValue< + Pallet, + BoundedVec::AccountId, <::Currency as Currency<::AccountId>>::Balance>, ::MaxCandidates>, + ValueQuery, + >; + + /// Migrate to V2. + pub struct UncheckedMigrationToV2(sp_std::marker::PhantomData); + impl UncheckedOnRuntimeUpgrade for UncheckedMigrationToV2 { + fn on_runtime_upgrade() -> Weight { + let mut weight = Weight::zero(); + let mut count: u64 = 0; + // candidates who exist under the old `Candidates` key + let candidates = Candidates::::take(); + + // New candidates who have registered since the upgrade. Under normal circumstances, + // this should not exist because the migration should be applied when the upgrade + // happens. But in Polkadot/Kusama we messed this up, and people registered under + // `CandidateList` while their funds were locked in `Candidates`. + let new_candidate_list = CandidateList::::get(); + if new_candidate_list.len().is_zero() { + // The new list is empty, so this is essentially being applied correctly. We just + // put the candidates into the new storage item. + CandidateList::::put(&candidates); + // 1 write for the new list + weight.saturating_accrue(T::DbWeight::get().reads_writes(0, 1)); + } else { + // Oops, the runtime upgraded without the migration. There are new candidates in + // `CandidateList`. So, let's just refund the old ones and assume they have already + // started participating in the new system. + for candidate in candidates { + let err = T::Currency::unreserve(&candidate.who, candidate.deposit); + if err > Zero::zero() { + log::error!( + target: LOG_TARGET, + "{:?} balance was unable to be unreserved from {:?}", + err, &candidate.who, + ); + } + count.saturating_inc(); + } + weight.saturating_accrue( + <::WeightInfo as pallet_balances::WeightInfo>::force_unreserve().saturating_mul(count.into()), + ); + } + + log::info!( + target: LOG_TARGET, + "Unreserved locked bond of {} candidates, upgraded storage to version 2", + count, + ); + + weight.saturating_accrue(T::DbWeight::get().reads_writes(3, 2)); + weight + } + + #[cfg(feature = "try-runtime")] + fn pre_upgrade() -> Result, sp_runtime::DispatchError> { + let number_of_candidates = Candidates::::get().to_vec().len(); + Ok((number_of_candidates as u32).encode()) + } + + #[cfg(feature = "try-runtime")] + fn post_upgrade(_number_of_candidates: Vec) -> Result<(), sp_runtime::DispatchError> { + let new_number_of_candidates = Candidates::::get().to_vec().len(); + assert_eq!( + new_number_of_candidates, 0 as usize, + "after migration, the candidates map should be empty" + ); + Ok(()) + } + } +} + /// Version 1 Migration /// This migration ensures that any existing `Invulnerables` storage lists are sorted. pub mod v1 { @@ -90,3 +188,136 @@ pub mod v1 { } } } + +#[cfg(all(feature = "try-runtime", test))] +mod tests { + use super::*; + use crate::{ + migration::v2::Candidates, + mock::{new_test_ext, Balances, Test}, + }; + use frame_support::{ + traits::{Currency, ReservableCurrency, StorageVersion}, + BoundedVec, + }; + use sp_runtime::traits::ConstU32; + + #[test] + fn migrate_to_v2_with_new_candidates() { + new_test_ext().execute_with(|| { + let storage_version = StorageVersion::new(1); + storage_version.put::>(); + + let one = 1u64; + let two = 2u64; + let three = 3u64; + let deposit = 10u64; + + // Set balance to 100 + Balances::make_free_balance_be(&one, 100u64); + Balances::make_free_balance_be(&two, 100u64); + Balances::make_free_balance_be(&three, 100u64); + + // Reservations: 10 for the "old" candidacy and 10 for the "new" + Balances::reserve(&one, 10u64).unwrap(); // old + Balances::reserve(&two, 20u64).unwrap(); // old + new + Balances::reserve(&three, 10u64).unwrap(); // new + + // Candidate info + let candidate_one = CandidateInfo { who: one, deposit }; + let candidate_two = CandidateInfo { who: two, deposit }; + let candidate_three = CandidateInfo { who: three, deposit }; + + // Storage lists + let bounded_candidates = + BoundedVec::, ConstU32<20>>::try_from(vec![ + candidate_one.clone(), + candidate_two.clone(), + ]) + .expect("it works"); + let bounded_candidate_list = + BoundedVec::, ConstU32<20>>::try_from(vec![ + candidate_two.clone(), + candidate_three.clone(), + ]) + .expect("it works"); + + // Set storage + Candidates::::put(bounded_candidates); + CandidateList::::put(bounded_candidate_list.clone()); + + // Sanity check + assert_eq!(Balances::free_balance(one), 90); + assert_eq!(Balances::free_balance(two), 80); + assert_eq!(Balances::free_balance(three), 90); + + // Run migration + v2::MigrationToV2::::on_runtime_upgrade(); + + let new_storage_version = StorageVersion::get::>(); + assert_eq!(new_storage_version, 2); + + // 10 should have been unreserved from the old candidacy + assert_eq!(Balances::free_balance(one), 100); + assert_eq!(Balances::free_balance(two), 90); + assert_eq!(Balances::free_balance(three), 90); + // The storage item should be gone + assert!(Candidates::::get().is_empty()); + // The new storage item should be preserved + assert_eq!(CandidateList::::get(), bounded_candidate_list); + }); + } + + #[test] + fn migrate_to_v2_without_new_candidates() { + new_test_ext().execute_with(|| { + let storage_version = StorageVersion::new(1); + storage_version.put::>(); + + let one = 1u64; + let two = 2u64; + let deposit = 10u64; + + // Set balance to 100 + Balances::make_free_balance_be(&one, 100u64); + Balances::make_free_balance_be(&two, 100u64); + + // Reservations + Balances::reserve(&one, 10u64).unwrap(); // old + Balances::reserve(&two, 10u64).unwrap(); // old + + // Candidate info + let candidate_one = CandidateInfo { who: one, deposit }; + let candidate_two = CandidateInfo { who: two, deposit }; + + // Storage lists + let bounded_candidates = + BoundedVec::, ConstU32<20>>::try_from(vec![ + candidate_one.clone(), + candidate_two.clone(), + ]) + .expect("it works"); + + // Set storage + Candidates::::put(bounded_candidates.clone()); + + // Sanity check + assert_eq!(Balances::free_balance(one), 90); + assert_eq!(Balances::free_balance(two), 90); + + // Run migration + v2::MigrationToV2::::on_runtime_upgrade(); + + let new_storage_version = StorageVersion::get::>(); + assert_eq!(new_storage_version, 2); + + // Nothing changes deposit-wise + assert_eq!(Balances::free_balance(one), 90); + assert_eq!(Balances::free_balance(two), 90); + // The storage item should be gone + assert!(Candidates::::get().is_empty()); + // The new storage item should have the info now + assert_eq!(CandidateList::::get(), bounded_candidates); + }); + } +} diff --git a/cumulus/pallets/dmp-queue/Cargo.toml b/cumulus/pallets/dmp-queue/Cargo.toml index b2b24aeed72ba28ea320a90b8e725ce983fa1a07..687cda164fb0bd3d4aefb9d6b51f6735ef3a43c3 100644 --- a/cumulus/pallets/dmp-queue/Cargo.toml +++ b/cumulus/pallets/dmp-queue/Cargo.toml @@ -14,7 +14,7 @@ workspace = true targets = ["x86_64-unknown-linux-gnu"] [dependencies] -codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = ["derive"] } +codec = { package = "parity-scale-codec", version = "3.6.12", default-features = false, features = ["derive"] } log = { workspace = true } scale-info = { version = "2.11.1", default-features = false, features = ["derive"] } diff --git a/cumulus/pallets/dmp-queue/src/lib.rs b/cumulus/pallets/dmp-queue/src/lib.rs index 79cc4bc895ec29b87eb95e629e0a9624fd7f62a5..9b3ec684febab81fb535c52118cbadb64b61e984 100644 --- a/cumulus/pallets/dmp-queue/src/lib.rs +++ b/cumulus/pallets/dmp-queue/src/lib.rs @@ -21,6 +21,7 @@ //! from the runtime once `Completed` was emitted. #![cfg_attr(not(feature = "std"), no_std)] +#![allow(deprecated)] // The pallet itself is deprecated. use migration::*; pub use pallet::*; @@ -38,6 +39,9 @@ pub type MaxDmpMessageLenOf = <::DmpSink as frame_support::traits::HandleMessage>::MaxMessageLen; #[frame_support::pallet] +#[deprecated( + note = "`cumulus-pallet-dmp-queue` will be removed after November 2024. It can be removed once its lazy migration completed. See ." +)] pub mod pallet { use super::*; use frame_support::{pallet_prelude::*, traits::HandleMessage, weights::WeightMeter}; diff --git a/cumulus/pallets/parachain-system/Cargo.toml b/cumulus/pallets/parachain-system/Cargo.toml index cc2e8943caad529ec05d6daa82598dc4c210aeee..0c94d0d05a64f488cb9e0e145fccea9ba8052f50 100644 --- a/cumulus/pallets/parachain-system/Cargo.toml +++ b/cumulus/pallets/parachain-system/Cargo.toml @@ -11,7 +11,7 @@ workspace = true [dependencies] bytes = { version = "1.4.0", default-features = false } -codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = ["derive"] } +codec = { package = "parity-scale-codec", version = "3.6.12", default-features = false, features = ["derive"] } environmental = { version = "1.1.4", default-features = false } impl-trait-for-tuples = "0.2.1" log = { workspace = true } @@ -38,6 +38,7 @@ polkadot-parachain-primitives = { path = "../../../polkadot/parachain", default- 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 } +xcm-builder = { package = "staging-xcm-builder", path = "../../../polkadot/xcm/xcm-builder", default-features = false } # Cumulus cumulus-pallet-parachain-system-proc-macro = { path = "proc-macro", default-features = false } @@ -95,6 +96,7 @@ std = [ "sp-tracing/std", "sp-trie/std", "trie-db/std", + "xcm-builder/std", "xcm/std", ] @@ -109,6 +111,7 @@ runtime-benchmarks = [ "polkadot-runtime-common/runtime-benchmarks", "polkadot-runtime-parachains/runtime-benchmarks", "sp-runtime/runtime-benchmarks", + "xcm-builder/runtime-benchmarks", ] try-runtime = [ diff --git a/cumulus/pallets/parachain-system/src/lib.rs b/cumulus/pallets/parachain-system/src/lib.rs index 54a1def59600dff5dd8b1484691dcb18fff5ce63..7657dc4555eee822dd612935eb3c5ac735759be1 100644 --- a/cumulus/pallets/parachain-system/src/lib.rs +++ b/cumulus/pallets/parachain-system/src/lib.rs @@ -30,7 +30,7 @@ use codec::{Decode, Encode}; use cumulus_primitives_core::{ relay_chain, AbridgedHostConfiguration, ChannelInfo, ChannelStatus, CollationInfo, - GetChannelInfo, InboundDownwardMessage, InboundHrmpMessage, MessageSendError, + GetChannelInfo, InboundDownwardMessage, InboundHrmpMessage, ListChannelInfos, MessageSendError, OutboundHrmpMessage, ParaId, PersistedValidationData, UpwardMessage, UpwardMessageSender, XcmpMessageHandler, XcmpMessageSource, }; @@ -55,7 +55,8 @@ use sp_runtime::{ BoundedSlice, FixedU128, RuntimeDebug, Saturating, }; use sp_std::{cmp, collections::btree_map::BTreeMap, prelude::*}; -use xcm::latest::XcmHash; +use xcm::{latest::XcmHash, VersionedLocation, VersionedXcm}; +use xcm_builder::InspectMessageQueues; mod benchmarking; pub mod migration; @@ -1021,6 +1022,13 @@ impl FeeTracker for Pallet { } } +impl ListChannelInfos for Pallet { + fn outgoing_channels() -> Vec { + let Some(state) = RelevantMessagingState::::get() else { return Vec::new() }; + state.egress_channels.into_iter().map(|(id, _)| id).collect() + } +} + impl GetChannelInfo for Pallet { fn get_channel_status(id: ParaId) -> ChannelStatus { // Note, that we are using `relevant_messaging_state` which may be from the previous @@ -1608,6 +1616,19 @@ impl UpwardMessageSender for Pallet { } } +impl InspectMessageQueues for Pallet { + fn get_messages() -> Vec<(VersionedLocation, Vec>)> { + use xcm::prelude::*; + + let messages: Vec> = PendingUpwardMessages::::get() + .iter() + .map(|encoded_message| VersionedXcm::<()>::decode(&mut &encoded_message[..]).unwrap()) + .collect(); + + vec![(VersionedLocation::V4(Parent.into()), messages)] + } +} + #[cfg(feature = "runtime-benchmarks")] impl polkadot_runtime_common::xcm_sender::EnsureForParachain for Pallet { fn ensure(para_id: ParaId) { diff --git a/cumulus/pallets/parachain-system/src/mock.rs b/cumulus/pallets/parachain-system/src/mock.rs index fe89dfe68c67e4b5d9f9e046dcf2a780a292da0a..e8d2eb70e26296219bff909543083eb9663fae99 100644 --- a/cumulus/pallets/parachain-system/src/mock.rs +++ b/cumulus/pallets/parachain-system/src/mock.rs @@ -122,7 +122,7 @@ impl pallet_message_queue::Config for Test { type Size = u32; type QueueChangeHandler = (); type QueuePausedQuery = (); - type HeapSize = sp_core::ConstU32<{ 64 * 1024 }>; + type HeapSize = sp_core::ConstU32<{ 103 * 1024 }>; type MaxStale = sp_core::ConstU32<8>; type ServiceWeight = MaxWeight; type IdleMaxServiceWeight = (); diff --git a/cumulus/pallets/session-benchmarking/Cargo.toml b/cumulus/pallets/session-benchmarking/Cargo.toml index 43fde4ea6009cce7d2dedceb815e2948beb80196..001c3d8aceac5a5db27aba87d666fdf83e92021c 100644 --- a/cumulus/pallets/session-benchmarking/Cargo.toml +++ b/cumulus/pallets/session-benchmarking/Cargo.toml @@ -16,7 +16,7 @@ workspace = true targets = ["x86_64-unknown-linux-gnu"] [dependencies] -parity-scale-codec = { version = "3.6.4", default-features = false } +parity-scale-codec = { version = "3.6.12", default-features = false } sp-std = { path = "../../../substrate/primitives/std", default-features = false } sp-runtime = { path = "../../../substrate/primitives/runtime", default-features = false } frame-support = { path = "../../../substrate/frame/support", default-features = false } diff --git a/cumulus/pallets/session-benchmarking/src/inner.rs b/cumulus/pallets/session-benchmarking/src/inner.rs new file mode 100644 index 0000000000000000000000000000000000000000..cffd0776f3d99c99525d12e0392bdf177b246bd5 --- /dev/null +++ b/cumulus/pallets/session-benchmarking/src/inner.rs @@ -0,0 +1,42 @@ +// 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 pallet-session. + +use sp_std::{prelude::*, vec}; + +use frame_benchmarking::{benchmarks, whitelisted_caller}; +use frame_system::RawOrigin; +use pallet_session::*; +use parity_scale_codec::Decode; +pub struct Pallet(pallet_session::Pallet); +pub trait Config: pallet_session::Config {} + +benchmarks! { + set_keys { + let caller: T::AccountId = whitelisted_caller(); + frame_system::Pallet::::inc_providers(&caller); + let keys = T::Keys::decode(&mut sp_runtime::traits::TrailingZeroInput::zeroes()).unwrap(); + let proof: Vec = vec![0,1,2,3]; + }: _(RawOrigin::Signed(caller), keys, proof) + + purge_keys { + let caller: T::AccountId = whitelisted_caller(); + frame_system::Pallet::::inc_providers(&caller); + let keys = T::Keys::decode(&mut sp_runtime::traits::TrailingZeroInput::zeroes()).unwrap(); + let proof: Vec = vec![0,1,2,3]; + let _t = pallet_session::Pallet::::set_keys(RawOrigin::Signed(caller.clone()).into(), keys, proof); + }: _(RawOrigin::Signed(caller)) +} diff --git a/cumulus/pallets/session-benchmarking/src/lib.rs b/cumulus/pallets/session-benchmarking/src/lib.rs index f474def6b13762136ca90b2f812e9c5a3e26a0e2..a95d6fb7d591460f2055f076f60199b213b055b8 100644 --- a/cumulus/pallets/session-benchmarking/src/lib.rs +++ b/cumulus/pallets/session-benchmarking/src/lib.rs @@ -1,3 +1,5 @@ +// This file is part of Substrate. + // Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 @@ -13,31 +15,13 @@ // See the License for the specific language governing permissions and // limitations under the License. -//! Benchmarking setup for pallet-session -#![cfg_attr(not(feature = "std"), no_std)] -#![cfg(feature = "runtime-benchmarks")] -use sp_std::{prelude::*, vec}; +//! Benchmarks for the Session Pallet. +// This is separated into its own crate due to cyclic dependency issues. -use frame_benchmarking::{benchmarks, whitelisted_caller}; -use frame_system::RawOrigin; -use pallet_session::*; -use parity_scale_codec::Decode; -pub struct Pallet(pallet_session::Pallet); -pub trait Config: pallet_session::Config {} +#![cfg_attr(not(feature = "std"), no_std)] -benchmarks! { - set_keys { - let caller: T::AccountId = whitelisted_caller(); - frame_system::Pallet::::inc_providers(&caller); - let keys = T::Keys::decode(&mut sp_runtime::traits::TrailingZeroInput::zeroes()).unwrap(); - let proof: Vec = vec![0,1,2,3]; - }: _(RawOrigin::Signed(caller), keys, proof) +#[cfg(feature = "runtime-benchmarks")] +pub mod inner; - purge_keys { - let caller: T::AccountId = whitelisted_caller(); - frame_system::Pallet::::inc_providers(&caller); - let keys = T::Keys::decode(&mut sp_runtime::traits::TrailingZeroInput::zeroes()).unwrap(); - let proof: Vec = vec![0,1,2,3]; - let _t = pallet_session::Pallet::::set_keys(RawOrigin::Signed(caller.clone()).into(), keys, proof); - }: _(RawOrigin::Signed(caller)) -} +#[cfg(feature = "runtime-benchmarks")] +pub use inner::*; diff --git a/cumulus/pallets/solo-to-para/Cargo.toml b/cumulus/pallets/solo-to-para/Cargo.toml index 417038d7833c5ca4ec4acf681cba73d24ab45c5e..17b0fb2a01662d517a49d1bfd669ed071caf0ed7 100644 --- a/cumulus/pallets/solo-to-para/Cargo.toml +++ b/cumulus/pallets/solo-to-para/Cargo.toml @@ -10,7 +10,7 @@ license = "Apache-2.0" workspace = true [dependencies] -codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = ["derive"] } +codec = { package = "parity-scale-codec", version = "3.6.12", default-features = false, features = ["derive"] } scale-info = { version = "2.11.1", default-features = false, features = ["derive"] } # Substrate diff --git a/cumulus/pallets/xcm/Cargo.toml b/cumulus/pallets/xcm/Cargo.toml index 9122e110fb92e51b0f85e3ba4136d30178d8ab7a..178d981702f2e6dc42d05556e20a86f50106b6ee 100644 --- a/cumulus/pallets/xcm/Cargo.toml +++ b/cumulus/pallets/xcm/Cargo.toml @@ -10,7 +10,7 @@ description = "Pallet for stuff specific to parachains' usage of XCM" workspace = true [dependencies] -codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = ["derive"] } +codec = { package = "parity-scale-codec", version = "3.6.12", default-features = false, features = ["derive"] } scale-info = { version = "2.11.1", default-features = false, features = ["derive"] } sp-std = { path = "../../../substrate/primitives/std", default-features = false } diff --git a/cumulus/pallets/xcmp-queue/Cargo.toml b/cumulus/pallets/xcmp-queue/Cargo.toml index ab196c6d3ec6a089d8099d6ae893631ac513e9d7..1941214da2e7b868760fd3a7d0fcf065600a5caa 100644 --- a/cumulus/pallets/xcmp-queue/Cargo.toml +++ b/cumulus/pallets/xcmp-queue/Cargo.toml @@ -10,7 +10,7 @@ license = "Apache-2.0" workspace = true [dependencies] -codec = { package = "parity-scale-codec", version = "3.0.0", features = ["derive"], default-features = false } +codec = { package = "parity-scale-codec", version = "3.6.12", features = ["derive"], default-features = false } log = { workspace = true } scale-info = { version = "2.11.1", default-features = false, features = ["derive"] } @@ -28,6 +28,7 @@ polkadot-runtime-common = { path = "../../../polkadot/runtime/common", default-f polkadot-runtime-parachains = { path = "../../../polkadot/runtime/parachains", default-features = false } 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 } # Cumulus cumulus-primitives-core = { path = "../../primitives/core", default-features = false } @@ -46,9 +47,6 @@ sp-core = { path = "../../../substrate/primitives/core" } pallet-balances = { path = "../../../substrate/frame/balances" } frame-support = { path = "../../../substrate/frame/support", features = ["experimental"] } -# Polkadot -xcm-builder = { package = "staging-xcm-builder", path = "../../../polkadot/xcm/xcm-builder" } - # Cumulus cumulus-pallet-parachain-system = { path = "../parachain-system", features = ["parameterized-consensus-hook"] } @@ -71,6 +69,7 @@ std = [ "sp-io/std", "sp-runtime/std", "sp-std/std", + "xcm-builder/std", "xcm-executor/std", "xcm/std", ] diff --git a/cumulus/pallets/xcmp-queue/src/lib.rs b/cumulus/pallets/xcmp-queue/src/lib.rs index deced13a9e814ff2a4f05a9a02fe68d169b5a6be..5633f05f13bb81370a23512effefaf6ae1fb23fa 100644 --- a/cumulus/pallets/xcmp-queue/src/lib.rs +++ b/cumulus/pallets/xcmp-queue/src/lib.rs @@ -51,7 +51,7 @@ pub mod weights; pub use weights::WeightInfo; use bounded_collections::BoundedBTreeSet; -use codec::{Decode, DecodeLimit, Encode}; +use codec::{Decode, DecodeLimit, Encode, MaxEncodedLen}; use cumulus_primitives_core::{ relay_chain::BlockNumber as RelayBlockNumber, ChannelStatus, GetChannelInfo, MessageSendError, ParaId, XcmpMessageFormat, XcmpMessageHandler, XcmpMessageSource, @@ -59,7 +59,7 @@ use cumulus_primitives_core::{ use frame_support::{ defensive, defensive_assert, - traits::{EnqueueMessage, EnsureOrigin, Get, QueueFootprint, QueuePausedQuery}, + traits::{Defensive, EnqueueMessage, EnsureOrigin, Get, QueueFootprint, QueuePausedQuery}, weights::{Weight, WeightMeter}, BoundedVec, }; @@ -68,9 +68,10 @@ use polkadot_runtime_common::xcm_sender::PriceForMessageDelivery; use polkadot_runtime_parachains::FeeTracker; use scale_info::TypeInfo; use sp_core::MAX_POSSIBLE_ALLOCATION; -use sp_runtime::{FixedU128, RuntimeDebug, Saturating}; +use sp_runtime::{FixedU128, RuntimeDebug, Saturating, WeakBoundedVec}; use sp_std::prelude::*; -use xcm::{latest::prelude::*, VersionedXcm, WrapVersion, MAX_XCM_DECODE_DEPTH}; +use xcm::{latest::prelude::*, VersionedLocation, VersionedXcm, WrapVersion, MAX_XCM_DECODE_DEPTH}; +use xcm_builder::InspectMessageQueues; use xcm_executor::traits::ConvertOrigin; pub use pallet::*; @@ -105,7 +106,6 @@ pub mod pallet { #[pallet::pallet] #[pallet::storage_version(migration::STORAGE_VERSION)] - #[pallet::without_storage_info] pub struct Pallet(_); #[pallet::config] @@ -132,6 +132,25 @@ pub mod pallet { #[pallet::constant] type MaxInboundSuspended: Get; + /// Maximal number of outbound XCMP channels that can have messages queued at the same time. + /// + /// If this is reached, then no further messages can be sent to channels that do not yet + /// have a message queued. This should be set to the expected maximum of outbound channels + /// which is determined by [`Self::ChannelInfo`]. It is important to set this large enough, + /// since otherwise the congestion control protocol will not work as intended and messages + /// may be dropped. This value increases the PoV and should therefore not be picked too + /// high. Governance needs to pay attention to not open more channels than this value. + #[pallet::constant] + type MaxActiveOutboundChannels: Get; + + /// The maximal page size for HRMP message pages. + /// + /// A lower limit can be set dynamically, but this is the hard-limit for the PoV worst case + /// benchmarking. The limit for the size of a message is slightly below this, since some + /// overhead is incurred for encoding the format. + #[pallet::constant] + type MaxPageSize: Get; + /// The origin that is allowed to resume or suspend the XCMP queue. type ControllerOrigin: EnsureOrigin; @@ -276,6 +295,10 @@ pub mod pallet { AlreadySuspended, /// The execution is already resumed. AlreadyResumed, + /// There are too many active outbound channels. + TooManyActiveOutboundChannels, + /// The message is too big. + TooBig, } /// The suspended inbound XCMP channels. All others are not suspended. @@ -297,19 +320,28 @@ pub mod pallet { /// case of the need to send a high-priority signal message this block. /// The bool is true if there is a signal message waiting to be sent. #[pallet::storage] - pub(super) type OutboundXcmpStatus = - StorageValue<_, Vec, ValueQuery>; + pub(super) type OutboundXcmpStatus = StorageValue< + _, + BoundedVec, + ValueQuery, + >; - // The new way of doing it: /// The messages outbound in a given XCMP channel. #[pallet::storage] - pub(super) type OutboundXcmpMessages = - StorageDoubleMap<_, Blake2_128Concat, ParaId, Twox64Concat, u16, Vec, ValueQuery>; + pub(super) type OutboundXcmpMessages = StorageDoubleMap< + _, + Blake2_128Concat, + ParaId, + Twox64Concat, + u16, + WeakBoundedVec, + ValueQuery, + >; /// Any signal messages waiting to be sent. #[pallet::storage] pub(super) type SignalMessages = - StorageMap<_, Blake2_128Concat, ParaId, Vec, ValueQuery>; + StorageMap<_, Blake2_128Concat, ParaId, WeakBoundedVec, ValueQuery>; /// The configuration which controls the dynamics of the outbound queue. #[pallet::storage] @@ -331,15 +363,14 @@ pub mod pallet { StorageMap<_, Twox64Concat, ParaId, FixedU128, ValueQuery, InitialFactor>; } -#[derive(Copy, Clone, Eq, PartialEq, Encode, Decode, RuntimeDebug, TypeInfo)] +#[derive(Copy, Clone, Eq, PartialEq, Encode, Decode, RuntimeDebug, TypeInfo, MaxEncodedLen)] pub enum OutboundState { Ok, Suspended, } /// Struct containing detailed information about the outbound channel. -#[derive(Clone, Eq, PartialEq, Encode, Decode, TypeInfo)] -#[cfg_attr(feature = "std", derive(Debug))] +#[derive(Clone, Eq, PartialEq, Encode, Decode, TypeInfo, RuntimeDebug, MaxEncodedLen)] pub struct OutboundChannelDetails { /// The `ParaId` of the parachain that this channel is connected with. recipient: ParaId, @@ -375,7 +406,7 @@ impl OutboundChannelDetails { } } -#[derive(Copy, Clone, Eq, PartialEq, Encode, Decode, RuntimeDebug, TypeInfo)] +#[derive(Copy, Clone, Eq, PartialEq, Encode, Decode, RuntimeDebug, TypeInfo, MaxEncodedLen)] pub struct QueueConfigData { /// The number of pages which must be in the queue for the other side to be told to suspend /// their sending. @@ -478,7 +509,10 @@ impl Pallet { { details } else { - all_channels.push(OutboundChannelDetails::new(recipient)); + all_channels.try_push(OutboundChannelDetails::new(recipient)).map_err(|e| { + log::error!("Failed to activate HRMP channel: {:?}", e); + MessageSendError::TooManyChannels + })?; all_channels .last_mut() .expect("can't be empty; a new element was just pushed; qed") @@ -503,7 +537,9 @@ impl Pallet { if page.len() + encoded_fragment.len() > max_message_size { return None } - page.extend_from_slice(&encoded_fragment[..]); + for frag in encoded_fragment.iter() { + page.try_push(*frag).ok()?; + } Some(page.len()) }, ) @@ -521,7 +557,10 @@ impl Pallet { new_page.extend_from_slice(&encoded_fragment[..]); let last_page_size = new_page.len(); let number_of_pages = (channel_details.last_index - channel_details.first_index) as u32; - >::insert(recipient, page_index, new_page); + let bounded_page = BoundedVec::::try_from(new_page) + .map_err(|_| MessageSendError::TooBig)?; + let bounded_page = WeakBoundedVec::force_from(bounded_page.into_inner(), None); + >::insert(recipient, page_index, bounded_page); >::put(all_channels); (number_of_pages, last_page_size) }; @@ -543,17 +582,24 @@ impl Pallet { /// Sends a signal to the `dest` chain over XCMP. This is guaranteed to be dispatched on this /// block. - fn send_signal(dest: ParaId, signal: ChannelSignal) { + fn send_signal(dest: ParaId, signal: ChannelSignal) -> Result<(), Error> { let mut s = >::get(); if let Some(details) = s.iter_mut().find(|item| item.recipient == dest) { details.signals_exist = true; } else { - s.push(OutboundChannelDetails::new(dest).with_signals()); + s.try_push(OutboundChannelDetails::new(dest).with_signals()) + .map_err(|_| Error::::TooManyActiveOutboundChannels)?; } - >::mutate(dest, |page| { - *page = (XcmpMessageFormat::Signals, signal).encode(); - }); + + let page = BoundedVec::::try_from( + (XcmpMessageFormat::Signals, signal).encode(), + ) + .map_err(|_| Error::::TooBig)?; + let page = WeakBoundedVec::force_from(page.into_inner(), None); + + >::insert(dest, page); >::put(s); + Ok(()) } fn suspend_channel(target: ParaId) { @@ -563,7 +609,9 @@ impl Pallet { defensive_assert!(ok, "WARNING: Attempt to suspend channel that was not Ok."); details.state = OutboundState::Suspended; } else { - s.push(OutboundChannelDetails::new(target).with_suspended_state()); + if s.try_push(OutboundChannelDetails::new(target).with_suspended_state()).is_err() { + defensive!("Cannot pause channel; too many outbound channels"); + } } }); } @@ -664,18 +712,25 @@ impl OnQueueChanged for Pallet { let suspended = suspended_channels.contains(¶); if suspended && fp.ready_pages <= resume_threshold { - Self::send_signal(para, ChannelSignal::Resume); - - suspended_channels.remove(¶); - >::put(suspended_channels); + if let Err(err) = Self::send_signal(para, ChannelSignal::Resume) { + log::error!("defensive: Could not send resumption signal to inbound channel of sibling {:?}: {:?}; channel remains suspended.", para, err); + } else { + suspended_channels.remove(¶); + >::put(suspended_channels); + } } 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); - if let Err(err) = suspended_channels.try_insert(para) { + if let Err(err) = Self::send_signal(para, ChannelSignal::Suspend) { + // It will retry if `drop_threshold` is not reached, but it could be too late. + log::error!( + "defensive: Could not send suspension signal; future messages may be dropped: {:?}", err + ); + } else if let Err(err) = suspended_channels.try_insert(para) { log::error!("Too many channels suspended; cannot suspend sibling {:?}: {:?}; further messages may be dropped.", para, err); + } else { + >::put(suspended_channels); } - >::put(suspended_channels); } } } @@ -842,7 +897,7 @@ impl XcmpMessageSource for Pallet { // since it's so unlikely then for now we just drop it. defensive!("WARNING: oversize message in queue - dropping"); } else { - result.push((para_id, page)); + result.push((para_id, page.into_inner())); } let max_total_size = match T::ChannelInfo::get_channel_info(para_id) { @@ -890,7 +945,9 @@ impl XcmpMessageSource for Pallet { let pruned = old_statuses_len - statuses.len(); // removing an item from status implies a message being sent, so the result messages must // be no less than the pruned channels. - statuses.rotate_left(result.len().saturating_sub(pruned)); + let _ = statuses.try_rotate_left(result.len().saturating_sub(pruned)).defensive_proof( + "Could not store HRMP channels config. Some HRMP channels may be broken.", + ); >::put(statuses); @@ -916,7 +973,8 @@ impl SendXcm for Pallet { let price = T::PriceForSiblingDelivery::price_for_delivery(id, &xcm); let versioned_xcm = T::VersionWrapper::wrap_version(&d, xcm) .map_err(|()| SendError::DestinationUnsupported)?; - validate_xcm_nesting(&versioned_xcm) + versioned_xcm + .validate_xcm_nesting() .map_err(|()| SendError::ExceedsMaxMessageSize)?; Ok(((id, versioned_xcm), price)) @@ -932,10 +990,6 @@ impl SendXcm for Pallet { fn deliver((id, xcm): (ParaId, VersionedXcm<()>)) -> Result { let hash = xcm.using_encoded(sp_io::hashing::blake2_256); - defensive_assert!( - validate_xcm_nesting(&xcm).is_ok(), - "Tickets are valid prior to delivery by trait XCM; qed" - ); match Self::send_fragment(id, XcmpMessageFormat::ConcatenatedVersionedXcm, xcm) { Ok(_) => { @@ -950,14 +1004,36 @@ impl SendXcm for Pallet { } } -/// Checks that the XCM is decodable with `MAX_XCM_DECODE_DEPTH`. -/// -/// Note that this uses the limit of the sender - not the receiver. It it best effort. -pub(crate) fn validate_xcm_nesting(xcm: &VersionedXcm<()>) -> Result<(), ()> { - xcm.using_encoded(|mut enc| { - VersionedXcm::<()>::decode_all_with_depth_limit(MAX_XCM_DECODE_DEPTH, &mut enc).map(|_| ()) - }) - .map_err(|_| ()) +impl InspectMessageQueues for Pallet { + fn get_messages() -> Vec<(VersionedLocation, Vec>)> { + use xcm::prelude::*; + + OutboundXcmpMessages::::iter() + .map(|(para_id, _, messages)| { + let mut data = &messages[..]; + let decoded_format = + XcmpMessageFormat::decode_with_depth_limit(MAX_XCM_DECODE_DEPTH, &mut data) + .unwrap(); + if decoded_format != XcmpMessageFormat::ConcatenatedVersionedXcm { + panic!("Unexpected format.") + } + let mut decoded_messages = Vec::new(); + while !data.is_empty() { + let decoded_message = VersionedXcm::<()>::decode_with_depth_limit( + MAX_XCM_DECODE_DEPTH, + &mut data, + ) + .unwrap(); + decoded_messages.push(decoded_message); + } + + ( + VersionedLocation::V4((Parent, Parachain(para_id.into())).into()), + decoded_messages, + ) + }) + .collect() + } } impl FeeTracker for Pallet { diff --git a/cumulus/pallets/xcmp-queue/src/migration.rs b/cumulus/pallets/xcmp-queue/src/migration.rs index 1702cd70bc2fb7e09cf15fbe21294bdb76b96ef1..b64982a893029f51aeb689d94d54066165ac40a3 100644 --- a/cumulus/pallets/xcmp-queue/src/migration.rs +++ b/cumulus/pallets/xcmp-queue/src/migration.rs @@ -16,6 +16,8 @@ //! A module that is responsible for migration of storage. +pub mod v5; + use crate::{Config, OverweightIndex, Pallet, QueueConfig, QueueConfigData, DEFAULT_POV_SIZE}; use cumulus_primitives_core::XcmpMessageFormat; use frame_support::{ @@ -25,7 +27,7 @@ use frame_support::{ }; /// The in-code storage version. -pub const STORAGE_VERSION: StorageVersion = StorageVersion::new(4); +pub const STORAGE_VERSION: StorageVersion = StorageVersion::new(5); pub const LOG: &str = "runtime::xcmp-queue-migration"; diff --git a/cumulus/pallets/xcmp-queue/src/migration/v5.rs b/cumulus/pallets/xcmp-queue/src/migration/v5.rs new file mode 100644 index 0000000000000000000000000000000000000000..247adab7108fac8a278ee81827a9e65e27c320f0 --- /dev/null +++ b/cumulus/pallets/xcmp-queue/src/migration/v5.rs @@ -0,0 +1,108 @@ +// 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 . + +//! Migrates the storage to version 5. + +use crate::*; +use cumulus_primitives_core::ListChannelInfos; +use frame_support::{pallet_prelude::*, traits::UncheckedOnRuntimeUpgrade}; + +/// Configs needed to run the V5 migration. +pub trait V5Config: Config { + /// List all outbound channels with their target `ParaId` and maximum message size. + type ChannelList: ListChannelInfos; +} + +/// Ensures that the storage migrates cleanly to V5. +/// +/// The migration itself is a no-op, but it checks that none of the `BoundedVec`s would truncate on +/// the next decode after the upgrade was applied. +pub type MigrateV4ToV5 = frame_support::migrations::VersionedMigration< + 4, + 5, + unversioned::UncheckedMigrateV4ToV5, + Pallet, + ::DbWeight, +>; + +// V4 storage aliases +mod v4 { + use super::*; + + #[frame_support::storage_alias] + pub(super) type OutboundXcmpStatus = + StorageValue, Vec, ValueQuery>; + + #[frame_support::storage_alias] + pub(super) type OutboundXcmpMessages = StorageDoubleMap< + Pallet, + Blake2_128Concat, + ParaId, + Twox64Concat, + u16, + Vec, + ValueQuery, + >; + + #[frame_support::storage_alias] + pub(super) type SignalMessages = + StorageMap, Blake2_128Concat, ParaId, Vec, ValueQuery>; +} + +// Private module to hide the migration. +mod unversioned { + /// Please use [`MigrateV4ToV5`] instead. + pub struct UncheckedMigrateV4ToV5(core::marker::PhantomData); +} + +impl UncheckedOnRuntimeUpgrade for unversioned::UncheckedMigrateV4ToV5 { + fn on_runtime_upgrade() -> frame_support::weights::Weight { + Default::default() + } + + #[cfg(feature = "try-runtime")] + fn post_upgrade(_: Vec) -> Result<(), sp_runtime::DispatchError> { + // We dont need any front-run protection for this since channels are opened by governance. + ensure!( + v4::OutboundXcmpStatus::::get().len() as u32 <= T::MaxActiveOutboundChannels::get(), + "Too many outbound channels. Close some channels or increase `MaxActiveOutboundChannels`." + ); + + ensure!(T::MaxPageSize::get() >= 16, "Sanity check failed: MaxPageSize too small"); + + // Check if any channels have a too large message max sizes. + let max_msg_len = T::MaxPageSize::get() - XcmpMessageFormat::max_encoded_len() as u32; + for channel in T::ChannelList::outgoing_channels() { + let info = T::ChannelInfo::get_channel_info(channel) + .expect("All listed channels must provide info"); + + if info.max_message_size > max_msg_len { + log::error!( + "Max message size for channel is too large. This means that the V5 \ + migration can be front-run and an attacker could place a large message just right \ + before the migration to make other messages un-decodable. Please either increase \ + `MaxPageSize` or decrease the `max_message_size` for this channel. Channel max: {}, \ + MaxPageSize: {}", + info.max_message_size, + max_msg_len + ); + return Err("Migration can be front-run".into()); + } + } + + Ok(()) + } +} diff --git a/cumulus/pallets/xcmp-queue/src/mock.rs b/cumulus/pallets/xcmp-queue/src/mock.rs index 9d9a723cf8b538b604c45ff5b2bd366cd6f92c2d..97121aa78e9ad0359413b41fb0960e65fddf1335 100644 --- a/cumulus/pallets/xcmp-queue/src/mock.rs +++ b/cumulus/pallets/xcmp-queue/src/mock.rs @@ -178,6 +178,7 @@ impl xcm_executor::Config for XcmConfig { type HrmpNewChannelOpenRequestHandler = (); type HrmpChannelAcceptedHandler = (); type HrmpChannelClosingHandler = (); + type XcmRecorder = (); } pub type XcmRouter = ( @@ -276,7 +277,11 @@ impl Config for Test { type ChannelInfo = MockedChannelInfo; type VersionWrapper = (); type XcmpQueue = EnqueueToLocalStorage>; - type MaxInboundSuspended = sp_core::ConstU32<1_000>; + type MaxInboundSuspended = ConstU32<1_000>; + type MaxActiveOutboundChannels = ConstU32<128>; + // Most on-chain HRMP channels are configured to use 102400 bytes of max message size, so we + // need to set the page size larger than that until we reduce the channel size on-chain. + type MaxPageSize = ConstU32<{ 103 * 1024 }>; type ControllerOrigin = EnsureRoot; type ControllerOriginConverter = SystemParachainAsSuperuser; type WeightInfo = (); diff --git a/cumulus/pallets/xcmp-queue/src/tests.rs b/cumulus/pallets/xcmp-queue/src/tests.rs index 0b41095828f2f93810a2855d175ecd60a12853d7..7c02059e5a90477a761ee8bb9ae00d6e2cf6e124 100644 --- a/cumulus/pallets/xcmp-queue/src/tests.rs +++ b/cumulus/pallets/xcmp-queue/src/tests.rs @@ -520,7 +520,7 @@ fn hrmp_signals_are_prioritized() { }); // But a signal gets prioritized instead of the messages: - XcmpQueue::send_signal(sibling_para_id.into(), ChannelSignal::Suspend); + assert_ok!(XcmpQueue::send_signal(sibling_para_id.into(), ChannelSignal::Suspend)); let taken = XcmpQueue::take_outbound_messages(130); assert_eq!( @@ -844,3 +844,43 @@ fn verify_fee_factor_increase_and_decrease() { assert!(DeliveryFeeFactor::::get(sibling_para_id) < FixedU128::from_float(1.63)); }); } + +#[test] +fn get_messages_works() { + new_test_ext().execute_with(|| { + use xcm_builder::InspectMessageQueues; + let sibling_para_id = ParaId::from(2001); + ParachainSystem::open_outbound_hrmp_channel_for_benchmarks_or_tests(sibling_para_id); + let destination: Location = (Parent, Parachain(sibling_para_id.into())).into(); + let other_sibling_para_id = ParaId::from(2002); + let other_destination: Location = (Parent, Parachain(other_sibling_para_id.into())).into(); + let message = Xcm(vec![ClearOrigin]); + assert_ok!(send_xcm::(destination.clone(), message.clone())); + assert_ok!(send_xcm::(destination.clone(), message.clone())); + assert_ok!(send_xcm::(destination.clone(), message.clone())); + ParachainSystem::open_outbound_hrmp_channel_for_benchmarks_or_tests(other_sibling_para_id); + assert_ok!(send_xcm::(other_destination.clone(), message.clone())); + assert_ok!(send_xcm::(other_destination.clone(), message)); + let queued_messages = XcmpQueue::get_messages(); + assert_eq!( + queued_messages, + vec![ + ( + VersionedLocation::V4(other_destination), + vec![ + VersionedXcm::V4(Xcm(vec![ClearOrigin])), + VersionedXcm::V4(Xcm(vec![ClearOrigin])), + ], + ), + ( + VersionedLocation::V4(destination), + vec![ + VersionedXcm::V4(Xcm(vec![ClearOrigin])), + VersionedXcm::V4(Xcm(vec![ClearOrigin])), + VersionedXcm::V4(Xcm(vec![ClearOrigin])), + ], + ), + ], + ); + }); +} diff --git a/cumulus/parachains/chain-specs/asset-hub-kusama.json b/cumulus/parachains/chain-specs/asset-hub-kusama.json index 66a705a40869ce6eb3fe2ac7a028ce68c784c18c..00e342381ee1c06a65bfaa51111fb55643cfabba 100644 --- a/cumulus/parachains/chain-specs/asset-hub-kusama.json +++ b/cumulus/parachains/chain-specs/asset-hub-kusama.json @@ -11,8 +11,8 @@ "/dns/boot.stake.plus/tcp/34334/wss/p2p/12D3KooWAzSSZ7jLqMw1WPomYEKCYANQaKemXQ8BKoFvNEvfmdqR", "/dns/boot.metaspan.io/tcp/26052/p2p/12D3KooW9z9hKqe3mqYAp5UJMhZiCqhkTHyiR43fegnGmTJ3JAba", "/dns/boot.metaspan.io/tcp/26056/wss/p2p/12D3KooW9z9hKqe3mqYAp5UJMhZiCqhkTHyiR43fegnGmTJ3JAba", - "/dns/boot-cr.gatotech.network/tcp/33210/p2p/12D3KooWRMUYeWMPkadDG8baX9j1e95fspfp8MhPGym5BQza7Fm5", - "/dns/boot-cr.gatotech.network/tcp/35210/wss/p2p/12D3KooWRMUYeWMPkadDG8baX9j1e95fspfp8MhPGym5BQza7Fm5", + "/dns/boot.gatotech.network/tcp/33210/p2p/12D3KooWRMUYeWMPkadDG8baX9j1e95fspfp8MhPGym5BQza7Fm5", + "/dns/boot.gatotech.network/tcp/35210/wss/p2p/12D3KooWRMUYeWMPkadDG8baX9j1e95fspfp8MhPGym5BQza7Fm5", "/dns/statemine-bootnode.turboflakes.io/tcp/30320/p2p/12D3KooWN2Qqvp5wWgjbBMpbqhKgvSibSHfomP5VWVD9VCn3VrV4", "/dns/statemine-bootnode.turboflakes.io/tcp/30420/wss/p2p/12D3KooWN2Qqvp5wWgjbBMpbqhKgvSibSHfomP5VWVD9VCn3VrV4", "/dns/boot-node.helikon.io/tcp/10210/p2p/12D3KooWFXRQce3aMgZMn5SxvHtYH4PsR63TZLf8LrnBsEVTyzdr", diff --git a/cumulus/parachains/chain-specs/asset-hub-polkadot.json b/cumulus/parachains/chain-specs/asset-hub-polkadot.json index 16caa52ba91376ed30187c89d249ff38ed1ea42a..22b11757b66bb7103152997b4d276378f0960700 100644 --- a/cumulus/parachains/chain-specs/asset-hub-polkadot.json +++ b/cumulus/parachains/chain-specs/asset-hub-polkadot.json @@ -11,8 +11,8 @@ "/dns/boot.stake.plus/tcp/35334/wss/p2p/12D3KooWFrQjYaPZSSLLxEVmoaHFcrF6VoY4awG4KRSLaqy3JCdQ", "/dns/boot.metaspan.io/tcp/16052/p2p/12D3KooWLwiJuvqQUB4kYaSjLenFKH9dWZhGZ4qi7pSb3sUYU651", "/dns/boot.metaspan.io/tcp/16056/wss/p2p/12D3KooWLwiJuvqQUB4kYaSjLenFKH9dWZhGZ4qi7pSb3sUYU651", - "/dns/boot-cr.gatotech.network/tcp/33110/p2p/12D3KooWKgwQfAeDoJARdtxFNNWfbYmcu6s4yUuSifnNoDgzHZgm", - "/dns/boot-cr.gatotech.network/tcp/35110/wss/p2p/12D3KooWKgwQfAeDoJARdtxFNNWfbYmcu6s4yUuSifnNoDgzHZgm", + "/dns/boot.gatotech.network/tcp/33110/p2p/12D3KooWKgwQfAeDoJARdtxFNNWfbYmcu6s4yUuSifnNoDgzHZgm", + "/dns/boot.gatotech.network/tcp/35110/wss/p2p/12D3KooWKgwQfAeDoJARdtxFNNWfbYmcu6s4yUuSifnNoDgzHZgm", "/dns/statemint-bootnode.turboflakes.io/tcp/30315/p2p/12D3KooWL8CyLww3m3pRySQGGYGNJhWDMqko3j5xi67ckP7hDUvo", "/dns/statemint-bootnode.turboflakes.io/tcp/30415/wss/p2p/12D3KooWL8CyLww3m3pRySQGGYGNJhWDMqko3j5xi67ckP7hDUvo", "/dns/boot-node.helikon.io/tcp/10220/p2p/12D3KooW9uybhguhDjVJc3U3kgZC3i8rWmAnSpbnJkmuR7C6ZsRW", diff --git a/cumulus/parachains/chain-specs/asset-hub-rococo.json b/cumulus/parachains/chain-specs/asset-hub-rococo.json index 900d9f0ffb2c35645d59e16649ee49b7713a01f1..87ff2fb220a19b1ec01d280be6e58ab2cafffd90 100644 --- a/cumulus/parachains/chain-specs/asset-hub-rococo.json +++ b/cumulus/parachains/chain-specs/asset-hub-rococo.json @@ -4,7 +4,11 @@ "chainType": "Live", "bootNodes": [ "/dns/rococo-asset-hub-bootnode-0.polkadot.io/tcp/30333/p2p/12D3KooWRrZMndHAopzao34uGsN7srjS3gh9nAjTGKLSyJeU31Lg", - "/dns/rococo-asset-hub-bootnode-1.polkadot.io/tcp/30333/p2p/12D3KooWAewimoNJqMaiiV5pYiowA5hLuh5JS5QiRJCCyWVrrSTS" + "/dns/rococo-asset-hub-bootnode-1.polkadot.io/tcp/30333/p2p/12D3KooWAewimoNJqMaiiV5pYiowA5hLuh5JS5QiRJCCyWVrrSTS", + "/dns/rococo-asset-hub-bootnode-0.polkadot.io/tcp/30335/ws/p2p/12D3KooWRrZMndHAopzao34uGsN7srjS3gh9nAjTGKLSyJeU31Lg", + "/dns/rococo-asset-hub-bootnode-1.polkadot.io/tcp/30335/ws/p2p/12D3KooWAewimoNJqMaiiV5pYiowA5hLuh5JS5QiRJCCyWVrrSTS", + "/dns/rococo-asset-hub-bootnode-0.polkadot.io/tcp/443/wss/p2p/12D3KooWRrZMndHAopzao34uGsN7srjS3gh9nAjTGKLSyJeU31Lg", + "/dns/rococo-asset-hub-bootnode-1.polkadot.io/tcp/443/wss/p2p/12D3KooWAewimoNJqMaiiV5pYiowA5hLuh5JS5QiRJCCyWVrrSTS" ], "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 670935c9d2474242307d691d8707030c70f49982..830eb2c5918069ac46fed21a27360ba92c5aebce 100644 --- a/cumulus/parachains/chain-specs/asset-hub-westend.json +++ b/cumulus/parachains/chain-specs/asset-hub-westend.json @@ -5,12 +5,16 @@ "bootNodes": [ "/dns/westend-asset-hub-bootnode-0.polkadot.io/tcp/30333/p2p/12D3KooWJaAfPyiye7ZQBuHengTJJoMrcaz7Jj1UzHiKdNxA1Nkd", "/dns/westend-asset-hub-bootnode-1.polkadot.io/tcp/30333/p2p/12D3KooWGL3hpWycWyeqyL9gHNnmmsL474WkPZdqraBHu4L6fQrW", + "/dns/westend-asset-hub-bootnode-0.polkadot.io/tcp/30335/ws/p2p/12D3KooWJaAfPyiye7ZQBuHengTJJoMrcaz7Jj1UzHiKdNxA1Nkd", + "/dns/westend-asset-hub-bootnode-1.polkadot.io/tcp/30335/ws/p2p/12D3KooWGL3hpWycWyeqyL9gHNnmmsL474WkPZdqraBHu4L6fQrW", + "/dns/westend-asset-hub-connect-0.polkadot.io/tcp/443/wss/p2p/12D3KooWJaAfPyiye7ZQBuHengTJJoMrcaz7Jj1UzHiKdNxA1Nkd", + "/dns/westend-asset-hub-connect-1.polkadot.io/tcp/443/wss/p2p/12D3KooWGL3hpWycWyeqyL9gHNnmmsL474WkPZdqraBHu4L6fQrW", "/dns/boot.stake.plus/tcp/33333/p2p/12D3KooWNiB27rpXX7EYongoWWUeRKzLQxWGms6MQU2B9LX7Ztzo", "/dns/boot.stake.plus/tcp/33334/wss/p2p/12D3KooWNiB27rpXX7EYongoWWUeRKzLQxWGms6MQU2B9LX7Ztzo", "/dns/boot.metaspan.io/tcp/36052/p2p/12D3KooWBCqfNb6Y39DXTr4UBWXyjuS3hcZM1qTbHhDXxF6HkAJJ", "/dns/boot.metaspan.io/tcp/36056/wss/p2p/12D3KooWBCqfNb6Y39DXTr4UBWXyjuS3hcZM1qTbHhDXxF6HkAJJ", - "/dns/boot-cr.gatotech.network/tcp/33310/p2p/12D3KooWMSW6hr8KcNBhGFN1bg8kYC76o67PnuDEbxRhxacW6dui", - "/dns/boot-cr.gatotech.network/tcp/35310/wss/p2p/12D3KooWMSW6hr8KcNBhGFN1bg8kYC76o67PnuDEbxRhxacW6dui", + "/dns/boot.gatotech.network/tcp/33310/p2p/12D3KooWMSW6hr8KcNBhGFN1bg8kYC76o67PnuDEbxRhxacW6dui", + "/dns/boot.gatotech.network/tcp/35310/wss/p2p/12D3KooWMSW6hr8KcNBhGFN1bg8kYC76o67PnuDEbxRhxacW6dui", "/dns/westmint-bootnode.turboflakes.io/tcp/30325/p2p/12D3KooWHU4qqSyqKdbXdrCTMXUJxxueaZjqpqSaQqYiFPw6XqEx", "/dns/westmint-bootnode.turboflakes.io/tcp/30425/wss/p2p/12D3KooWHU4qqSyqKdbXdrCTMXUJxxueaZjqpqSaQqYiFPw6XqEx", "/dns/boot-node.helikon.io/tcp/10200/p2p/12D3KooWMRY8wb7rMT81LLuivvsy6ahUxKHQgYJw4zm1hC1uYLxb", diff --git a/cumulus/parachains/chain-specs/bridge-hub-kusama.json b/cumulus/parachains/chain-specs/bridge-hub-kusama.json index 6644ea41ab748548d3c6dcbd06951522672dbb53..46b33ed44c1a823daf25a2e834abc602cb35f0dc 100644 --- a/cumulus/parachains/chain-specs/bridge-hub-kusama.json +++ b/cumulus/parachains/chain-specs/bridge-hub-kusama.json @@ -11,8 +11,8 @@ "/dns/boot.stake.plus/tcp/41334/wss/p2p/12D3KooWBzbs2jsXjG5dipktGPKaUm9XWvkmeJFsEAGkVt946Aa7", "/dns/boot.metaspan.io/tcp/26032/p2p/12D3KooWKfuSaZrLNz43PDgM4inMALXRHTSh2WBuqQtZRq8zmT1Z", "/dns/boot.metaspan.io/tcp/26036/wss/p2p/12D3KooWKfuSaZrLNz43PDgM4inMALXRHTSh2WBuqQtZRq8zmT1Z", - "/dns/boot-cr.gatotech.network/tcp/33230/p2p/12D3KooWFQFmg8UqAYLDNc2onySB6o5LLvpbx3eXZVqz9YFxAmXs", - "/dns/boot-cr.gatotech.network/tcp/35230/wss/p2p/12D3KooWFQFmg8UqAYLDNc2onySB6o5LLvpbx3eXZVqz9YFxAmXs", + "/dns/boot.gatotech.network/tcp/33230/p2p/12D3KooWFQFmg8UqAYLDNc2onySB6o5LLvpbx3eXZVqz9YFxAmXs", + "/dns/boot.gatotech.network/tcp/35230/wss/p2p/12D3KooWFQFmg8UqAYLDNc2onySB6o5LLvpbx3eXZVqz9YFxAmXs", "/dns/bridge-hub-kusama-bootnode.turboflakes.io/tcp/30615/p2p/12D3KooWE3dJXbwA5SQqbDNxHfj7BXJRcy2KiXWjJY4VUMKoa7S2", "/dns/bridge-hub-kusama-bootnode.turboflakes.io/tcp/30715/wss/p2p/12D3KooWE3dJXbwA5SQqbDNxHfj7BXJRcy2KiXWjJY4VUMKoa7S2", "/dns/boot-node.helikon.io/tcp/10250/p2p/12D3KooWDJLkhqQdXcVKWX7CqJHnpAY6PzrPc4ZG2CUWnARbmguy", diff --git a/cumulus/parachains/chain-specs/bridge-hub-polkadot.json b/cumulus/parachains/chain-specs/bridge-hub-polkadot.json index c51c5eff89b86a0ce553bbcfc472f6fb5cf0d535..0a642caddb7684b35b74eb4b115157667f4370ba 100644 --- a/cumulus/parachains/chain-specs/bridge-hub-polkadot.json +++ b/cumulus/parachains/chain-specs/bridge-hub-polkadot.json @@ -9,8 +9,10 @@ "/dns/polkadot-bridge-hub-connect-a-1.polkadot.io/tcp/443/wss/p2p/12D3KooWG4ypDHLKGCv4BZ6PuaGUwQHKAH6p2D6arR2uQ1eiR1T3", "/dns/polkadot-bridge-hub-boot-ng.dwellir.com/tcp/30339/p2p/12D3KooWPZ38PL3PhRVcUVYDNn7nRcZF8MykmWWLBKeDV2yna1vV", "/dns/polkadot-bridge-hub-boot-ng.dwellir.com/tcp/443/wss/p2p/12D3KooWPZ38PL3PhRVcUVYDNn7nRcZF8MykmWWLBKeDV2yna1vV", - "/dns/boot-cr.gatotech.network/tcp/33130/p2p/12D3KooWCnFzfEdd7MwUNrrDv66FuS2DM5MGuiaB4y48XS7qNjF6", - "/dns/boot-cr.gatotech.network/tcp/35130/wss/p2p/12D3KooWCnFzfEdd7MwUNrrDv66FuS2DM5MGuiaB4y48XS7qNjF6", + "/dns/boot.gatotech.network/tcp/33130/p2p/12D3KooWCnFzfEdd7MwUNrrDv66FuS2DM5MGuiaB4y48XS7qNjF6", + "/dns/boot.gatotech.network/tcp/35130/wss/p2p/12D3KooWCnFzfEdd7MwUNrrDv66FuS2DM5MGuiaB4y48XS7qNjF6", + "/dns/boot.stake.plus/tcp/42333/p2p/12D3KooWEoTCu22Uab6prbfcD1FPpPZmfhkAVeMZQJ3fHnkCVmJz", + "/dns/boot.stake.plus/tcp/42334/wss/p2p/12D3KooWEoTCu22Uab6prbfcD1FPpPZmfhkAVeMZQJ3fHnkCVmJz", "/dns/bridge-hub-polkadot-bootnode.turboflakes.io/tcp/30610/p2p/12D3KooWNEgaQRQHJHvGDh8Rg4RyLmDCCz3yAf2gAdHZZJAUUD8Q", "/dns/bridge-hub-polkadot-bootnode.turboflakes.io/tcp/30710/wss/p2p/12D3KooWNEgaQRQHJHvGDh8Rg4RyLmDCCz3yAf2gAdHZZJAUUD8Q", "/dns/boot.metaspan.io/tcp/16032/p2p/12D3KooWQTfRnrK3FfbrotpSP5RVJbjBHVBSu8VSzhj9qcvjaqnZ", diff --git a/cumulus/parachains/chain-specs/bridge-hub-rococo.json b/cumulus/parachains/chain-specs/bridge-hub-rococo.json index 6b430678a86c88d35894819d6433fcf605270d79..53aef58422db38f8417d7add5abee0b6ecbbd755 100644 --- a/cumulus/parachains/chain-specs/bridge-hub-rococo.json +++ b/cumulus/parachains/chain-specs/bridge-hub-rococo.json @@ -4,7 +4,11 @@ "chainType": "Live", "bootNodes": [ "/dns/rococo-bridge-hub-collator-node-0.parity-testnet.parity.io/tcp/30333/p2p/12D3KooWJCFBJmFF65xz5xHeZQRSCf35BxfSEB3RHQFoLza28LWU", - "/dns/rococo-bridge-hub-collator-node-1.parity-testnet.parity.io/tcp/30333/p2p/12D3KooWJzLd8skcAgA24EcJey7aJAhYctfUxWGjSP5Usk9wbpPZ" + "/dns/rococo-bridge-hub-collator-node-1.parity-testnet.parity.io/tcp/30333/p2p/12D3KooWJzLd8skcAgA24EcJey7aJAhYctfUxWGjSP5Usk9wbpPZ", + "/dns/rococo-bridge-hub-collator-node-0.parity-testnet.parity.io/tcp/30335/ws/p2p/12D3KooWJCFBJmFF65xz5xHeZQRSCf35BxfSEB3RHQFoLza28LWU", + "/dns/rococo-bridge-hub-collator-node-1.parity-testnet.parity.io/tcp/30335/ws/p2p/12D3KooWJzLd8skcAgA24EcJey7aJAhYctfUxWGjSP5Usk9wbpPZ", + "/dns/rococo-bridge-hub-collator-node-0.parity-testnet.parity.io/tcp/443/wss/p2p/12D3KooWJCFBJmFF65xz5xHeZQRSCf35BxfSEB3RHQFoLza28LWU", + "/dns/rococo-bridge-hub-collator-node-1.parity-testnet.parity.io/tcp/443/wss/p2p/12D3KooWJzLd8skcAgA24EcJey7aJAhYctfUxWGjSP5Usk9wbpPZ" ], "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 447207a58107a95bcd5fca173d9d5476a0ce9cab..c07857894f71663fe80c35f775ea56ddd55accc4 100644 --- a/cumulus/parachains/chain-specs/bridge-hub-westend.json +++ b/cumulus/parachains/chain-specs/bridge-hub-westend.json @@ -5,10 +5,16 @@ "bootNodes": [ "/dns/westend-bridge-hub-collator-node-0.parity-testnet.parity.io/tcp/30333/p2p/12D3KooWKyEuqkkWvFSrwZWKWBAsHgLV3HGfHj7yH3LNJLAVhmxY", "/dns/westend-bridge-hub-collator-node-1.parity-testnet.parity.io/tcp/30333/p2p/12D3KooWBpvudthz61XC4oP2YYFFJdhWohBeQ1ffn1BMSGWhapjd", + "/dns/westend-bridge-hub-collator-node-0.parity-testnet.parity.io/tcp/30335/ws/p2p/12D3KooWKyEuqkkWvFSrwZWKWBAsHgLV3HGfHj7yH3LNJLAVhmxY", + "/dns/westend-bridge-hub-collator-node-1.parity-testnet.parity.io/tcp/30335/ws/p2p/12D3KooWBpvudthz61XC4oP2YYFFJdhWohBeQ1ffn1BMSGWhapjd", + "/dns/westend-bridge-hub-collator-node-0.parity-testnet.parity.io/tcp/443/wss/p2p/12D3KooWKyEuqkkWvFSrwZWKWBAsHgLV3HGfHj7yH3LNJLAVhmxY", + "/dns/westend-bridge-hub-collator-node-1.parity-testnet.parity.io/tcp/443/wss/p2p/12D3KooWBpvudthz61XC4oP2YYFFJdhWohBeQ1ffn1BMSGWhapjd", "/dns/westend-bridge-hub-boot-ng.dwellir.com/tcp/30338/p2p/12D3KooWJWWRYTAwBLqYkh7iMBGDr5ouJ3MHj7M3fZ7zWS4zEk6F", "/dns/westend-bridge-hub-boot-ng.dwellir.com/tcp/443/wss/p2p/12D3KooWJWWRYTAwBLqYkh7iMBGDr5ouJ3MHj7M3fZ7zWS4zEk6F", - "/dns/boot-cr.gatotech.network/tcp/33330/p2p/12D3KooWJHG6qznPzTSEbuujHNcvyzBZcR9zNRPFcXWUaoVWZBEw", - "/dns/boot-cr.gatotech.network/tcp/35330/wss/p2p/12D3KooWJHG6qznPzTSEbuujHNcvyzBZcR9zNRPFcXWUaoVWZBEw", + "/dns/boot.stake.plus/tcp/40333/p2p/12D3KooWPGMsGPdGJx6HrByiKUyz91wgUHmjG5UXTmkJ9tUphAQn", + "/dns/boot.stake.plus/tcp/40334/wss/p2p/12D3KooWPGMsGPdGJx6HrByiKUyz91wgUHmjG5UXTmkJ9tUphAQn", + "/dns/boot.gatotech.network/tcp/33330/p2p/12D3KooWJHG6qznPzTSEbuujHNcvyzBZcR9zNRPFcXWUaoVWZBEw", + "/dns/boot.gatotech.network/tcp/35330/wss/p2p/12D3KooWJHG6qznPzTSEbuujHNcvyzBZcR9zNRPFcXWUaoVWZBEw", "/dns/bridge-hub-westend-bootnode.turboflakes.io/tcp/30620/p2p/12D3KooWLeExhPWCDUjcxCdzxTP5TpPbNBVG5t9MPvk1dZUM5naU", "/dns/bridge-hub-westend-bootnode.turboflakes.io/tcp/30720/wss/p2p/12D3KooWLeExhPWCDUjcxCdzxTP5TpPbNBVG5t9MPvk1dZUM5naU", "/dns/boot.metaspan.io/tcp/36032/p2p/12D3KooWPaLsu3buByBnGFQnp5UP4q1S652dGVft92TFeChizFir", diff --git a/cumulus/parachains/chain-specs/collectives-polkadot.json b/cumulus/parachains/chain-specs/collectives-polkadot.json index ce80e21ae625e813be0f71245bc454cb284455f3..b2f3ff812d05da83d28be150de5a00466cc450bd 100644 --- a/cumulus/parachains/chain-specs/collectives-polkadot.json +++ b/cumulus/parachains/chain-specs/collectives-polkadot.json @@ -11,8 +11,8 @@ "/dns/boot.stake.plus/tcp/37334/wss/p2p/12D3KooWRgFfEtwPo3xorKGYALRHRteKNgF37iN9q8xTLPYc34LA", "/dns/boot.metaspan.io/tcp/16072/p2p/12D3KooWJWTTu2t2yg5bFRH6tjEpfzKwZir5R9JRRjQpgFPXdDfp", "/dns/boot.metaspan.io/tcp/16076/wss/p2p/12D3KooWJWTTu2t2yg5bFRH6tjEpfzKwZir5R9JRRjQpgFPXdDfp", - "/dns/boot-cr.gatotech.network/tcp/33120/p2p/12D3KooWGZsa9tSeLQ1VeC996e1YsCPuyRYMipHQuXikPjcKcpVQ", - "/dns/boot-cr.gatotech.network/tcp/35120/wss/p2p/12D3KooWGZsa9tSeLQ1VeC996e1YsCPuyRYMipHQuXikPjcKcpVQ", + "/dns/boot.gatotech.network/tcp/33120/p2p/12D3KooWGZsa9tSeLQ1VeC996e1YsCPuyRYMipHQuXikPjcKcpVQ", + "/dns/boot.gatotech.network/tcp/35120/wss/p2p/12D3KooWGZsa9tSeLQ1VeC996e1YsCPuyRYMipHQuXikPjcKcpVQ", "/dns/collectives-polkadot-bootnode.turboflakes.io/tcp/30605/p2p/12D3KooWPyzM7eX64J4aG8uRfSARakDVtiEtthEM8FUjrLWAg2sC", "/dns/collectives-polkadot-bootnode.turboflakes.io/tcp/30705/wss/p2p/12D3KooWPyzM7eX64J4aG8uRfSARakDVtiEtthEM8FUjrLWAg2sC", "/dns/boot-node.helikon.io/tcp/10230/p2p/12D3KooWS8CBz4P5CBny9aBy2EQUvAExFo9PUVT57X8r3zWMFkXT", diff --git a/cumulus/parachains/chain-specs/collectives-westend.json b/cumulus/parachains/chain-specs/collectives-westend.json index e459c631f8be9df7c5c52993c116f11ef619fefe..8680e3a7671dcb402f7f445eea44baccbe79b00d 100644 --- a/cumulus/parachains/chain-specs/collectives-westend.json +++ b/cumulus/parachains/chain-specs/collectives-westend.json @@ -5,14 +5,16 @@ "bootNodes": [ "/dns/westend-collectives-collator-node-0.parity-testnet.parity.io/tcp/30334/p2p/12D3KooWBMAuyzQu3yAf8YXyoyxsSzSsgoaqAepgnNyQcPaPjPXe", "/dns/westend-collectives-collator-node-1.parity-testnet.parity.io/tcp/30334/p2p/12D3KooWAujYtHbCs4MiDD57JNTntTJnYnikfnaPa7JdnMyAUrHB", + "/dns/westend-collectives-collator-node-0.parity-testnet.parity.io/tcp/30335/ws/p2p/12D3KooWBMAuyzQu3yAf8YXyoyxsSzSsgoaqAepgnNyQcPaPjPXe", + "/dns/westend-collectives-collator-node-1.parity-testnet.parity.io/tcp/30335/ws/p2p/12D3KooWAujYtHbCs4MiDD57JNTntTJnYnikfnaPa7JdnMyAUrHB", "/dns/westend-collectives-collator-0.polkadot.io/tcp/443/wss/p2p/12D3KooWBMAuyzQu3yAf8YXyoyxsSzSsgoaqAepgnNyQcPaPjPXe", "/dns/westend-collectives-collator-1.polkadot.io/tcp/443/wss/p2p/12D3KooWAujYtHbCs4MiDD57JNTntTJnYnikfnaPa7JdnMyAUrHB", "/dns/boot.stake.plus/tcp/38333/p2p/12D3KooWQoVsFCfgu21iu6kdtQsU9T6dPn1wsyLn1U34yPerR6zQ", "/dns/boot.stake.plus/tcp/38334/wss/p2p/12D3KooWQoVsFCfgu21iu6kdtQsU9T6dPn1wsyLn1U34yPerR6zQ", "/dns/boot.metaspan.io/tcp/36072/p2p/12D3KooWEf2QXWq5pAbFJLfbnexA7KYtRRDSPkqTP64n1KtdsdV2", "/dns/boot.metaspan.io/tcp/36076/wss/p2p/12D3KooWEf2QXWq5pAbFJLfbnexA7KYtRRDSPkqTP64n1KtdsdV2", - "/dns/boot-cr.gatotech.network/tcp/33320/p2p/12D3KooWMedtdBGiSn7HLZusHwafXkZAdmWD18ciGQBfS4X1fv9K", - "/dns/boot-cr.gatotech.network/tcp/35320/wss/p2p/12D3KooWMedtdBGiSn7HLZusHwafXkZAdmWD18ciGQBfS4X1fv9K", + "/dns/boot.gatotech.network/tcp/33320/p2p/12D3KooWMedtdBGiSn7HLZusHwafXkZAdmWD18ciGQBfS4X1fv9K", + "/dns/boot.gatotech.network/tcp/35320/wss/p2p/12D3KooWMedtdBGiSn7HLZusHwafXkZAdmWD18ciGQBfS4X1fv9K", "/dns/collectives-westend-bootnode.turboflakes.io/tcp/30600/p2p/12D3KooWAe9CFXp6je3TAPQJE135KRemTLSqEqQBZMFwJontrThZ", "/dns/collectives-westend-bootnode.turboflakes.io/tcp/30700/wss/p2p/12D3KooWAe9CFXp6je3TAPQJE135KRemTLSqEqQBZMFwJontrThZ", "/dns/boot-node.helikon.io/tcp/10260/p2p/12D3KooWMzfnt29VAmrJHQcJU6Vfn4RsMbqPqgyWHqt9VTTAbSrL", diff --git a/cumulus/parachains/chain-specs/contracts-rococo.json b/cumulus/parachains/chain-specs/contracts-rococo.json index 422268a5efdb2f8efc96da27dde92a92b11ac9ab..71783481e5cc7ba962c04701f71fb21dc0e5eee9 100644 --- a/cumulus/parachains/chain-specs/contracts-rococo.json +++ b/cumulus/parachains/chain-specs/contracts-rococo.json @@ -5,6 +5,8 @@ "bootNodes": [ "/dns/rococo-contracts-collator-node-0.parity-testnet.parity.io/tcp/30333/p2p/12D3KooWKg3Rpxcr9oJ8n6khoxpGKWztCZydtUZk2cojHqnfLrpj", "/dns/rococo-contracts-collator-node-1.parity-testnet.parity.io/tcp/30333/p2p/12D3KooWPEXYrz8tHU3nDtPoPw4V7ou5dzMEWSTuUj7vaWiYVAVh", + "/dns/rococo-contracts-collator-node-0.parity-testnet.parity.io/tcp/30335/ws/p2p/12D3KooWKg3Rpxcr9oJ8n6khoxpGKWztCZydtUZk2cojHqnfLrpj", + "/dns/rococo-contracts-collator-node-1.parity-testnet.parity.io/tcp/30335/ws/p2p/12D3KooWPEXYrz8tHU3nDtPoPw4V7ou5dzMEWSTuUj7vaWiYVAVh", "/dns/rococo-contracts-collator-node-0.polkadot.io/tcp/443/wss/p2p/12D3KooWKg3Rpxcr9oJ8n6khoxpGKWztCZydtUZk2cojHqnfLrpj", "/dns/rococo-contracts-collator-node-1.polkadot.io/tcp/443/wss/p2p/12D3KooWPEXYrz8tHU3nDtPoPw4V7ou5dzMEWSTuUj7vaWiYVAVh" ], diff --git a/cumulus/parachains/chain-specs/coretime-kusama.json b/cumulus/parachains/chain-specs/coretime-kusama.json index ebb79e03f045565a915800afee4574491eaa3bc7..4ebaab82e75242f5c50c725cfdbde980c7e24459 100644 --- a/cumulus/parachains/chain-specs/coretime-kusama.json +++ b/cumulus/parachains/chain-specs/coretime-kusama.json @@ -6,7 +6,25 @@ "/dns/kusama-coretime-connect-a-0.polkadot.io/tcp/30334/p2p/12D3KooWR7Biy6nPgQFhk2eYP62pAkcFA6he9RUFURTDh7ewTjpo", "/dns/kusama-coretime-connect-a-1.polkadot.io/tcp/30334/p2p/12D3KooWAGFiMZDF9RxdacrkenzGdo8nhfSe9EXofHc5mHeJ9vGX", "/dns/kusama-coretime-connect-a-0.polkadot.io/tcp/443/wss/p2p/12D3KooWR7Biy6nPgQFhk2eYP62pAkcFA6he9RUFURTDh7ewTjpo", - "/dns/kusama-coretime-connect-a-1.polkadot.io/tcp/443/wss/p2p/12D3KooWAGFiMZDF9RxdacrkenzGdo8nhfSe9EXofHc5mHeJ9vGX" + "/dns/kusama-coretime-connect-a-1.polkadot.io/tcp/443/wss/p2p/12D3KooWAGFiMZDF9RxdacrkenzGdo8nhfSe9EXofHc5mHeJ9vGX", + "/dns/boot.metaspan.io/tcp/33024/p2p/12D3KooWPmwMhG54ixDv2b3sCfYEJ1DWDrjaduBCBwqFFdqvVsmS", + "/dns/boot.metaspan.io/tcp/33026/wss/p2p/12D3KooWPmwMhG54ixDv2b3sCfYEJ1DWDrjaduBCBwqFFdqvVsmS", + "/dns/boot.stake.plus/tcp/47333/p2p/12D3KooWKKKoyywqdkkpZzCzVWt5VXEk5PbS9tUm635L5ohyf8bU", + "/dns/boot.stake.plus/tcp/47334/wss/p2p/12D3KooWKKKoyywqdkkpZzCzVWt5VXEk5PbS9tUm635L5ohyf8bU", + "/dns/coretime-kusama-boot-ng.dwellir.com/tcp/30358/p2p/12D3KooWSoPisbYQTAj79Dtsxx1qAiEFTouvXCfNJ1A3SQWQzuct", + "/dns/coretime-kusama-boot-ng.dwellir.com/tcp/443/wss/p2p/12D3KooWSoPisbYQTAj79Dtsxx1qAiEFTouvXCfNJ1A3SQWQzuct", + "/dns/boot.gatotech.network/tcp/33250/p2p/12D3KooWMpgcWr5pb7em7rWaQV4J6P2kn3YCjCeP1ESMsJPffn1a", + "/dns/boot.gatotech.network/tcp/35250/wss/p2p/12D3KooWMpgcWr5pb7em7rWaQV4J6P2kn3YCjCeP1ESMsJPffn1a", + "/dns/kcore16.rotko.net/tcp/33726/p2p/12D3KooWCyPSkk5cq2eEdw1qHizfa6UT4QggSarCEtcvNXpnod8B", + "/dns/kcore16.rotko.net/tcp/35726/wss/p2p/12D3KooWCyPSkk5cq2eEdw1qHizfa6UT4QggSarCEtcvNXpnod8B", + "/dns/coretime-kusama-bootnode.turboflakes.io/tcp/30660/p2p/12D3KooWHTr9GLvJEnGYKCu3FHC3DwqBiFg9MQUWsjPCP4YH5xyf", + "/dns/coretime-kusama-bootnode.turboflakes.io/tcp/30760/wss/p2p/12D3KooWHTr9GLvJEnGYKCu3FHC3DwqBiFg9MQUWsjPCP4YH5xyf", + "/dns/coretime-kusama.bootnodes.polkadotters.com/tcp/30371/p2p/12D3KooWHy7TAuK6EoVij2tfaeh3KkaEJxhTmumbEom3HfRnSEsp", + "/dns/coretime-kusama.bootnodes.polkadotters.com/tcp/30373/wss/p2p/12D3KooWHy7TAuK6EoVij2tfaeh3KkaEJxhTmumbEom3HfRnSEsp", + "/dns/boot-node.helikon.io/tcp/7420/p2p/12D3KooWK4eKFpYftyuLdBdXrkdJXHKt7KZcNLb92Ufkvo17B9T2", + "/dns/boot-node.helikon.io/tcp/7422/wss/p2p/12D3KooWK4eKFpYftyuLdBdXrkdJXHKt7KZcNLb92Ufkvo17B9T2", + "/dns/coretime-kusama-bootnode.radiumblock.com/tcp/30333/p2p/12D3KooWFzW9AgxNfkVNCepVByS7URDCRDAA5p3XzBLVptqZvWoL", + "/dns/coretime-kusama-bootnode.radiumblock.com/tcp/30336/wss/p2p/12D3KooWFzW9AgxNfkVNCepVByS7URDCRDAA5p3XzBLVptqZvWoL" ], "telemetryEndpoints": null, "protocolId": null, @@ -89,4 +107,4 @@ "childrenDefault": {} } } -} \ No newline at end of file +} diff --git a/cumulus/parachains/chain-specs/coretime-rococo.json b/cumulus/parachains/chain-specs/coretime-rococo.json index 39506095bfe0983c182850084f2602a882ea0caa..082e7dd26a952ccf7d156ea25ad208d9468be71d 100644 --- a/cumulus/parachains/chain-specs/coretime-rococo.json +++ b/cumulus/parachains/chain-specs/coretime-rococo.json @@ -4,7 +4,11 @@ "chainType": "Live", "bootNodes": [ "/dns/rococo-coretime-collator-node-0.polkadot.io/tcp/30333/p2p/12D3KooWHBUH9wGBx1Yq1ZePov9VL3AzxRPv5DTR4KadiCU6VKxy", - "/dns/rococo-coretime-collator-node-1.polkadot.io/tcp/30333/p2p/12D3KooWB3SKxdj6kpwTkdMnHJi6YmadojCzmEqFkeFJjxN812XX" + "/dns/rococo-coretime-collator-node-1.polkadot.io/tcp/30333/p2p/12D3KooWB3SKxdj6kpwTkdMnHJi6YmadojCzmEqFkeFJjxN812XX", + "/dns/rococo-coretime-collator-node-0.polkadot.io/tcp/30335/ws/p2p/12D3KooWHBUH9wGBx1Yq1ZePov9VL3AzxRPv5DTR4KadiCU6VKxy", + "/dns/rococo-coretime-collator-node-1.polkadot.io/tcp/30335/ws/p2p/12D3KooWB3SKxdj6kpwTkdMnHJi6YmadojCzmEqFkeFJjxN812XX", + "/dns/rococo-coretime-collator-node-0.polkadot.io/tcp/443/wss/p2p/12D3KooWHBUH9wGBx1Yq1ZePov9VL3AzxRPv5DTR4KadiCU6VKxy", + "/dns/rococo-coretime-collator-node-1.polkadot.io/tcp/443/wss/p2p/12D3KooWB3SKxdj6kpwTkdMnHJi6YmadojCzmEqFkeFJjxN812XX" ], "telemetryEndpoints": null, "protocolId": null, @@ -67,4 +71,4 @@ "childrenDefault": {} } } -} \ No newline at end of file +} diff --git a/cumulus/parachains/chain-specs/coretime-westend.json b/cumulus/parachains/chain-specs/coretime-westend.json index 8f096fa6a9629dda3891efd00349467baff41bbf..586879b9abc2f043f170f20523132a1c7e02e74d 100644 --- a/cumulus/parachains/chain-specs/coretime-westend.json +++ b/cumulus/parachains/chain-specs/coretime-westend.json @@ -5,11 +5,30 @@ "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", + "/dns/coretime-westend-bootnode.radiumblock.com/tcp/30333/p2p/12D3KooWK7Zj1mCPg6h3eMp7v6akJ1o6AocRr59NLusDwBXQgrhw", + "/dns/coretime-westend-bootnode.radiumblock.com/tcp/30336/wss/p2p/12D3KooWK7Zj1mCPg6h3eMp7v6akJ1o6AocRr59NLusDwBXQgrhw", + "/dns/westend-coretime-collator-node-0.parity-testnet.parity.io/tcp/30335/ws/p2p/12D3KooWP93Dzk8T7GWxyWw9jhLcz8Pksokk3R9vL2eEH337bNkT", + "/dns/westend-coretime-collator-node-1.parity-testnet.parity.io/tcp/30335/ws/p2p/12D3KooWMh2imeAzsZKGQgm2cv6Uoep3GBYtwGfujt1bs5YfVzkH", + "/dns/westend-coretime-collator-node-0.parity-testnet.parity.io/tcp/443/wss/p2p/12D3KooWP93Dzk8T7GWxyWw9jhLcz8Pksokk3R9vL2eEH337bNkT", + "/dns/westend-coretime-collator-node-1.parity-testnet.parity.io/tcp/443/wss/p2p/12D3KooWMh2imeAzsZKGQgm2cv6Uoep3GBYtwGfujt1bs5YfVzkH", "/dns/boot.metaspan.io/tcp/33019/p2p/12D3KooWCa1uNnEZqiqJY9jkKNQxwSLGPeZ5MjWHhjQMGwga9JMM", + "/dns/boot.metaspan.io/tcp/33020/wss/p2p/12D3KooWCa1uNnEZqiqJY9jkKNQxwSLGPeZ5MjWHhjQMGwga9JMM", "/dns/boot-node.helikon.io/tcp/9420/p2p/12D3KooWFBPartM873MNm1AmVK3etUz34cAE9A9rwPztPno2epQ3", "/dns/boot-node.helikon.io/tcp/9422/wss/p2p/12D3KooWFBPartM873MNm1AmVK3etUz34cAE9A9rwPztPno2epQ3", "/dns/coretime-westend-boot-ng.dwellir.com/tcp/443/wss/p2p/12D3KooWHewSFwJueRprNZNfkncdjud9DrGzvP1qfmgPd7VK66gw", - "/dns/coretime-westend-boot-ng.dwellir.com/tcp/30356/p2p/12D3KooWHewSFwJueRprNZNfkncdjud9DrGzvP1qfmgPd7VK66gw" + "/dns/coretime-westend-boot-ng.dwellir.com/tcp/30356/p2p/12D3KooWHewSFwJueRprNZNfkncdjud9DrGzvP1qfmgPd7VK66gw", + "/dns/boot.stake.plus/tcp/45333/p2p/12D3KooWEFQapPJXNyZMt892qXZ8YgDuHWt2vhLeRvny98oUjEto", + "/dns/boot.stake.plus/tcp/45334/wss/p2p/12D3KooWEFQapPJXNyZMt892qXZ8YgDuHWt2vhLeRvny98oUjEto", + "/dns/coretime-westend-bootnode.radiumblock.com/tcp/30333/p2p/12D3KooWK7Zj1mCPg6h3eMp7v6akJ1o6AocRr59NLusDwBXQgrhw", + "/dns/coretime-westend-bootnode.radiumblock.com/tcp/30336/wss/p2p/12D3KooWK7Zj1mCPg6h3eMp7v6akJ1o6AocRr59NLusDwBXQgrhw", + "/dns/ibp-boot-westend-coretime.luckyfriday.io/tcp/443/wss/p2p/12D3KooWBzfzNhvyRVTb9KtNYpkRf26yTRHorBZR2LmYhH5ArCey", + "/dns/ibp-boot-westend-coretime.luckyfriday.io/tcp/30340/p2p/12D3KooWBzfzNhvyRVTb9KtNYpkRf26yTRHorBZR2LmYhH5ArCey", + "/dns/wcore16.rotko.net/tcp/33736/p2p/12D3KooWFmGg7EGzxGDawuJ9EfyEznCrZfMJgGa4eHpMWjcJmg85", + "/dns/wcore16.rotko.net/tcp/35736/wss/p2p/12D3KooWFmGg7EGzxGDawuJ9EfyEznCrZfMJgGa4eHpMWjcJmg85", + "/dns/boot.gatotech.network/tcp/33350/p2p/12D3KooWN6FJDaZvWbtX1pSc6UdHgyF2UZtYxPp3UkXQZa8ko7uS", + "/dns/boot.gatotech.network/tcp/35350/wss/p2p/12D3KooWN6FJDaZvWbtX1pSc6UdHgyF2UZtYxPp3UkXQZa8ko7uS", + "/dns/coretime-westend.bootnodes.polkadotters.com/tcp/30358/wss/p2p/12D3KooWDc9T2vQ8rHvX7hAt9eLWktD9Q89NDTcLm5STkuNbzUGf", + "/dns/coretime-westend.bootnodes.polkadotters.com/tcp/30356/p2p/12D3KooWDc9T2vQ8rHvX7hAt9eLWktD9Q89NDTcLm5STkuNbzUGf" ], "telemetryEndpoints": null, "protocolId": null, diff --git a/cumulus/parachains/chain-specs/people-kusama.json b/cumulus/parachains/chain-specs/people-kusama.json index 7a55435d12e895f1544dd338b2ec168085569f9a..518a7be751509aeeb3973f654b371e3498355949 100644 --- a/cumulus/parachains/chain-specs/people-kusama.json +++ b/cumulus/parachains/chain-specs/people-kusama.json @@ -3,10 +3,10 @@ "id": "people-kusama", "chainType": "Live", "bootNodes": [ - "/dns/kusama-people-connect-0.kusama.io/tcp/30334/p2p/12D3KooWQaqG5TNmDfRWrtH7tMsN7YeqwVkSfoZT4GkemSzezNi1", - "/dns/kusama-people-connect-1.kusama.io/tcp/30334/p2p/12D3KooWKhYoQH9LdSyvY3SVZY9gFf6ZV1bFh6317TRehUP3r5fm", - "/dns/kusama-people-connect-0.kusama.io/tcp/443/wss/p2p/12D3KooWQaqG5TNmDfRWrtH7tMsN7YeqwVkSfoZT4GkemSzezNi1", - "/dns/kusama-people-connect-1.kusama.io/tcp/443/wss/p2p/12D3KooWKhYoQH9LdSyvY3SVZY9gFf6ZV1bFh6317TRehUP3r5fm" + "/dns/kusama-people-connect-0.polkadot.io/tcp/30334/p2p/12D3KooWQaqG5TNmDfRWrtH7tMsN7YeqwVkSfoZT4GkemSzezNi1", + "/dns/kusama-people-connect-1.polkadot.io/tcp/30334/p2p/12D3KooWKhYoQH9LdSyvY3SVZY9gFf6ZV1bFh6317TRehUP3r5fm", + "/dns/kusama-people-connect-0.polkadot.io/tcp/443/wss/p2p/12D3KooWQaqG5TNmDfRWrtH7tMsN7YeqwVkSfoZT4GkemSzezNi1", + "/dns/kusama-people-connect-1.polkadot.io/tcp/443/wss/p2p/12D3KooWKhYoQH9LdSyvY3SVZY9gFf6ZV1bFh6317TRehUP3r5fm" ], "telemetryEndpoints": null, "protocolId": null, @@ -88,9 +88,6388 @@ "0xd5e1a2fa16732ce6906189438c0a82c64e7b9012096b41c4eb3aaf947f6ea429": "0x0000", "0xe38f185207498abb5c213d0fb059b3d84e7b9012096b41c4eb3aaf947f6ea429": "0x0100", "0xe38f185207498abb5c213d0fb059b3d86323ae84c43568be0d1394d5d0d522c4": "0x03000000", - "0xf0c365c3cf59d671eb72da0e7a4113c44e7b9012096b41c4eb3aaf947f6ea429": "0x0000" + "0xf0c365c3cf59d671eb72da0e7a4113c44e7b9012096b41c4eb3aaf947f6ea429": "0x0000", + "0x2aeddc77fe58c98d50bd37f1b90840f91f7f3f3eb1c2a69978da998d19f74ec5": "0x1801c674e09ef751ea2fb6f9eaa6e505f5f90e0585b1f06d9d774449c90c75266b3c00902f500900000000000000000000000000000000000000018ef5289702f6b8c7d22b3562ffda7d5593a5f6414226925e72097efbf9b2572000c8e6bc1704000000000000000000000000000000000000014ce421370cf0257d869618ec25c324ed4c6c7f65289297a3c134332c212e350b0010a5d4e80000000000000000000000000000000000000001a6915d6fb30cd30367f23194c68842a6018f565c773ea0c544eb2a62597b1b340010a5d4e80000000000000000000000000000000000000001b6a0389596b472840969a9088eb5852fa03a5b5dd7a3c2fc7275d7c05563a90000902f500900000000000000000000000000000000000000016c0197856b35c7f631f5aa8d9cfd83f7e75202b0d821e67d2f344e4e4b5fc10f00902f500900000000000000000000000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2001a999956b512c074747399c0fbcabd1076ce5a68ccc3f21da73f2b8747c87a71aec14a792bd55050a44cbe58c7196f": "0xfc5d04e7ff3965c8285a2c23aa573117deeed886bbe5e3be0974f1cf0a2ff216073039f09f9a80", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf20027994ba957c6ec7138a4649f05b9bd80c546b7e44391d7f7832d8cd5456f7ca1a76a73e73807544a4184bb59ce6048": "0x5270ec35ba01254d8bff046a1a58f16d3ae615c235efd6e99a35f233b2d9df2c0cf09fa69020534852494d50", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf20036af6dd10e8692493044fc37feec1412c0e71c578bac3ac4c85fb1d9f0645451aa4503782c3f0f3260486b8d3e6123": "0x12c0e71d326f83f4e6089448e147fdab51b0b7398a7d0cc9a88b0571432e7310033636", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf20068043e94d92496a755395960c92c01727dba627f34c210eba395fc7f60d28b3a58c5dbd6b63fb4f9788ee764b2702a": "0x443c76dcde19df9387486ded7845c6d85ec2a4c17f38f8b1e7a0a14de7968d7d0231", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf200e420fe7fad43e6112bdc886600d40d5da7c5df13916304befdcf8c879f5a35c7d65539711eb5cac00a9d5176b36b58": "0x5a9e357de87525b67cf9ed1d0f06a15a6363665ca1c9f43ff527c87c0945597c0230", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2014247ce055f7db9af9631b382a7370a541145a8a9d8b066ecd0c7dff89c9d397a18e2e0e9d65a36cb2c1295c768e376": "0x925000bd5b83d502f56c49f2a91e3532af9f919d6eb52d750b72539c6b62d45b0544534b31", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2014446e470b0ae39ab405f9d1d71337112c0e71cba3dffa43d603a1637f373c134f4eb3b0ca902a937e218cf992b4f1b": "0x12c0e71d326f83f4e6089448e147fdab51b0b7398a7d0cc9a88b0571432e7310033835", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2017185f0a21043525d99a5d934b4322c5883a7c739d00f1d125475cda89e7ceff0f406badf56a7c1270c16f850f62cd5": "0x89abf449cfb7d9b862b775abe556bccbe647820fd4d7a50b63872b657c96506f033031", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2017d70cc4f902c5ec93f5a80574ca9bc6621dd4e5cdd0ba737c572710c13df35b316d39ecd12c1ae1320bd6db069a07a": "0xc5c184f0565e2192d6aedae584ee736cef875f0e1c558ee3ede26869acd0b4d60945696e737465696e", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf20183848bff64fb39e82b8f09455849c2a24f97e96ae4e213d8eae1f35213c986e0ec03126812b24cc1bdc99484430440": "0xfc5d04e7ff3965c8285a2c23aa573117deeed886bbe5e3be0974f1cf0a2ff21606456d696c79", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf201a590f51715a01416d8af71b8911f72f2395f3e80b47fe6ce9eaf63553371c59c73b403bdc28862c86ab1040e62226a": "0x68f8bfef657c69a5c34721cbaa618ae9eb2108566f9a2606cf5055578e0c251106706f6f6c31", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf201cde46327cce392512ad52e8d16c8ad7a3a98a1dcff1349491c4de950bac2427069580f45cabcf5b57e645d0df2882b": "0x4eed7cf3f4f6560d58db4eb78bd24b655bbd1d7a5c6b454e77c8dc5e2721a54d12444941424c4f20434f4e54524f4c4c4552", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf201cf563ada9e37a12b43c23c5c0a1d5ec8c3dee0510e7e05a5ac3e8ab4e13befdeb0366408b0c47c5a41c887d7dfdd58": "0xaa220871834d1f214169691dfd97c70823d90d192b246378dc01a59daafffe0d0e48797065727370686572652d31", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf201df75237d9c28749ff88c3629f478abb8dd36cb05189e12ff133ef1c0f3ddf97d1319dc737e4acbd882d17e143bb083": "0xc0b881e2db47fb95982cd5c364b87e6cdf5a5c8a336d980156623b53815c597b033037", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf201f67bed5ee86b1cc1704c54f75094ec587fc2461b55e47619ef522b4bd986f71f7adfd207166e6dd2ba381117a2dd08": "0x948223bb2e7bcc8a55be248add34b625c1c0826c58fe037fa5c8e4591440dc59033032", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2020a67feecfc1baf4b326830fcee99ba800bea28742b7e03bf213fd6cbd84e862ccdc18e30b94635f5778a8103133f36": "0x6aa7f16d0ce7a6288dd1d2f1779fafb18d4c60ee78e89ab3dd3bc0979aad386e0232", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2021891a9f30fc074325596c84c3098be702ffebbe8d46bc7b2d33457e61ee616e16c56d726244a6ee549a25723459873": "0x9c7c545141ea2dd84fe5ef7d567ea450f59967e7afa68e5f1ff7f7c46db19627033636", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2021bc60d6ce58079c69164e9cbde46ae56c33c3e6261199d162ed7e756297752416cc7f7dc0eec30460a12a0a7e0c577": "0xc229d8ccc5e5650d17760ce2b7c42bdae5f6afc6e8bab249ec77f3f779ee5a6512353a206e6f64616d61746963732e636f6d", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2023a20efb3ac4201d658271e83019ff01c761954d8265833c4b21c7296a314229af2391b34fc090aa76a817b2e79836a": "0x18cf1686419c41dc5d3e76d373e3176c32c6d23c755fe1fc357f9c755ffc00190233", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf20249f6186526b3c5a73b2550a4f77e28305b1665aadfdadf6d13f6c8eb36db7e3868ba648e86bdb7d60f23677ea6b337": "0xaed98e15e3ed392e38654215c3d1fa8143de53460386b60139fbb45c036c1b430653462d3233", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf202bd65d7890fbc23149d026366a2cdb712c0e71d208c668db313147edb94aa31af86ca4e55d4900fed5eda638862b803": "0x12c0e71d326f83f4e6089448e147fdab51b0b7398a7d0cc9a88b0571432e7310033133", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf202c366188ecd4b59e0e9ff5323286c19e212871311a823c9537b3f70adf0a9697c7286c84fdefe5603bb2fc49b0a7b67": "0x187c76f60b8e91032091aacb1ec79764af51e796a0c962bd2f2e766e9e5ade450854415241444f58", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf202c4c9771014895723e5f0e7e3b67499c2bf131a9bc49208383fce6b0ebd78517ff563ff812f146c441d917dbe726c4d": "0x584d715bcb7a2d3b6a3120891dba91b19b12df42cd50f1c76103e2581d5b42740767677770657a", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf202d3730801109c284b64f4c750dd62b9e8fc1e37b0b57aae49b99fb66be1cd0454d275d34a1c031ae4b796fa30d38736": "0xc87dd7c321ad3dca39e53d05541bf9d17306d681ab556029b0f172156e12b6030a434152474f4b534d32", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf202d86f32d2aa798639cfad1f0a1327a9ad17c83beb46308e21cb6fb45b9587a826addb8c001e01bc2280847982af1b77": "0x600e047c97181ac8d0b9d5a6372f6018f556d68b2b4cdb529d87da365f718d4006f09f92b031", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf202d88bc643c0481680c7d501c743c722be0bc39e129f4ecfac3d20c50d78472dca69f693150064093df5edb3a0caf14b": "0x3cf3f47f611c9dd952bd9007a85b0d84383f91e2f25edd0f13d6be20b5805110033031", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf202e7e87a05e6e3d188d4aa12e16595fb080bd036530545e5e07ad813a408fa757bdd643e76b9d1171417d7eff0d7fe4b": "0x0a7ac5be69a8243f8880d5fd015b2e8f8f30ce6c7162f8bcb5ad1a1fa4246d32054d617263", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf202f1ff1a76fbd652a072b1553bee7ef332ef9a68234eec37684bf683d6e07e2deaf52a336ad7dd7e124041baeee37368": "0x9ce84f6cd845ac3fb2a009aae8e99b1a2fb64aa3e7ce1c7867f3ab2db0c9bc00105f5f5f6c656469727461626f726573", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf203025c67a37f9de0530e46911b31a55b9801988b622814386aa36c7aeb697cc35596ede2bcc7e3c7f7c83d99192c611e": "0x56d629a2c80762d412fad9c15d8cc973b463f600895170d43a10ca504b4f454e16205b31335d20542e4d452f4b5553414d415f424f54", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf203371878c11a0f29fb7eb85d26e341d5e4f861ee16e48158f3a84e6e04f1959495fa8b39f13b39c2d3a9a464151f595e": "0x844152eccf08725bea8ce898d6fc5362ff2d0bc9dfc21ed15fd138438d1606220c4b436f6e74726f6c6c6572", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf20386428efa585a36020d76528b28c3458886a23f6aa185a4d262ade722584c6f1e384ce10b269bfb898abf8785cd934a": "0xf6b21d624832094b03aa672e016462a020e217cc67b1434785b99114a2b4fa5a04763039", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2038da5dd2caf09bf420b4f1d62838b37c282b526ff533bee49db3c9c7ecba02b951f63f8442cc33443a78679d5246829": "0xce5c65fecd7bb733ee636a381fa9dd916f8cca91e2e403c8aea2f7ed32b31d680e424c41434b4d4952524f523234", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf203a89a47bc0b8695d2a696b017df9249663b801c02f2b76565f5b60d817e7dd805babdc276b53d20e19cebd199c88555": "0xa6805c6dc7757cea227e11839257d4e24ad39520621e99e6016ee0e1907c3315033032", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf203adecd29d62220c01af1fe296ff62c7eaeb9d2bee9133ac09633b0361b04567f3997d6aa139a401c12f929be161d9f6": "0x548dcb6c3aabe041e7f7ee65af37818dc7ff1ff1a4300008100322c39e9c610b07424159414b41", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf203d084fa8c88a7030eb111d51f9e56f086929ec01fdfdecf2c5ad0c4f9b537e65084f053980fa1215fb9377dc325f52d": "0xe8b2603f6baee5bc32a9b9e4eee9168499fa553d35edb56aef0035ff7e1f165e0a506f6f6c20f09f9a80", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf203db2032eab02e544102e8a26522b190e0fe63b7c5032e2437b3f8327e95b07eae600a8ad4f31e17db0f80a3208c4728": "0xfc659bba6d3985002708101d9c2aea9155bd520c105688751281cb40e4d37163033031", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2044f6c8244ce36a76ad70843294f01cf26eb2cbbeb40e98cf9d5f39918fe54290600520ccfc9e519efb5779ddf48225f": "0xce5c65fecd7bb733ee636a381fa9dd916f8cca91e2e403c8aea2f7ed32b31d680d424c41434b4d4952524f5235", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2048e9d4e54980e7e80db4c46b84264f2ea4cf3795941a47d46c2b433ee328d7d2a71c85007251569a6e1fa5535af173d": "0x548dcb6c3aabe041e7f7ee65af37818dc7ff1ff1a4300008100322c39e9c610b074b415a414b49", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf204a1456c707e805462a0f595c16a950ab0b7458638e3862d435924db213a27b64b5029bb2f06f68bd337b1c3de43fe44": "0x9c7c545141ea2dd84fe5ef7d567ea450f59967e7afa68e5f1ff7f7c46db19627033738", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2057032750a00050f18d9976d6090d84860384fabe173278be399e99aaafc7d5b3eb2547af81fbc8039eb6fc49ae008bb": "0x0456840228e994122a2750c966571ca20d2456db20a7cb84603ed8e2d550377604303031", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2058830e2c4e4dbe31045ce28fc980a8c3c1cdb7f10555d9e080e83ac20acbb4880b32d3d30319f055e37652c7ef3d36f": "0x12d9c0035dd422388e6d346f61df3d9f3667f8ab761c8c57120dd61917976e10032d42", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf205b2dc427f2aecabe11a2ceca1f7a6349c2df8fb28c6749d31d1716854ef3548aff85aafef3175c5e49030715c00fc25": "0x8c8305ff8478e6309325ebbfb81e8c1883d39e65d2ef84f88e4a428615c4927704313438", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2062b0a5a8bc99462cc0bf8fcf90203cba830e5f0091c9f1c5da8a2a9a1a7a0de5802c6bdd3d9e23175d8c116ef226251": "0xd60cf655685824e9966b0a10c01dc8b17b37e24944fdd760e4dd73ff1dd4ac140574726573", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf206574a0ef09abd6ead4f5761035820cbf64689da7688eec693a364879994be8568da0f7ff5223c391b6b58626f827527": "0x0a71c6a0fbf9b63ac089c5395bdea4917a84aabb3475d4454147c4d24ce1013a05706f6f6c", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf20674e3388e2e1aa4aaa342a8355ff3662a4f829cfd9c12a01da70549643e5bade2829684c101fe7c1362176c884a3719": "0x8433eae795936e63871cbcf0410517d1dad4755f2da4a6d88c1cc1c589b8e86f14535452415742455252592d5354414b494e4732", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2069112c1c85b4d5d7a1a2e5e98b946798e21a74a8d65c99c228e22e79b3e016bab0eb656a5235af8132c2a9a818c7a2c": "0xce5c65fecd7bb733ee636a381fa9dd916f8cca91e2e403c8aea2f7ed32b31d680e424c41434b4d4952524f523439", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf206e8846cf7d041c8a528c5def8819ecfff07f170fb1e51a81ed96a4ca36d82decd18c5aefabae24a03d36ec5f8ffb257": "0x1ea86f3c82538c486a25d8abca26760e57e76a01212419c7f1c8b510121fca73042d5242", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf206f8e4b397c44dc3b1b19dd0dc7962d84729298bb2a53d0e5974d34d14932af4d4905334d5f9a57d7931ed1eb04eae67": "0x4c4769cc1bf4774f19c7433e31a5b8cb686944cdd758e193d264410d4918b1200232", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf20717ea76d2755ba7508819bbb7aed8bb12c0e71d0d3a5ede1ed512ea065c3970ff43788f057c99ffa3afe8ede608da0e": "0x12c0e71d326f83f4e6089448e147fdab51b0b7398a7d0cc9a88b0571432e7310033130", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2071d474a3a0dd340668c44dfa1a3b906a63f88c1fbb368cfd13ca5e7a68e16da2e80b94fb382948eea95616685598235": "0x22fff76bb4a0a5d66cff0392dbc083abbac3b3046f6fcc328abf0ddd16ca08370232", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf20730e29b5c9c55b9ad22e208fbaa9c8170d4121446293f928e59d4f8a5eea096ebe1c2538002fcbf7b7845dd2e19ee6d": "0x7a54e6a55c0453407909789a06c3ee6719f8735ac370d6f17dc342717fd76819033035", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf20743b925eb1b48c3154a37a00254f8c5e88efbf462925faaafc04b00555e946a843a6a018de2e47cfca41b0804a9f128": "0xaa2b3e0a8702aebcb83d552838a17902b2403b0f16c4e52a4514fe02df532e3c0c303320f09f908f2052414d", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf207871568136038f8f6fe7b31199f4eda8a74d6464340d1e60feb30c35ef63b8e48737f225e6343b1875e352756d0160f": "0xa8a2e5461f346cf0c23d1ca613437432a160525b6487dbb718afa51439d48d040d56616c696461746f722d3031", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf207ac57824770a9bdb269d1db618967f46d6f646c70792f6e6f706c73004d000000000000000000000000000000000000": "0xd6aadb9a7f66a45224f6f83011f854c0b5758c626b213f97cbffded94830507d05f09f909c", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf208a202c55ad5022a2add3835e2998492fa6c823ba7c33395d2f298934f304b44af030504cf1af0f1a3f29c78442e0750": "0xaed98e15e3ed392e38654215c3d1fa8143de53460386b60139fbb45c036c1b430653462d3130", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf208b030a3e4385a9eaa71ae95cf3b4df5e50c1ab151d60148984c5494bdd23ddd7e5520a8b4873de12ca413a6f37bc3cd": "0x90c7f4e84347dc6e4e176f9156b2347378faa9b538a857b404cee3e3417063050a5374616b696e672032", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf208b8c566be5926cd348648d055d052cd07e8861ce764f34220c198710b60b72f8c59c617fef101bdba96bf6f598016d3": "0x201f968f24fc0df93fe98dab905ff103d00a9a232329bfe78c22663dbe60a12d04303430", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf208cef132f46d5bf78fe7bfdf6e7cd9405db58282171c8d2c73678f13f3c61579902ea4572ae9e9158046e8e820bf4d82": "0xc0b881e2db47fb95982cd5c364b87e6cdf5a5c8a336d980156623b53815c597b04423039", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf208ec1901955f6a8ba9fcf40920b62ccf48f5c152ca97d46d67467f3b6c7e2fff11e1f95abc0ea7298255c026ff65d92b": "0xd4e6d6256f56677bcdbc0543f1a2c40aa82497b33af1748fc10113b1e2a1b46011f09f8d80204b534d20303320f09f8d80", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf209163a5f2972e9c2ad31a6a386bce8bf5c9d4bed4df1d87e33b03c63aef108b00b23253cc0cda93b528ea9f95c33f522": "0xe643e4515fa656d6d830c088ec251ab76ba6cebd85be7e7d6362eafff654e2220f534f4e59412d5354414b494e4732", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2096e0db1cbfa92374241919548f80bb3d6945be0cef12df3e9d25d4bfed7c4f6fbe980487ccdcf13891998454d4c7d3c": "0x5202845d849d9eb6a7e5a414492a86d205be4a374ede34e98fc2440de4809a3e033031", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf209acd96884a49ebbd9fadaacd9136d796c8bfefb8ac4b47696a47ba939ccc48415c02fe947afd32437190cf5a3644002": "0x52e73898bf4601f9c9a7fa052de0cc313b159dd368d458f4cb0341eedcd6d81804763036", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf209c5e5eddd7408e51c125433483eb9177e437bd1edbcf02649eb8a4103c8668f5903ceffd5b2a4215c0d211affbe5f6c": "0xf6b21d624832094b03aa672e016462a020e217cc67b1434785b99114a2b4fa5a04763238", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf209da7bc8ea2f3eacbccb7a616c4bb60db4adbb4e711987eb53c39b12dfd79435736f1317a869db5f50d5a913e4045550": "0x46b4eca928ede3e8075d86e25581d46adf3eff915646eab110d13e2fbd947b5e107765623376616c696461746f722d32", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf209e0feacd17dc8258f8d124326e8e79ed047791087bdd0caca708a478371eb8dfc056a36028504ea64f4cc43713fa918": "0xc229d8ccc5e5650d17760ce2b7c42bdae5f6afc6e8bab249ec77f3f779ee5a651331303a206e6f64616d61746963732e636f6d", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf209e61fbe0b11a8469a72a9bcc3a79154e2623f940ce24961b8e483b3b00c94e84fd32a5f13a67a09ef5a19d28af59435": "0xca42f0b5c7957571706f29d2828291b148b4b162100ddcac72c507fd8ab69b2e073033f09f90a6", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf209ed2ad028c5f938dede2fc8cc8069b2565e801907aa5ceae0511572155aaaed09c8ecc03b7dca4790609ffe26bdba0c": "0x8c8305ff8478e6309325ebbfb81e8c1883d39e65d2ef84f88e4a428615c4927704313339", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf20a0833d62ff297dc2423ea20aa9e2d7d9e62629f1f1b6e219c95d80577ba4215ffeee870b4c6f6672e2191bbc3a4b750": "0x3674aa73951219dbd27b3e3fc5847b806c68c1de38fd4f22f9493a461c80e903124f5247414e4943204d494c4420f09f8cb1", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf20a08568a637562705bc4fecb1d33c4f012c0e71cc0578209ed2ff07931f254566de682bd7407f07913ca1c4a30e7a633": "0x12c0e71d326f83f4e6089448e147fdab51b0b7398a7d0cc9a88b0571432e7310033831", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf20a50a0c42e458db074cd89e3140a971b8e9871679378b82009f51f30eec29bcddfe60c4f7d22c24f74883b47d935a565": "0x2ce1929ab903f695bdeeeb79a588774d71468362129136f1b7f7b31a32958f9810494e434841494e574f524b53203030", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf20a73e46ec9da49f29fea3b464d77109b12c0e71cd31ae09c2af44df1c49f572234348e1637127de385daad38c2bd3632": "0x12c0e71d326f83f4e6089448e147fdab51b0b7398a7d0cc9a88b0571432e7310033332", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf20adb7651bea6d4d81c019977882d63f75213e3c8881ed30ead22d177f5c25c4cb8bf46cf2d04a8ce55ddbc06118a9516": "0xe4a66ee66171e3238670377bc9ffbd7cb4bda47baf25e6ed80c2070942ee3f721070617468726f636b6e6574776f726b", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf20ae46c66639fbf674157c4a9171cafa778905d56c02810911e1ebaf201ac246eff919f4e71a5bfa5b29eaf6819663944": "0x48ca001326b583070e370be3bc6680d09cad47649584a5c992bd388c693b9a54033232", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf20b0f22c210fbf446d674b51a6e05f9110daa7f988ac07541286ffd6ac83affa9d4f0e119c04eba5f1fb74e51719867c9": "0x6610a5024c2a5db3d02056d4344d120ec7be283100d71a6715f09275167e4f38033031", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf20b432ff63b59bf96f318de5ffc7832c1a00b6ded2d4d0101146c5f76452f6900532c39cfb36b911e38776c782cfcef59": "0x9c7c545141ea2dd84fe5ef7d567ea450f59967e7afa68e5f1ff7f7c46db19627033537", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf20b90dc8cfc3e699a2611c7437eecd07cdeb5320179cd1dab5b17c203384b7ec2fa9e73577a82954f9c526ad535552422": "0x5247e73b8ad3c36bb4e01c93a9bd6a6048afce1e2a45863ea5fe99778b530b61033031", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf20bb0cfec7089d8b9e17ca192fae0a4ee0a9e884e29b1c07ae4918e17e7ec48bbfe9622cd9badab882d14064c8d672b3d": "0x6a0051ef580a2b9dd19a368b82ec20f9a605b0207f2e8d364e6c985b5b2ba8710232", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf20bf5e86edbfecf7c34436cdd4fae89db424ecaa1e5d069bb89c743c3ddb44d9cb023aff0ad78e3c502bd39b0abbf7715": "0x7a54e6a55c0453407909789a06c3ee6719f8735ac370d6f17dc342717fd768191041737365744855422d4b534d2d3031", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf20c07ed359e65249593e99ee8fa2bfe3e2d2a9ef6dff17530bba04671deccf9754c7cdf0b079e0ac825a43c5c0e274620": "0x90c7f4e84347dc6e4e176f9156b2347378faa9b538a857b404cee3e3417063050a5374616b696e672031", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf20c0ab7f0e067fc048e2d09c4b539c63d866f40b96e6ca6405ed0c44747726b3972ca4773aac5273dcc25ffbb5003b075": "0xc4516751df2e5803bac3bf9cf7b6d55cf4acbd76f861ad0a2a2b71b7a5ed805407f09f98883134", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf20c1af3384ddbe14bb73ed1432e7b2ac1bc97eeb4ec96658e0ec1d15b07524376ed7e1444bd35f3c4fc21526176f4c979": "0x749ddc93a65dfec3af27cc7478212cb7d4b0c0357fef35a0163966ab5333b75707636172626f6e", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf20c5277389a76828673fd42ec57c47c66a26c112ec96a277c48e91f46d5385fbdfee248c6ee7c3a66a9f8e640b31922a8": "0x8c8305ff8478e6309325ebbfb81e8c1883d39e65d2ef84f88e4a428615c492770574656368", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf20c598f045d1f5b180f40f1d98146be72e04176c772d8e5b3758231c8155b2265e9522e5047b15f388a23cc707767923e": "0x9a2cb674ea2f4866664769a1663fd6aa321d9cfb89b67c402c881891700c0f571046726965647269636820486179656b", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf20c85d3369694863e11c43a04c68b3f96d34e07fff5d2c51bf316d91599d98e2e1ecc8bab38f57caa40a4206967dc8ac0": "0x008d8404893c7b4b80f397605cc96e61fec3c89676c8c2794a2a7d281d678b1a074b554b414249", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf20caa6f5c0b928e524b323b57e1aa3469f16a6e2b7183e7a10f701d357d224e9ca87bfbc49a663fbfa27426a8f5e9b1d7": "0x38ae9a751c06cfc8b4bfb06f4d0b8d88df80fc88317415ad6f1b9bb6ca11494104303136", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf20d00278bd6531560df393cb9de7b02fc12c0e71d36450dd3d651da12ea3ff51a9f306650744f4c164ceaa7b2cc084546": "0x12c0e71d326f83f4e6089448e147fdab51b0b7398a7d0cc9a88b0571432e7310033539", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf20d26eef7e0e73557aefe05256116b0761a7df77359ce352ba50059ec6e2635d7964a50cae9012e4a737f5e82c353aa0d": "0x8c8305ff8478e6309325ebbfb81e8c1883d39e65d2ef84f88e4a428615c4927704313331", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf20d461b6a1731b017b92cfee609c6e3b152e32efcfa98867081b563878242febcb31531cf4648cc496bbf851f39f31f6d": "0xf00168a3d082a8ccf93945b1f173fdaecc1ce76fc09bbde18423640194be7212073036f09f9a80", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf20d70449b3466fda44840841f97768623522159de5d549c217b26deed24558c4ea6e33ab8daf73f5410665acc1d5f845c": "0x1aaf37daa4afffeb0d84c47f52330d8293ea648e1bba5fe0e35355057e63c1670f73656c6265725f636f6e74726f6c", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf20db0fa311944ee03f68cb14e3a4773a580ec6fb1ab57be7d791fa9bb7e711b2736c6422e0b66932b54f3e95f614b4b2d": "0x9c7c545141ea2dd84fe5ef7d567ea450f59967e7afa68e5f1ff7f7c46db19627033136", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf20dd32323836d31919cb4cee6850e02135c97523bb1c1be25aad6bfb7a52d7e1a55fab08a78c2099daf42951adf713353": "0xaed98e15e3ed392e38654215c3d1fa8143de53460386b60139fbb45c036c1b430653462d3339", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf20dd6a0fe0a25f539d978c7fefe2bdcbd74a0fe5948a9e16263adeced4ac5592a4e15ec77d223be684d9229ab3659fc70": "0xce5c65fecd7bb733ee636a381fa9dd916f8cca91e2e403c8aea2f7ed32b31d680e424c41434b4d4952524f523437", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf20e075b69e5ae02a46271d1b1294e5bf912c0e71ce93b3b5ce42fde862b4d609631d600ee1cc3f3717268e7b9b3e1467a": "0x12c0e71d326f83f4e6089448e147fdab51b0b7398a7d0cc9a88b0571432e7310033834", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf20e0ca2b2ed572a3b489c91f83993260940ad8a6c92b5be3305a78ec0ec67cc600e791fb2769b9cae21cad79c40f7c92c": "0x9c7c545141ea2dd84fe5ef7d567ea450f59967e7afa68e5f1ff7f7c46db19627033435", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf20e416e5b5a385055e1f692da0cf0f8b3d21f6f288702a2646b5cec6d0cb5f77d48638af67cf77d6dee823e2959ccb967": "0x9c7c545141ea2dd84fe5ef7d567ea450f59967e7afa68e5f1ff7f7c46db19627033439", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf20e495e95537e75e686c3cb9a975a87326e32e6b0a35b369455c50fcaf7153945fd6d92b850a593ea33b5c3b51d7e5a2a": "0x8c8305ff8478e6309325ebbfb81e8c1883d39e65d2ef84f88e4a428615c4927704313335", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf20ebce498b8ea6cb844b59453ebbccdff041eda8cf4ea9ed59862c6f5ad3a51e7ef62eff19b629cb241a10d5fd7f96d22": "0xaed98e15e3ed392e38654215c3d1fa8143de53460386b60139fbb45c036c1b430653462d3133", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf20ecda764c9be13ae791ffe4aa9702d1744d50e5b2db8b483e5731d39c1e71f33d6ab32318c144f5dc41e57d1d21ee779": "0x1c6d8b40be9990c19e993d238e6e3613cfc6cbc51979d5fa61dd6ea259385609086e702d726f6f74", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf20ef92e517426f8737223efd744536afb1ad58fdac86f68d5a3a9a8e07163426d717ef0426d3e03604ae3bf4ed481a923": "0x48ca001326b583070e370be3bc6680d09cad47649584a5c992bd388c693b9a54033038", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2103babf10c477bacfddf27dc23fb5be6bf7c2411b8362b3beedd04428317c3eeb3639379c64eaa724d44eb77b15cc85b": "0x6a2bd95c44c00bcad3fef2f7226ad90b8b93c3c1b9679236d5abfdb39c89584408636f756e63696c", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf210769b6d502a8f0b2b26cf9be30f66e58e57071fe8c6591960d214a1100419ff2e2e92d4989a99646354df48ef91e664": "0x1e015452870e49b4e4c3e054556b19683e8895586bfa58638a74a5782ab4f71209414c4558415f3031", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2108c2734b36b8888f4a19edc8b64f422a6ef8a1f259f84d8e435d119d7c0b8f4d91c7ef95bef739c81ff66a2cad2cc45": "0xaa18b3cf52cb27fd19d5b80fe7982ff955e0d5124dae26ac360056f401dad84607416368696d31", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf210cd9b5224b78be4929deac8776e2ba46817038f23e3b1e7d91f641929205495b7be633fc2247d0bcc5a6f9709a8f82d": "0xd6aadb9a7f66a45224f6f83011f854c0b5758c626b213f97cbffded94830507d05f09f909c", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf210e1d1720cc5799c635647b68b396e943f25ee912fc878195d9904d4474bf1ffa58d1570bdc39af3f8fdd88829b15655": "0xaa7880fe9ca2bbf331fc13e40525dcb0da661f143df506fed76d8ada3db8f55104303032", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf21160f447eeed0c082d88e23f3c2553b1c68dc89f99b0b46b9e3a10f9b115283e27b7f6fd591a9f6cf53fbaf1b1a4685f": "0xc4516751df2e5803bac3bf9cf7b6d55cf4acbd76f861ad0a2a2b71b7a5ed805407f09f98883130", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2116fee05fc8e4ddbb6958227b9c8ea44d5f8960e7af211c990e0d092ba6038772482a74e9dc91e5696c84fd079992ffe": "0x5a9e357de87525b67cf9ed1d0f06a15a6363665ca1c9f43ff527c87c0945597c0232", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf21185c189300056dde7eb239cf182b8ed223b081a343ef66eeb872caa2ceac54d75566c279627592362d2cd162bd21831": "0x2cba024614ea8ccd1ebf7a634f30b38d65c082be6aaa92551b9c3b4d1f15ae6e0a4368696c746570696e", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf211af50e830a384d6cddff2c8765f5e6abcbb3c28aa69648bcb3eb9b493c06256abecc144fca20c90144dc4dc920bff76": "0x7a895955042cb3fe863f3564e7b30e9130e37b6d905be11c0cf91064de1cd83a0530322d43", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf211e4c6afb785c7c325f25d434d4c547340e30e1462871a4a8a38dbf705b96b986d699b62ed53e890b8f42544e3bd7b38": "0x1c7376c9f2afef25e542556d2af805dfa691a414efb9e0fc9a8e33f625294f670232", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf211ece78f336d20c9df63aff306176237820f781b839533ebb3f3606d6bdb794136b3da9a8eab8ddb2f4b2c29cefb515a": "0x7add073714bbf9da81fe49db63778e918217e56c55e4f81f68e7d2e7d0e59d0e085448554e444552", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf21205a8f89ba76fa0d8e59d76f99e1366284e0442b44363d362b1194b107f46ec28e76932170fdbbf8077dbe87aa26001": "0x284eb76f4116f4b75a718fd1a374cc5b6e02fc18f37e02deb3054e57539c5328064672656e7a", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf21210f72f44ff8832d4eec2d9ec420b5354ba6fba820d02b4f0def9908ed99ed988d415d9b7c272a1d9394fd670ea8950": "0xf6b21d624832094b03aa672e016462a020e217cc67b1434785b99114a2b4fa5a04763136", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf21239ddf641b9fe0e1c4a22ce2f5a455a3c0bb72774583cae164f6f184ea05f95f90c8fa34203b9b2c5a2c1b6beb90a5f": "0x8429c11f2ff4fc700087c7fdad402d6e97c6df5e73988c3a36c2b6fde7daee210d5a4b56616c696461746f7232", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf21292a4b58384768449837f754c99a44ba434a662f5ab9e81bb83c07ab5282538bafe448f142d2b6b119362b1bebbe176": "0xe26969331bf77ce04768009026a5362d51e5bccc12f788b8cda2a43ef218bd040b48656964656c62657267", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf212e1ebe0cf66f108c421c8aaec37e4f620430a70d2db1bf57c424e5e81de47ade7f1f0ceae2b568b9182ecf9b025aa35": "0x2cf0838b05fb182718de859525fa1e6d53d557e5fcf631ee9ff44c619810d43b0c476f762050726f78792032", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf212eab7168c18605d270be8e19009c67d245fa94cbc6c035f58068a57aee59359d7d464caf058fe55e30623df66dbca94": "0xf00168a3d082a8ccf93945b1f173fdaecc1ce76fc09bbde18423640194be7212083330f09f9a8020", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf213783372b26c4b0f21d1ab58ab4fcee312c0e71c508ea654da98971a9a27caa027e9478b84c319ecc1fb63288ffd9b0d": "0x12c0e71d326f83f4e6089448e147fdab51b0b7398a7d0cc9a88b0571432e7310033933", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf213a6aa123ebf90a2d40cb44290bcbe5e4ac0609d3d326fa83a76b4e89a445ff2c0e6436b338481041af7500057c870a6": "0x6aa9e19b08ef554ef0b123940b685c0d64eabd9a1ec487e43bb7e1f3d981c06200", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf213c3b27ac47fa89e8df1b00c8149ee6b8278ef29ec5edfc3f2694075448853b34a387e0299bcc326c41e9507a5f0ac2f": "0xfa65ad25c6a51ba28504fe803d9e3d542135924ba9fc0736cd3f1d9b839017780f466f726b6c6573734e6174696f6e", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf213ea12bbf865f261fcf67c0989fafbcf3515e1b78389f5ef86a9b5e739a0912d6cc4e9f4775698ac23458e8fe8764f89": "0xa8a2e5461f346cf0c23d1ca613437432a160525b6487dbb718afa51439d48d040d56616c696461746f722d3032", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf213ff6fa1d0e480ef82d3023f2bc505ec4ea8dd0f74def3f37653a2bc9932edbaa87ba9a185c55cd8b5bd733ea86c6257": "0x04c73bb4b37fd89e159ea8dda26c4021a4af572826ad6397d8fa9942c18b356805504f4f4c", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2142dfa9359ba3ed2b2f893e502c8b2390071d7ea9d85cf0a22365cd41cca3f63121fbef0e1eea72109db9b12af8d4860": "0x56d629a2c80762d412fad9c15d8cc973b463f600895170d43a10ca504b4f454e15205b355d20542e4d452f4b5553414d415f424f54", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf21430648e2a6c6137bb3f5d386e349ccd5c0db244fc6960005482b5e6c2896bf2064efd1e5be17e851dc8139f839cf062": "0x5842026fdfe358c9320e35012deeedc83c1e19d2b677eba10a1fad0d93c82b6607417a617a656c", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf21431c0f7853fa382a145bcca8ae92d7112c0e71d330bdafa9c3a6218dcea201399a6cfe0fa73c2692e7a83492614e40a": "0x12c0e71d326f83f4e6089448e147fdab51b0b7398a7d0cc9a88b0571432e731008436f756e63696c", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf214d11f5a4090ba5cb906b055f30a6646100a7405e03b712786ff8d6b522fe258843ec33d366eb61379c98aa028bf380c": "0xc664fbde2dbcea2d4180fc9e285ac56ecb6f89a9b88cbee9b407bbceea7da912033031", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf21509e5011f25807bb89b4356ecf60dc9ecd0f078418756af923fefc497d98efcdd243170af2694cb75a2becfe2811732": "0xf00272047a1369138c7948e8d193757bd7d6319254926d2b91175398d8250e30033032", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2152556d9023c3ebe1aa764cdf018f1384f83a66e4c8f4afa5949586c22ba0e7d73e7e4dbd6c1efeb9ccd689080834600": "0xd61813f456c8f11087d572921c67afff25605aa712899d6a6b04cc42c3d2d4170235", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf215bbfd788ae2c0f9c9e0a225c0ec055cfe57cc05a0401fad57f17da9b903ef6d679b4d16c107a89f7a8c3da798d10919": "0x42f3c525c66f2a4eacfa88479f7537670d2e1f45f4ec25703a111f5f003ba15d033031", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf215cb25fdc3162fa7d0913e39788c78cde1926d2b7dcec1ba035361a2d58a3ddbbc4386ba5bd61d5dd57d22d508154dec": "0x30fd1beaa72357f61ba1fe7e90aa8c5080fcd49b2c82e1b8315bcd9a223cbe4105f09f909d", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf215d8cc207ae11b542cb7cbb92097c7237c49a3654ea5a5313645948de60749792de736cb3870da7b401e78734eac3b60": "0x1c6d8b40be9990c19e993d238e6e3613cfc6cbc51979d5fa61dd6ea259385609033130", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf215e50edbdf8f9c55d248be9aa8aebeb41253640274e26277dde50bc1d72ed0b3f627e4c6b66d8343d4c52ae97afd0f03": "0x6a88b4d1ab30ab4708521d6c6d480a858d92692c0b0cff67e1a6904e23b84112067374617368", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf215f2fef1721c0c68c45126a895ef442f5c3e489388961303bbe308673f7faba33bae973af37d6ca444e1772a750c9775": "0xa43b2797bd4dd454d7fb0870a2a4edd62b39eea0801f6baaf09b05c8634b5a250234", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2160abd6b7efddfa47d7721371053129bd47e15ef535a26d9ee0e3199ea99baf7cae9d94a05581316885d0b21549ddd4e": "0xce5c65fecd7bb733ee636a381fa9dd916f8cca91e2e403c8aea2f7ed32b31d680e424c41434b4d4952524f523139", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2167ad101f38ea67077b668a5004b17b68219020203f8d92b4c8ae0dc2a5a9c7c5641486ac27a4b591d3560b434650658": "0xce5c65fecd7bb733ee636a381fa9dd916f8cca91e2e403c8aea2f7ed32b31d680e424c41434b4d4952524f523136", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2169ea0d85e46590c62e047babd2031ed5ff23e481785ec5fddb6178f6860b44bdaa0150ef473a91de3f1ff794b2b6fcb": "0x74422321a842adfae9419ecd3983c4fa2da6e879ccc1db031e54c742bbb9bc030232", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf216b68724c80dd9950366d2a74bd473c9489553ecd89d7eda44e51d14dd217fcd4e8f183036ebc916ebb32844bffa9915": "0xce5c65fecd7bb733ee636a381fa9dd916f8cca91e2e403c8aea2f7ed32b31d680e424c41434b4d4952524f523436", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf216dd1b48754a2a6bfc3757b772f9f01910a315981265a9951067374fb624c1976dcf865c9dc43d08e3031ead35a06219": "0x726ac63a0a6a700ad7e1178fef89a87620bbc152a19f74708defc7f08bbc6556032f32", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2170594a2516688ce8c96ad22c918ef74a28d12dd5c12e1bc0f85ba2935bff3b257089ef59869ad310056febaa5793959": "0x4ac4eaed36e5c54f045b46cb54f533b2d3949c0ca7137e89ef03ee3f56f8155f05f09f8c9f", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2172e6fdcc7f8c128b419cad0db414c1ca6b7d31c38534c4c6dd648a247e5ed408172cd647084f554747823fe69304f43": "0xf6b21d624832094b03aa672e016462a020e217cc67b1434785b99114a2b4fa5a04763230", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2174ab42842aa14b268b5d779ff1bec02d69631266f8f9a76413f5f902d59578faf655a0dbf92938ed749fee838c81bd7": "0xf00168a3d082a8ccf93945b1f173fdaecc1ce76fc09bbde18423640194be7212083234f09f9a8020", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf21768a70b5a9f93e434aaea779186eb691d6cb02740c7ed074385a93d27f0f9fe5efc113a8e5961d964c54b0afc6bfa12": "0xd46e6f10cd59b0f6d7082dffb33d27c9f29801233f8e28fe3f5edf2d51762c6a04303135", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf21771c10a29ca314e7ede3eaa2e2ea1cf305b1686b3030de938cfe6a01467a664fd1b42e4f43fab7295963640c5128a7b": "0xaed98e15e3ed392e38654215c3d1fa8143de53460386b60139fbb45c036c1b430653462d3134", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf21782c028b4cee54e88a2a2f59b187df39a7994a63250d77c7cf6ea9f364f136dfd163cf4ee30d1fbf5de6808e443f25c": "0x749ddc93a65dfec3af27cc7478212cb7d4b0c0357fef35a0163966ab5333b7570a626572796c6c69756d", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf21796b54cfe327241f52ab83de740e7744613a2044c0cc5b2f0faca94f2d6e7b7533c1ca3610cca54ba03ab9c5831d826": "0xf429460ae52548e754c712a7cfc75f1bf7c9295da165293ca52ccc686db5c02d033032", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf217bbd7d19db7a586a590ef36d2a5c15b9c4151f0860839590586185a1dd97ef4f3fa86a6c0ad4eeb24addd8bca2aa758": "0xce5c65fecd7bb733ee636a381fa9dd916f8cca91e2e403c8aea2f7ed32b31d680e424c41434b4d4952524f523236", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf217e32de8f088da5a6950148d4e5914ec544e2e588c90a2e53e051d2f87d40e222e1f034913a30f95a9a2f39114e5be38": "0x0277ce02b2ac78ceeb9ae4fa0a595005489bf3f5f77898415e32a3e9504a531418546578617320426c6f636b636861696e204e6f64652031", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf21800c0ae0531bd79c7e1a42d62b5473f0208bf1b4851b0e3013141e274ea24d6a498412f2703e598e87b7fbdfbc2a72d": "0x8adc4e19e79b3d2c744f88fa5aca47ef05ccaae141f6435c2d50df824433ae48033134", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2180c52a2a840db7f6da03a8f69143c170069c3ebd00f7ee39c7f8affd0d14205768535bf95633e60e26f8c8006c27f53": "0xc229d8ccc5e5650d17760ce2b7c42bdae5f6afc6e8bab249ec77f3f779ee5a651331313a206e6f64616d61746963732e636f6d", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf21813670e858ce3d80abda7ad1d8d520c1ccc2a2abfdd492dc72fddeaae0b32888f3397860a31b3fcc88430f7c5338c40": "0xf0e5ac8e356d7a3867e9919b8cb1984ee5a070b1659b6195deb85039a3b699280f466f726b6c6573734e6174696f6e", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2183128dc8292ea45b743287a6fee4c30005e13effb82cec8d1e3de31eefc750ea3afb8df4ee1ffc18a66cf56ae4fe178": "0x280221db3cd2515ba48cff6c400cf4624b9459eca62f30523972ee5b608e967b00", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf218327b1c3d72d8d4ae9355220d5ced9f06419ac9e6a0b6d955fc0274eb9911fddac424b804fa29062ea417f05d64803f": "0xe666c8204234e3e9dc671cc875c4f22316e6a7b67bb8b0538d8d77674468ed5007736869627569", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2185e775e2507305ce9086190859a2ee99bee35b6118399b673cf802455159ae282fa4a1e68368fb67cf85b00e4746119": "0xd61813f456c8f11087d572921c67afff25605aa712899d6a6b04cc42c3d2d417052d303030", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf218d86490bc369378378383a66f630a33de4ea9ea77e628210eb1aee0c6816cca8de5235e04a861059b889c6b396fbf15": "0xcea3dabe52b2a665b1e19bf8c6913a5d54e06d6413ca3ddbec8f9a22415ec47711416c7068612043656e74617572692043", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2190dfad73fafb0d1b45ccafde3be8ee05c975241098f4ce19cd95187485c1b0006584a560c101890f32d65a67e787700": "0xaed98e15e3ed392e38654215c3d1fa8143de53460386b60139fbb45c036c1b430653462d3039", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf219632c158fa4271ceec193c1107d6faa1020aecf6332d324cc8681199d469780ab81d8e87dc408aa96ca573c590ce344": "0xa0340d617b2e5fecf5813d12bf441eb025f610edf738af8f79a98a9e168f690d04303032", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2197cd122a188ea3dde82c0e656be2377d45b3d8d71f6ca469454a375a951d272db9426e3712e172272f951d8b289d300": "0x1c39ef78e57f239200072aa865312f87edfcb4d4133c6ccc0a7e33f5c799e2010743524f4e5553", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf219a3c826e64c31486f97b2646f45669633815302aca0725e74939106884963f32a80056aba37aa94dfe6220c039cc87e": "0x273e55ba58de0184bb96e5e691dcc9171ec58658d2b94c42c7e4ca7574f6a07613e5a4a7e59684206461697a656e2e696f2f32", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf219acb7972ea18adfc169f255ba2a0c53d4fda909c31173d9691cf6c488ffe22b46c795d0bc95aa062bcf08f414c4655a": "0x629c17f4f4a24ec53f85a7beb1c70b13379fb8e4f969560704d2c25133ba8d2419416c7a796d6f6c6f676973742d76616c696461746f722d31", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf219aed655a0935ba8565ad4a450629a910d3fb75084e9d91405dffa8b3f1396968dd935308d4dddc0e119fbd6be444482": "0x4e3711ff0fdcfc953c9ff93355ed42146e442c256b6010ddd5b5fe0ee8b8ac1c0b436f6e74726f6c6c6572", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf219e225f61a007373b152253cd4cdb5b1a4b5a3630311d5cf8919e20be535ded925f210724ef5c78f8e3754a32ed43841": "0x9c7c545141ea2dd84fe5ef7d567ea450f59967e7afa68e5f1ff7f7c46db19627033438", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf21a0c5cc216d2bead2dd9a018e52181c470cfc338f687e55d944e8e6867f90a05085cfb5e15e2f0d5315ca27026d0aa5d": "0xce5c65fecd7bb733ee636a381fa9dd916f8cca91e2e403c8aea2f7ed32b31d680e424c41434b4d4952524f523132", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf21a165841d41c9c4e6684035fca91b67b0da80f8169a692da1a6a0bda931750ed897b1ef4b0bc9bc6e0cbc906981e2b6a": "0x2a5bd5797da40fe8be1b94dd3260ef86d6b01cfc891c5c1cd160ad7fa198de57066b736d3034", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf21a428eb19ff37265b2a0f3e9d7ac61e5b6a0389596b472840969a9088eb5852fa03a5b5dd7a3c2fc7275d7c05563a900": "0x0ce0bbe155c5f116187af43bae0bd493872f436a139e23d9b26289d0721a310e116b7573616d615f726567697374726172", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf21a47fe57c5fa0349cec3067ff31bf4715c8186e944c4df5cbb64eb1080932db445d11f69fb4da145a98d0d6aabb4c009": "0xa6c5f0595d6ed85d6260bc682d4a68a4b4e605d43c67d56f2765d19698549772067374617368", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf21a53113712ec3e23dfa7a3fbbb4a81f44033dc4a810332f94b2874b5aa564424b0583f0e866c908346ae4b2bcb4f5e0e": "0x4e908afcf0fb6b394bd1a043bc8b226fac33b4742731b9cde5d324f450eb3006054b563034", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf21a562df6c0dda0f3b7c471f84b57be58e85a54ca5474be7ec4f0e149232199a19f1f962331e1ebd5be36cbb77d8b0c3e": "0x9c7c545141ea2dd84fe5ef7d567ea450f59967e7afa68e5f1ff7f7c46db19627033732", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf21a563b1be1c6f1fc691a3db82789b249a01f4cca8129d5e282faedcd6547e6676e91c46067489a28711f89da641b1737": "0xaa7880fe9ca2bbf331fc13e40525dcb0da661f143df506fed76d8ada3db8f55104424f54", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf21a92e3b3081837f84577ed9566d27d7efc2dda4a648f70d73746458b1109134bbda7b43b46ab3546d310823e36966d76": "0xaad8e905d4c09ac501fc3f74833019107288077bdaa77291588b5e021330657c10534d4152542d4b5553414d41205454", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf21aa6ce7ec8af0d5649fdd942061bce54c08ef34fd7c513a00cc447d3a01368dfb0df9d3c84ee52182b8749e18573e14d": "0xc229d8ccc5e5650d17760ce2b7c42bdae5f6afc6e8bab249ec77f3f779ee5a6512363a206e6f64616d61746963732e636f6d", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf21bc339faac854827df2a043f2074cedc6964958c102b007555e5fbd10a3f98ee67fb2bc270fa0d20fe2371916450079b": "0xe8b2603f6baee5bc32a9b9e4eee9168499fa553d35edb56aef0035ff7e1f165e0c314b5620f09f8c8eefb88f", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf21bd423f7418e9c1eb1d2a7a7be14778efaf6136c1b5c48e96fa266bedbb262f30748b53d9da7a435423272e1e67ede79": "0xc229d8ccc5e5650d17760ce2b7c42bdae5f6afc6e8bab249ec77f3f779ee5a651331353a206e6f64616d61746963732e636f6d", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf21c7ee21f03ee09ed1b714b8d65938e596366490cf9fcc50f7edbecb28e3b78330a0e35d3e073cfb3538ae6540f0542b0": "0x7cdc1a6a5a7f23437b6528edcdf553d0685f940a4e6e85579727ef3dc574563a04563031", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf21c83a483946d3f1c3aa060b653146cfac2de6256e9ff0ba9b97f862290f69ec0f72b31fa0a6843e0175e9e81a0165d6b": "0x96e24e9b5ab82dc275b82318a52cebed1cae3e25be096d5f288229b256359e430232", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf21c88a35959cf7297788e69c0938357382e0c76ebaeb0ca61c682a80271d95abff7bd6249acb3f90cd702df6f23368b16": "0xec5909db1fe8581fbe80eaf39b4577c12a99d5abc87131bc3d4363f623412f42033031", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf21ca9e5c7ad4fb067654fec77e3cf49d2e6f485794ef2701691b1508c90cb2d3bbf6186bff0716c43915936439e0645a9": "0x4284fa7c290fb6052b9437610cfb2e19b3b37081fc72140e444d5b57ca01924d033031", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf21d0913a4692809429ee2d8bc2051cbd15c5c5a4a025f3d8be84fa9ea36383c2cd168c8a018d50c88a34154afe9ecf04f": "0x548dcb6c3aabe041e7f7ee65af37818dc7ff1ff1a4300008100322c39e9c610b04474f56", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf21d2839773325d03130afbc0b9258596828add2af7269292c685caa58101bae5d78297eff522e3f6b239fd4fff6b52132": "0x845498df40e85e2ba9d9e213d1f476e7b147aab6a9098f1bb250e00251ef8f5c0232", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf21d7bcc3a30ea81e6b0f23efcf27793ca6d6f646c70792f6e6f706c730012000000000000000000000000000000000000": "0x04f3da939fa351c562c7e06e1e3716976b5e14230e83a45995cbad9086f49e1705706f6f6c", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf21dfa8f553250b1a01dd3029b6fb4c018c0d792a19684453c51324b0f2a420544d8c3378c515c85c6aad72b7059ed4cd1": "0x88e89854ec5f225c9a3b8889d4b1afc0cf6cf473d4265a96463c08cccf38905b033031", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf21e20801bf4118db9d2b9ebe8a8f6e8c8c21c287be88281cfac16666331518cf2820f4de9c29d7caf15ffb596f12cd953": "0xd49e16d1c4f6a051815c5865058cb218fe7d460fa893907bd0cf8596b493f45a046f6e65", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf21eb9704b8e9a24c4db38498d7e24840528e3a8ec56f21d20789923fc326898987dbae48643c059d5ba9a8afe843a6f45": "0xe4d733aa6e16d24e220efa69687f6ff198317062ab5ee12a059d47b732c27624033033", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf21eb98516eb454f77f6bf48524fb351aa72f10843313abdcc3fe2ab623e213c561d68539db6f9b47f72a41f2946c7fc45": "0xc4516751df2e5803bac3bf9cf7b6d55cf4acbd76f861ad0a2a2b71b7a5ed805406f09f988834", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf21edee54c7d3f913c6b5f680546f1c7272fa216946d71756ea4bc43259d6866958233f796bbdcbca326d684a840ef72f0": "0xb0d8ce5256f0b5a51a38ccaadc6d21fe930d8ff3da1dca198ebe1807802da75304303132", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf21eff94efdabbd48d172d1d4aee227d5dbf4221d5348a254fa587bc69297dd25173e89f25220ec395ec495e3df9c41d3b": "0xf00168a3d082a8ccf93945b1f173fdaecc1ce76fc09bbde18423640194be7212083130f09f9a8020", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf21f11459100d14c4bf85663adc622ad75f49bb2abd8dd96beaca34bd5bfb81b5edb5186922b92c3b1f5977cc401b79554": "0x3a3884dbc6806e8b4cccbf2c407d800c12141c3d7cacde442a649a6a2822ac170232", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf21f2e64dd2847cf975791908dfcd1d8c0cefcdee5940f8e74338264c625fd7fe4c671ce205773f69e8bf4cf1b372f8e26": "0xa89a9920a98f3591ccc0a1a4bc827a0adfba37b75fcc108ae3c7191bb9a32750032332", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf21f3b43aed9ce7291824c06d4892f051fdec5377d25559444879fa2dbfc018dc9bc4b574c73e7cc4ff17301e6f0404b0c": "0x8c8305ff8478e6309325ebbfb81e8c1883d39e65d2ef84f88e4a428615c4927704313035", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf21f42ea75dfcca5aa9269c87c2c7b16fe12c0e71d6034eaeb56b1637b948fefd184ecfebeffe8dab40a37c6cdf3971a40": "0x12c0e71d326f83f4e6089448e147fdab51b0b7398a7d0cc9a88b0571432e7310033232", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf21fb6bb2381445273135be0586609532bc0020cde3bd8293eb5d5b61b072a9f6b19cdce1624a8ee4a27ca8c57e3ffa628": "0xecc96f0e735d4677e64728f5300b27c97c3413ba01e7a60dd29cb89123990a660f666f726b6c6573736e6174696f6e", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf21fbd2ecdc920f992454e24c102f0582fffd31bf694e0d28434da06abd3fe4febe23b25054b5de48ed94246339c51b2e6": "0x1c6681030fd4860fcfc1dfad9ae55fc0181229b007b6365dc4c8f5fbe162554c033031", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf21fe4da6599e579730de6e7246ab6547b285f7ae7cc2580d54ec3be6fb7fa3ab6f2c1a32352c793b29163822091839e31": "0xd49fca4c127d246783d23e388e34c09446b624d2d5e1f7773c9590823d45101904303231", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2202b406165ae0b48a55036c390d6a7d45c899bdf0bebcb57f0f68da86b80f8840407e7388ee52cbbc1a60f18a7a2eb58": "0x02948b18cd5001e68a33499343bd8ed974fc8398bbfdc3dfafbc7c478544f67d0232", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf22040599cad87ec0bd34f66d1874b3f1712c0e71cf3f161c02727017e5ce4f8f6e245fa61bec1a3a1ac960fe11e917c26": "0x12c0e71d326f83f4e6089448e147fdab51b0b7398a7d0cc9a88b0571432e7310033037", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2209e38e283473095a463778fd16f4db182f53c176ea7abea9092ab9b7ccb5506dd3c81de6fe0a5d2b29068f53dd3706c": "0xf6944b2b5f590f132203e5dd4f04c56e594f43b5681a48b210899382c3880b4e036b32", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf220a577df28075abf403454d10bcde194fa0f5c211f7844143928941e88780961c972b189e6269ca6e0ad98fdae5c994d": "0xce5c65fecd7bb733ee636a381fa9dd916f8cca91e2e403c8aea2f7ed32b31d680e424c41434b4d4952524f523433", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf220b79b5bba03d2686899e7c2f4fd8d57bb3daa994e809e4484afce1c63b8737a9adb8a91ccb78d7002386a087b382de7": "0x122ff96f07bd9c9b3961c4387d71362315d05addda58f1dcce642888a643f93004303030", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf220b88d9599c058872b21e4b3cdee8ea95a43b9d3a39997151c4d745c1513b73ea440fcd50aec480eb4ddbe65fe692477": "0x9c7c545141ea2dd84fe5ef7d567ea450f59967e7afa68e5f1ff7f7c46db19627033437", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf220ba2427ac987e1ef9285ffa826ccee506929a0b268c8a51c457e031e971ba6d1624b2ecccfc94185a8b593549ef7b40": "0x48ca001326b583070e370be3bc6680d09cad47649584a5c992bd388c693b9a54033036", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf220bf3c4573e2e1f7ec7423d959ec2aa82aac721ff23bb9448f8ddec8ecd159961a23f604f8fd22d729c3390e9f36f843": "0x4608fc7527698d3f4d4cfcc6074f01c2ed59112ad670dd5206b3658bbb62a0730e4f70656e6269746c6162202332", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf220c19d30e3fb4f1ba4cbe7787f6ece10a227e750a30259349ff46ad36105156f552fedee92bc3b81470cea913d30d6cd": "0x3e3622fb285dddefdf8f9ac2ab59aa34e2abb5a316e9ebdc020317220e75f879033032", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf220c7172b569a66d53b866ac6577a4f60f2b13a9cb72a219a88fbb88f7c5306fcccbaa21a22484a24bbb84b8acee8b50b": "0x26842927c98a50ab1d439ab45f21c5beb6970556e1fd7b52df44977e4344b148033033", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf220e03524d700cacf37cb5192fd0e1f5b12c0e71c4b17ed34d92d3794d3cac294945580552a9200d74dbaeb0a17a2ce7e": "0x12c0e71d326f83f4e6089448e147fdab51b0b7398a7d0cc9a88b0571432e7310033639", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf22130193fa05adaee596bb9896b886a31c88752d6f18f0d5c804929cb727ce8999603dae997b121267ed59d5bb229af3b": "0xce5c65fecd7bb733ee636a381fa9dd916f8cca91e2e403c8aea2f7ed32b31d680d424c41434b4d4952524f5232", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf22132c32bfb3ae0cc31e4b119346fc882ba65343515a46a4aa9932cbdf0105d123c9d4ba9bef3be885c46f52c8c058d66": "0x5a1a549172a49f7591155007c51680ad8ad77571cea04acd1b0b84459e7792340f464f524b4c4553534e4154494f4e", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2213824be956ddcb02bbdc8707078a0ad86cb4a7d71b52b87a0ba07d245f92cc52dd40259d14190cd15f36b509f7ff511": "0xcad4349f82754f223d99182a3f9de949c41ff94e672f7f548e7f4e66c04b5c1b036b32", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf22148a915b086b8df3e3f451d5cfe83db7f90cbd721e0f6df172266f725ed45095c9ac42202cbd84abae8b5494119a938": "0xc0b881e2db47fb95982cd5c364b87e6cdf5a5c8a336d980156623b53815c597b033130", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2215732379e61d4fe352771dd1f73b23b2a5a25fb22ae60a8a24177845715bb880e16ad84344e91d1269ea6940e929f5b": "0x52e73898bf4601f9c9a7fa052de0cc313b159dd368d458f4cb0341eedcd6d81804763032", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2215a57003350bfe8b80a05321712c0b56679005100a874118c6c38e5b3183ef6cb71193480d1de0699f9bb6bfedf1f24": "0x8c20d46f86242eea89c400d5c478207e05c76bbab29a748af8aac90d627e1a010242", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2217cb5dc80e770e56301e3388342372f046511c11fc56b5492bf9fdb92b3ecf551ebb98b73241db611b2a44decbeb856": "0x56d629a2c80762d412fad9c15d8cc973b463f600895170d43a10ca504b4f454e16205b31345d20542e4d452f4b5553414d415f424f54", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2219bc92ff0195b58d944c87fa8c720de407ffe0ae098321e72b2b6fe6ba331285a2967a27430f04375910007010589c2": "0xc04f1633da0ab6cb71f71ece4d1a5c32926d3f707d250f66ab712d65eb374b2d04303333", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf221c70668af2f47e52784ab207b66b07abbce0e01ff970a8d2462a545370e0b992e069db055e417820aeb77e6870f9d09": "0xf00168a3d082a8ccf93945b1f173fdaecc1ce76fc09bbde18423640194be7212073133f09f9a80", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf221f2017acea08193896886ba2d42fc3652ff057f98f0c1bed31b2fd1ccd8de4d4acf957e79b3f71eb69820bf0dc1d22d": "0xd2eb07f02043788e254d9e2df57be11566d241c56302b91199b4647947af30200232", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2221549b91569912fd4013a346530e6c7982b1616f2b4b963fe2a8aaec915c4d3f90aada694bba3fa5924127e67a2456c": "0x0cf88657e8a5e5005c67c0ae58b0ea1137b817f32d30d80aba618a70b13bcc66033035", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2221e1f9b0353ab6960a7ad450d81b3442aa7daf7650583460d76859d7f4fea90eaf792ad9cc03e9bcc2667f165f00b36": "0x148a35cad2b2fe9cf6ffe0baf5f4f2f4ef894263baefead0e797a1e3e6d0a07f04303137", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf222442364ee4b51b29758d2beabe55e6f92def6fae3d1c6c1598aaaa7dfbd7038c3e047da285f993929e25bfea8d04b40": "0x08a23d4b915d29be5d2aa20f36649e004c6ee8df393064edad697934281bd51f08303150726f7879", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2225a8729dee127dd905734cc5723d49f2cce76137e2e2d9bb63e081d4074cfa4688d7d9781d2888f36634f646da62561": "0x02385caf9a08b92ca458a0b817a8cc303cefd5a0c6e108cb939e04242b9e007d14537562517565727920486f742057616c6c6574", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2229e03382361d7cce206587758627483faf6bf2c43d534d180a04d58c2838ebe73f3c98e0c3699f224ef0ac156c65e23": "0x9c7c545141ea2dd84fe5ef7d567ea450f59967e7afa68e5f1ff7f7c46db19627033231", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf222a6b1ea3c39e6c998b84bf80a02a9461aef0e83444feabcf8eda628195f0d756082152cad2aaea5dab16de839b50931": "0x945e90a1afc83f0c74a3ffe96b40c4ebb5397af04126bc2db23036c043be4a630231", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf222e875cf6d620f9a2b1c59ab9ab4cb2eebeb68d26988495f05130309042532d32304be1b171fba3f5f2ac94ef7d33dcd": "0xc5c184f0565e2192d6aedae584ee736cef875f0e1c558ee3ede26869acd0b4d60b4b6f6c6d6f676f726f76", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf222ecd11d7d3362f6706cfe9a27a85d258cf5dbc7c0ac18cccaaba93224d0c254df33169cf4d38befa64b443b6c4fb75b": "0xc46ff658221e07564fde2764017590264f9dfced3538e283856c43e0ee456e5105474f474f", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf223263a99547c12f80c2696d7124ea053905f923a67cec79db9e1415567822f2c440e794c4a38b43144bfb1a044b2a2f2": "0x51f78769768fc88c83546881a768523b3c70c2500159047a970ac4ef16768af616436861696e536166652056616c696461746f722030", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2233e4a764a53db1ddfe7eef21269a810a243baa53ed09e1a0a8879b132121047f10b53b52b4e8111292a196a15136737": "0x1c6d8b40be9990c19e993d238e6e3613cfc6cbc51979d5fa61dd6ea2593856090b6e702d746f67676c6572", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2237a4c02fe6a5829ff6b543bb92a7abf9a3e193ef4ff85f45060902986dd3ba10afd3e4a0749b6718119298be183bfde": "0xbebf5aa73bf19935376f19460dacf00bf0dcd021ca37d6a2284cc6347dfbb13b033031", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf22383fc60043a329576482e8e243f133d8a0e42d190d3ecaebf11d3834f4b992e0fab469e6bf17056d402cb172b827a22": "0x08769738ff8d53c17d6e0f0344e52c50a5ef6b61a33389f4dc4adbb7aa2f384d0a546563686e6963616c", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2238ca183d088243cf879ed73fbb18412b8e7e832b85afd9cac90cf30ab4477265f14901bc0f25b2142c2e488bce87352": "0x9e826b5434525d00c118f3f6b0a29b7f432be7bbd18659d472c5f07298e76949076d6572616b69", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf22440dac4070e76a7c2b9acdcbde28b80e8e0ac0aa68a0c138a3aa84813f0accae4ed7d6ae4b4905495026f16eda4e069": "0xe8e0ac0aa68a0c138a3aa84813f0accae4ed7d6ae4b4905495026f16eda4e0690b56616c696461746f7231", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf22443462acbc703f5e2df878bba1ee1c24e7dac693f453f3c407caea7909b1f56c8385dd3ea46059c9b0cdb32c19fba3b": "0x1e76b9da6373b204c3db21d2a7097a79afcf32f642a516980ae26c910e70a35c0b4b5553414d41424f5832", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2246208664a59c37b8232a108546ef20372c76dd7083bfe6b601d39dca6288bb8adaa0673c914f3b0c40ed812fa4b5429": "0x9c7c545141ea2dd84fe5ef7d567ea450f59967e7afa68e5f1ff7f7c46db19627033132", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf22467b0c1d946fb21de05bc940b426851ba7e6ae859516ab7792519d1ccc7781409bc58e534f54f4edd0981118d53405a": "0x2aa53f55efa82a9820f3c2569d4e52dc467475a1a11cfc9861ce5440316edb7a0232", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf22471b594c790c4a8ffb77218de909a518057b9f8b71f7e97f0bbb2dd94b1a047992ff072d07aa77f0a3fba1c28884025": "0x7c7d2fe83c4af79c49136f0f8c5f1a00cd8d0aa91c94fe74d0145cb96d688f66032333", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2248c079ff9305a5205356a76ad501e4948edca59aaf9ec40d9967f298ab5a5a2bb7265eef18569d5c065f318da512358": "0x8c2625b0e10c7bf65f283c576878cf00f67478d3dbb6bf39ee62b3ca19ce893d0c54616d6f204a756e746f20", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf22494a79e75cb38aec1af9bfe66916adb12c0e71c5200cf1cf22ac62ae2910eb3e485a104f610f1535ed1e844b78e2914": "0x12c0e71d326f83f4e6089448e147fdab51b0b7398a7d0cc9a88b0571432e7310033635", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf224a74414112e2385bd265ce7c5a6e384063dfccb3cf16ab95e3af6fa877724d2ec90697596897ea59069aefe5c223f58": "0x9c7c545141ea2dd84fe5ef7d567ea450f59967e7afa68e5f1ff7f7c46db19627033139", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf224d4c97f800cd5dc7866d75f926d746de816b1ea4928a0d642ee4b4fa99aecfb717bcd47086edb11316254c2e5844d29": "0x9c7c545141ea2dd84fe5ef7d567ea450f59967e7afa68e5f1ff7f7c46db19627033739", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf224e5fcb31802ec9ec4a03b048a2a3cefe6897f5eba9ec46ed569cb3c532d193f04bccc3971b065df4239a18a1e5e527c": "0x9c7c545141ea2dd84fe5ef7d567ea450f59967e7afa68e5f1ff7f7c46db19627033334", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf225213251c5514dfcf9906296ab7205d51907bcf63ee4c58723b0457cc8207bbb53841e33ce3d2876f8cef269c5d4d3af": "0xc5c184f0565e2192d6aedae584ee736cef875f0e1c558ee3ede26869acd0b4d6074e6577746f6e", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2252377a7bb8a36ce28f1521001db8b4a605cefe161fa9cb1c1649080f78f9cf7943320746e75dbb4b1cbdabbbd6a6638": "0xaed98e15e3ed392e38654215c3d1fa8143de53460386b60139fbb45c036c1b430653462d3335", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf22543fb90c7c06ed9092a68a20140a84a0c8bdf19914b8931589d6658da943de4de04cc1102902a9e30d3d3bc68892c02": "0x0a912cf4f0c7894598d81d26f2c24f6e5c2541f312462bb576593e9dc549146d0231", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf225b4b7079aac7ba74397e3a110131c9af204ee949a256b7e81637b358f1d8519458e9b79cec9f1e345ff9d2ad4516370": "0x9653ea6fa2a3e4072178c4de671464a69d9c72c7ff7170bc76697b46b3947b0f0574657374", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf225b6c8392d70ef4e5d8f3004f45443740e46029cb6daf09d2408e111ffb14010387ffbe77b16539839cbff1473a3a402": "0xf01c087c4a752cbf56ae4672f910acad4b234a830818356b8378afcd8e0423600c534158454d424552472032", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf225bc31d7924c787aee6d2843d367cb517ab0ef4391500cf4634c08dcc0bafc65b9c787a651ca8679b8ef33a6b557fe5e": "0x70661c356f24a2cddc859fbae974cdff149661f165f5e622df3060bcb8e7b373032332", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf225c76b12c5310d71a248e2b47d58cb8514a0db74267a9c3994944cb470c48a9f4c8a01df05766b96eb29789e9f049748": "0x6280b912d54001e1ac0bbc1023ba9a16974a6c23d22e817e97d418ea94d29642033032", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf225e2b1e96d72f8f2faf2e5c02063642aca2ecbecab066ed29eb6f04bc145a5fe6ee36cc0144f46a722862cf28dba2c67": "0xf6b21d624832094b03aa672e016462a020e217cc67b1434785b99114a2b4fa5a04763032", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf225ea69f6ea3dc893c1ccd4a4f289aa91c83b0bba37f25f365e26efbe6c9ecfa7905dbdc0b0e3ae60b29980b42c509c6f": "0x5ecc1b0043fe1fc18950cef3726fa74151bc41f77438ce924c11a9b43823ff43035632", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf22606754377682cdf7d7a8dcb21d08351f8df53c69120d27f523d11d1704a4dba9448aee78ea4f1481cee14fa15124511": "0xce5c65fecd7bb733ee636a381fa9dd916f8cca91e2e403c8aea2f7ed32b31d680e424c41434b4d4952524f523330", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2266a0ceb0a9776c0adfe016169dfa4d6e35a5bb9f11f2d71940593c4ff87fba89a7ab269825da6282025c43bf0b4c07c": "0x8ef5289702f6b8c7d22b3562ffda7d5593a5f6414226925e72097efbf9b257201c526567697374726172202331202d2054657374204163636f756e74", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf22698be0e43b2382133cc789436152a7208ec5cff0e253ab3a5d73aa4cf0db459f5128ed41f6b4d3dfbd99924f4346c58": "0x1eb38b0d5178bc680c10a204f81164946a25078c6d3b5f6813cef61c3aef4843066e6f646532", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf226aa69b6d7b1b9e4d2643e275020a81f7ebadb760b7f8ca8280f493f1604fa76e90df43f3ce4b084ea6383315b94653f": "0xea6a0804e0024beaa87fc072eb250446162310017e52147d18fada54a8ddb57b0235", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf226f32bcef343335e33d4bab42719c055e0169ecd64ca393045cc15687b0f3355f7c86eef2d25182c731a45e55f2d165c": "0x7042479798003022a5753c8547cb0de8ef25e2471e40889ff3909fe714e24c5d033033", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2270dc31da1c0092261b8550a52a8e63420cbc85619baeb354c068a5799d8ffa8b822505221d5357d7e70f2a3ebe08ea1": "0x2a5bd5797da40fe8be1b94dd3260ef86d6b01cfc891c5c1cd160ad7fa198de57066b736d3032", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2271a4d5b71d1e846e0dd6aa4b729046c4ad16debf0db0329b8fa6806c88a774c6d4873579225919e24c856728b575d4d": "0x56d629a2c80762d412fad9c15d8cc973b463f600895170d43a10ca504b4f454e15205b325d20542e4d452f4b5553414d415f424f54", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf22735323ae77e3c46dfafa9b41fcfef47f20bc9dd454ad586a9c7d259068e87412a8ea309a006e06857a0470704122701": "0xf6b21d624832094b03aa672e016462a020e217cc67b1434785b99114a2b4fa5a04763237", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2273c980fb676ea9204b5119d81a5d1667243fc7f5f476ee7c5fad9de673f1ccfdf59c3e92530c09d6d584ff19452c87c": "0x7243fc7f5f476ee7c5fad9de673f1ccfdf59c3e92530c09d6d584ff19452c87c164d45494e20454b5449544141422057414c4c455420", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2275863690937cb22a4ad61ef020a6d7f021ac11f4e66c8e210deb3f90609d0be4335e8c434912a92fbb1f67d3800452f": "0x8c8305ff8478e6309325ebbfb81e8c1883d39e65d2ef84f88e4a428615c4927704313238", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2275fcb0ed0b1f6f90708e70c6bbc4d423818c289aad92bbce3185cbc77619f99bb38a139fd9428ec6c2c97f964d01467": "0x7a54e6a55c0453407909789a06c3ee6719f8735ac370d6f17dc342717fd76819033036", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2276390edbde8a9d2dc25446e08ea7a4712c0e71c89568cdf09515dad33fa70b04cb39e21d8be64dee93e17569f962129": "0x12c0e71d326f83f4e6089448e147fdab51b0b7398a7d0cc9a88b0571432e7310033432", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2276b1a0f287bb8a9e322448184a1b7d35c9752508d09c36f243da599f0e850f3bea8f0cf5c43eaefa73bd9c6a075750b": "0xaed98e15e3ed392e38654215c3d1fa8143de53460386b60139fbb45c036c1b430653462d3330", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2278444534ff3156fd33c6448afc51ad512c0e71d378b0a623f2b9eb1b44430061c4f2bab9da7943fd286326a98b54a6c": "0x12c0e71d326f83f4e6089448e147fdab51b0b7398a7d0cc9a88b0571432e7310033530", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf227989d9fbd857434a0a130161cf82b32b06e4c7fa18e7887887e5b7424e8e2131e2a244163d4a70829f311a571d57c2e": "0xaa18b3cf52cb27fd19d5b80fe7982ff955e0d5124dae26ac360056f401dad8460b446f6d696e6971756531", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf227b5d660cf77fbb3ead82ec363f68f9338833de858facacb267fefbade2fe127da59cb1d3653e5acdaf5aaa1c0bb6f25": "0x04c73bb4b37fd89e159ea8dda26c4021a4af572826ad6397d8fa9942c18b356804554b31", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf227d5512b6c4425cfde8b11f1fb419270c6379520320c2c68f6e75938afa22a71c7f3bdcd1308ba1e7795a2fa2d9b9066": "0x9a92ad7c6dcc51fec9f6d98f8316406ca42bd04dbb029d3ce454330a20fac0770231", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2281b941957d5816af49eafa5806d300712c0e71c6323105cc5215aec99c36c3931fabbe7dc4a439329be146133235a36": "0x12c0e71d326f83f4e6089448e147fdab51b0b7398a7d0cc9a88b0571432e7310033637", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2281ddc7d5bf747f585a24d4c7fe7a0bdf6be65cc16c65708bb6a0e4b9958ffe23d1c56ee5683670a69dbbbb70c10d507": "0x6467fd4e7038b925c2422357380d8cc0c5f17d272f639af8fcfd1f1156de7040236b86b273ff34fce19d6b804eff5a3f5747ada4eaa22f1d49c01e52ddb7875b4b", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf22851fff2a13d1fa403c185f3d398a4d752acbe4b065282c5b36e7c1b552ccd1bae6039f9e2abc5fa4be566a8f5f10e45": "0x6610405d8ddaba4dcfca1fe4d14f83496de1055fe97efca594f2813a82900e40124e6f7a6f6d692053746174696f6e732032", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf22896f4c3aa70bf38c325627742de4508b497cbcd9414ec2922ff86acf2e22ad1b49aa07be1182a9490c47d3170e6861b": "0x8a56b1da8dc3f4bd58630c15f5754ee634528a007ab510c86a7e1fe6e62f4166065a656e6974", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf22916751bacf7a1c689bf4bbd6ddf0371e396927763007571ab5c30a835b67c150993def51b98681dd7a69e87d7125cf7": "0x1994df5bf0f44342b1719bfbb1561286bd81b6d84f577f55ef45fe7ad6f50e4a00", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2293eece183f6ea017f64f2d32b7f3c45669bfe047c0962dc3ba330b1fb1a83c5cb5262c964fda49b61e9f98a8c759c4f": "0x629c17f4f4a24ec53f85a7beb1c70b13379fb8e4f969560704d2c25133ba8d2412416c7a796d6f6c6f676973742d74697073", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf229481b0ce752c3130d1f37b3d4fe62df3a620493bb740849dc2f946560976cc5f8fc004b038cd61859f5be0b2ae3643f": "0x9c7c545141ea2dd84fe5ef7d567ea450f59967e7afa68e5f1ff7f7c46db19627033735", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf229bfcde621156468aea93db41e872cf912c0e71c536b024440ad0fd64324c6eebdc0e497207ff42489ca8a2489f6e327": "0x12c0e71d326f83f4e6089448e147fdab51b0b7398a7d0cc9a88b0571432e7310033934", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf22a2caa522dfc409937d4315e23476e3fa08ca28409640a6ce8108289d3a279cf6fc3f0657b60f3c41f89d04c0e5fbb2d": "0xcea3dabe52b2a665b1e19bf8c6913a5d54e06d6413ca3ddbec8f9a22415ec47712416c7068612043656e7461757269204262", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf22a3b31e12f5823b68f1fee94bdcca383c83bf4af534e16af8aefbc56dcf58d3488c77601bb1abdebafc2fee50534af7f": "0x9c7c545141ea2dd84fe5ef7d567ea450f59967e7afa68e5f1ff7f7c46db19627033938", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf22a691636b3a3cbef7b503826101e110490255910ad0897e5c6746e33cf138d8f38a6b46b685d06da2802f83917827c04": "0xb0ef511fbed15d88d75933d12bb50b56d1bbed109380b2fe0c7ec72d441191520232", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf22aa943c74840f4849588bfa41167504f0cbb4adb01af79c560636910430458ac44cf5fb9e24482279191e6ad8aa33148": "0xc4516751df2e5803bac3bf9cf7b6d55cf4acbd76f861ad0a2a2b71b7a5ed805406f09f988832", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf22aac3855e73925bf3eb8bfee2c26195e8d9511843f9df390385c97ef304025decc2d42cd7082db58f5b5e0523c58183e": "0x4eed7cf3f4f6560d58db4eb78bd24b655bbd1d7a5c6b454e77c8dc5e2721a54d07444941424c4f", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf22b4c364d171cae9e79e93ae2d94d1e623ea2629ce3574dc7dda1f20721f7d7a1109dea19ee434885d768c5c9f671271d": "0x8c8305ff8478e6309325ebbfb81e8c1883d39e65d2ef84f88e4a428615c4927704313139", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf22b52e9d7ddc972bbe306b9a3332fb9d2c09b9c71f2c39942154cf7749268d6978f82a55ab68d6a412c628b2ced7f9d3e": "0x6610a5024c2a5db3d02056d4344d120ec7be283100d71a6715f09275167e4f38077061796f7574", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf22bab81ede6f82fa5c2d8b7bd197504de679d98218b5d055c770d3a2a406e2e56a97083100bec05cb83f530632dc8c313": "0x1c6d8b40be9990c19e993d238e6e3613cfc6cbc51979d5fa61dd6ea2593856090e3131207c204368616f7344414f", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf22c0fea6262a5725940873b3385106acab4f8dd9a19e72f2ae65f989872a96ee2e239a9e135a868bddcb4dd278ef0f97a": "0x4eed7cf3f4f6560d58db4eb78bd24b655bbd1d7a5c6b454e77c8dc5e2721a54d0b4d55524349454c41474f", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf22c1f0987ad658f71dc2e4ee60a1b701f38bc883d8fb7ae97eb3a7862cff1252172f4a901264c84b7feee0a900a64f77d": "0xa2da2913d7db19baf0a41dc40a73d75bc6001ce1691c3ded78e4e86387881b4c0232", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf22c26bd89a02feec6d62288a29dfd9e0312c0e71d43df157fee32bea33e2335ca841ecf4689f61b53af12109a990e8b38": "0x12c0e71d326f83f4e6089448e147fdab51b0b7398a7d0cc9a88b0571432e7310033138", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf22c57288c177f6043c1551509c78494fbea073956416e6c3fb74d4423f458a028c9674f147468dc0e2ca6d2c140bcdf4d": "0xac33b989d0b4dd35d2fb8af4cd04cc5a3831e59023cb884044f5cda0541f1064033034", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf22c6bd18357e634c3d6411538738a0f0378c7e23425c0433a78c7f295bee57069c78743b4630161530af5e6e5ad5a7024": "0x78c7e23425c0433a78c7f295bee57069c78743b4630161530af5e6e5ad5a702408636f756e63696c", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf22cab4c1eefc06f688a24c634694308eee6a1e58c3cb43cd4bc65bc251f9c7a1a3de5bc3f815a643d658c8c018158aa01": "0x5889dcc187231dbcba0bc0dad136d1ecb09633bc7cd5e27e04daa0277009ff2f033032", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf22cccb10f9bfae617e9c42d761e0bb8ea4c9f8b6c9bbd518b19a4fe57cb38df839f9d893c577a9106579de22ab1ebbb36": "0xc229d8ccc5e5650d17760ce2b7c42bdae5f6afc6e8bab249ec77f3f779ee5a6512323a206e6f64616d61746963732e636f6d", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf22ce1c9b86fa2ec5b4854f8f77041d3be98ab313fb0a6faf344c680e6afda715f41179d993ab86f25e481a6259c976343": "0x9c7c545141ea2dd84fe5ef7d567ea450f59967e7afa68e5f1ff7f7c46db19627033135", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf22d09503a21fe80f4242378babcd8ebe7fefa1659ff7e86a20f110974463d76eb0238f0e02f6b526df7d586b0657d52d8": "0x54faa9f0cc59a977e73147865791a9272cd4980db5ff2eee27096d34ff2fab6904303338", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf22d40d3242214a6dbdf33b455b4c4b7a9ce2e98564f421ca69a64608d68480080f5f317f4de4e400af3c065181e0c8a11": "0xce2e98564f421ca69a64608d68480080f5f317f4de4e400af3c065181e0c8a110932446f4b53373266", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf22d4c45042aca35d80e31f4e40f1f8a5dc2e445df84e611e629ded39f69fb3ed7877398ad5ce82ae4028b1cbe997043cb": "0x625a907225b8ed830c16996d75cda73ef03750b535a6d83ca2ba1246be2dd4241e5b315d206269742e6c792f6265636f6d652d612d76616c696461746f72", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf22d75f9545b5c4b10fd50ca6508173793ca66d6f03e32d64a1a0b23baf1da3ee469d7d63c69ca26ccf3b47752d1171d02": "0xa26f9a811e752199217945e52bb96fb08229d7904bc030f6df73b5b4e6bbdb6e08436f6e74726f6c", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf22d846da596a776a6bd99ae5793e24c351015f23420ba4e90023e3df81d423db7fe2b2691657d45e98f02816e5a832b10": "0x8adc4e19e79b3d2c744f88fa5aca47ef05ccaae141f6435c2d50df824433ae48033135", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf22daedbfdc14657ae4482462d70f2935c300685aa838106c3737c9e6c6086481f3daedc1b1650b84cba9405389ade856c": "0x868cd54faea1a0e45836635b2bf658733436ec69c5567d651be592392cbb69dc0234", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf22dcde81a7dbcd9cd9afe0b401bd1f79274047a9abeb7a65811ffaf6ce18a99cb02e092d317eead7302b23e5b99ef3c14": "0x366c1d734b33c714b0e0e9f164426e66e3bfa97b917b23e5d3674f4a2074f86f0b434f4e54524f4c4c4552", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf22e84a4a945b3b1e334fffe4cf4b0bb91645903e6212a6142af81631297af316fdd60dfe4f02cfefe20d20153e7945720": "0xa26f9a811e752199217945e52bb96fb08229d7904bc030f6df73b5b4e6bbdb6e065374617368", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf22e9e656ec5a3792f36a6a7868aface0e1c6861821c1863896ec24a799c6ad302e7173b8674e399251bcc571e4977c729": "0x1eb38b0d5178bc680c10a204f81164946a25078c6d3b5f6813cef61c3aef4843116e6f6465322d636f6e74726f6c6c6572", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf22eb711fe51521dc536c3e8ae8fe4e841007f0252d2dda00e8007d8ba227234f9407f28a0584158c1a74b2e4401ba921e": "0xa6500e450888dd3758b301a0f99d433264362547ca7d0f7631ea53871aa3be350556414c31", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf22ee35136874b9ce15e28d8e9fe9528434b639041c549fb527faf54fd7e915d481955ae0bfb42842cfc3d63b5b98a0f31": "0x62f21f6587843801d599ed5855ae0ebdd2a84c822919e80cd6f12899e50887720258", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf22ee8b7ed0b4a8d7af6b8a1dab4d4be4a3c53243e05c79ffbbc910d8df74e4d1ae0197db16b7f00662e2aac74c8ceb302": "0x8c4c81f382ae2c201eed4b0b519f352aa9c0c8593122418b30ac9760844de2fa0232", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf22eee8ffb69a3b9806ddbd458373569a65cb36ec4414da2e8f8e6be74901ceaeb189e4bae84245b00640f96ea36814501": "0x38f45bd8f6341dac4486eedaf00f2357cd19b8d4b8f0271c7340d56fe02bca72033031", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf22f34922e2a2922da4afeaadc44ba7499389af7a171ff4ef270fc5c602f1570ae7b818fbcd797ae42b5ac9f14454c5b4e": "0x8429c11f2ff4fc700087c7fdad402d6e97c6df5e73988c3a36c2b6fde7daee210d5a4b56616c696461746f7233", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf22f46dde8630c188f0d344bb26d0798e012c0e71ca519959bc745598c859160abc7bdaac3949ca44ad9712c4a35e80c3e": "0x12c0e71d326f83f4e6089448e147fdab51b0b7398a7d0cc9a88b0571432e7310033239", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf22f4aca9679cdcab872802ffaf70676fc7b9a284d4e600ad4d23bcc2a12a3e52130d96586145ad8246bb3db4a7cb2e0f0": "0x6610a5024c2a5db3d02056d4344d120ec7be283100d71a6715f09275167e4f38033034", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf22f6c74d69b0ae9e4be1134e0d1034f2f6418bc819ab0a29b18e03aaf851463e3718bdb8649f5b864ce9654febf64c950": "0xa02f7333e25590e4f568ae8a2ddc93a879e92e48fa3cf1666ac56e020c106d5505506f6f6c", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf22fa7654c4aa6230e58f65b5b66a6d4245e5167d2749eb21e8d257aca0e738ebdf309e9e0ef503e1184463de7db3d0b28": "0xc4516751df2e5803bac3bf9cf7b6d55cf4acbd76f861ad0a2a2b71b7a5ed805406f09f988838", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf22ff897306f626450a6a589a03993a3d8403c772cc5a0320a23db863c40b5780a9390665df1e3b4255f32df1a0afc396e": "0x3a154cb2e55ed80b9b671b240ccf20a8e2a47a7097a61f156eaebdc98fe4780a033032", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf23011684e56d54a238826b5a928963ffaa057612349296f2777068dd47c499f36c5caa498c22b48f26c09b9498ade826f": "0xf6b21d624832094b03aa672e016462a020e217cc67b1434785b99114a2b4fa5a04763139", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf230117acc9de61be2ed1700dd8e07a10e9ef20ea6b98e87f656d7f23e0b2a310f45d6a6550a211e7df67540cd8b9c4b4a": "0xf6b21d624832094b03aa672e016462a020e217cc67b1434785b99114a2b4fa5a04763232", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf23055ef7f3959318572f2c72f84a7c5df8eabb61420c17a6e92eb2ca99f0e2cca15015784552ae332bf2105a592b80dc6": "0xf00168a3d082a8ccf93945b1f173fdaecc1ce76fc09bbde18423640194be7212083136f09f9a8020", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2306ae36b436b332f36093f5a288c59659a73a50c79a8b6552ac4628486f70e2efdc87020ce5460f6c7c5153429a61f58": "0x56923fcb0c362b333a2833175025883860f6b93996233319503a4ac478b7b11504474f56", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf23078e3402bea8a74fcad86d904ad4337206c097fd6569064a918b1fe42c9a302ee3762daa035b0c44eb771d6c34d1d08": "0xaa220871834d1f214169691dfd97c70823d90d192b246378dc01a59daafffe0d0e48797065727370686572652d32", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf230b0a6a605cff253ff46e0b65f43a29dfe41a0fab97ce06654fe9813a999a9d6dfb51bc7ab1f35dbbb27bbb3eac4c164": "0xeebbde3ff2bb37ca11414154e92c0521ac8051ea48d0d84b39714b2347763648033033", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf230f6e5348ce7d0c052619c0f815d14e9aacf425049b018fb55d17640939a6f651697b153bbc59a060a7f2ce4b4c5610e": "0x7ce2421f6b3c80a00c8fa9476eddad55f7bb9cc2f54ad916b4969c103b5fd438033031", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf23101377354ef463b6d4257bf9070e62266f3189c8351e824c55ea40817590b776431599273c4bd4c853b255e8cfb1b10": "0x56d629a2c80762d412fad9c15d8cc973b463f600895170d43a10ca504b4f454e15205b345d20542e4d452f4b5553414d415f424f54", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2310a359dba414c4ad563710c41387ec112c0e71cab33ca9929a6406d6634c55c8d28c63c99b18fb6a2c1eca3037b144a": "0x12c0e71d326f83f4e6089448e147fdab51b0b7398a7d0cc9a88b0571432e7310033738", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2317d821afe57e9ed52fd1977812baa6dcab8f3ac8a49d03d47e037a2f63bcb5f38a180115c70db29ee4f379e2e04c335": "0x8c8305ff8478e6309325ebbfb81e8c1883d39e65d2ef84f88e4a428615c4927704313430", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf23180ec9c6e76f1efad95ab3371c1287b0036d9a09a0a63e987a6c67a59b52f9eedf6215852cdb4fd034ec99475a17f1e": "0x8adc4e19e79b3d2c744f88fa5aca47ef05ccaae141f6435c2d50df824433ae48033133", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf231b722186de98b1feeda0be9e4f1c17b6804069db501a5d23ad862cb312892bdb603740707c1948b797d4d30dcd76d1b": "0x9c7c545141ea2dd84fe5ef7d567ea450f59967e7afa68e5f1ff7f7c46db19627033937", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2326acd80f3ad3abea8dd2ad7fbfb7797f2453d14482695f0ec5b7ec434dcddaaf83e09e570e22c293906edad0ef967c7": "0xc0b881e2db47fb95982cd5c364b87e6cdf5a5c8a336d980156623b53815c597b04423037", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2327a1f18eec3576a5b0e4670c37e3d6415647f856e3beac82df2fd67403a0fbd18fa79f584646112d15d61a064a681c5": "0xbcb916e7a7ef77dd1f610ed27ec519b4ec226028eb8edade41f95b217f89f6200744656e616c69", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf232ade47d0b89a6e7f0ae456172a9d04ce8ce09ecba19cbfda0c26fd052cc50a5365b22ced871d32fb6a2eb1853d2bb7e": "0x9c7c545141ea2dd84fe5ef7d567ea450f59967e7afa68e5f1ff7f7c46db19627033832", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf232c8c774a969e47bbd831e4ac133f990acf39cf23dd3530b4078b43141f0a0ce5c19549909b0ce4bc163984e045d9b65": "0xf6b21d624832094b03aa672e016462a020e217cc67b1434785b99114a2b4fa5a04763233", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf23334f94241fe9fb24eaa8c30bded18705611f54264f980f8d850f4fd87ab8eb7e6c86b99b396f50d1aed3c5cafcdfd88": "0x6c335d86444f3189027cd53244265047e52a96b4621fdaeeb9bc12857789867608e29aa1efb88f37", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2333e579bf94f3417638ea707ddbd3a44e79c699eb894e1a203b2c6deeaad557fd51fa352841d2d178d3bf78aa0bb1172": "0x36b5dcb29928d8a462f493e0250e895158fc4fc54eb5d00a2a6701fe36a4283d0d5069636f6e62656c6c6f2031", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2334f674ad4718de3cfdc31e0294ffcd5ea17387e7283543fb633e2a9e0f68d39e172cd5624c7095e6d81ad3468f35b70": "0x828618dad92559461b479508086bc781d88434e5372229cf66ffc887672e9b3404463153", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf233541aaf3b0b46163c153eea9269153b027d4770a8fb3ee70bb1d12b64f93c794dae984ed5e991267c7e776c77470f5a": "0xdce117ad72d855b586a1c7ab1e2e1400b00418037000a81a26d131eff8486b770231", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2335dce23fcb736c7d343245e1d97abc904f231f52cd2a234dd3a72a7c920ea6e10a7f85abede1a9b4062428bc303ad7d": "0x9c7c545141ea2dd84fe5ef7d567ea450f59967e7afa68e5f1ff7f7c46db19627033436", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf23365a7a90454eb5b2181b283cbe5afbaac2fb3fedf57f058e0c786f94c46f57eb68ad57982f0b96f56d5d438119ebf37": "0xeceb07c477bd40d22f83b08cce78f2375bc1e4cf188c0de1ffef592570383e590232", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2337cfd982a6aeabbc224f3da01500866e81c8e2c7bc6a6b6de522487e8829344e992a3440f957a52c86d93038b9b3dc8": "0x3e3622fb285dddefdf8f9ac2ab59aa34e2abb5a316e9ebdc020317220e75f879033031", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf23409b9d4359b7dfb24d65a40f241da551415a9d9719c249bdeecbb9b746639f743e2f238ef5a2b227ce206eb93724a6f": "0x5a6e6d7f1f5af2300c1b721cde7f08238ffef321bcb45cce819b00557fdedb00033032", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2348d794b1b37ec54981cce9b89d308fc12c0e71c55443e88a1777244fd0816a9f44562ca36e5b9d95d45f3d79a1cb560": "0x12c0e71d326f83f4e6089448e147fdab51b0b7398a7d0cc9a88b0571432e7310033932", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf234a57029046d165a045e3e0173bbf4d512c0e71d2b06750f95b1dc2ccf25272d0e77de2fa9efb9499be95ef938d6d766": "0x12c0e71d326f83f4e6089448e147fdab51b0b7398a7d0cc9a88b0571432e7310033531", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf234b9ba15342be66c3c34fe0ec01d7333023fe56458783b5ac1d399ab49e8ecfe911d282cf645ecc8b4d9803a130f685f": "0xd88a4b558274e57737ffd3fc9741848596199a29d77fe511804d20810cb7605000", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf234d09a76db87bebbfeaec04cd28c9bdb12c0e71cb214fffe90a9fd96c396cd776ae64fe664bd26e6072e7328b1df5756": "0x12c0e71d326f83f4e6089448e147fdab51b0b7398a7d0cc9a88b0571432e7310033938", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf234db77d5e2b41fa43ab18b6c949f624eee69e45394d3fea77645868ce1992caf33fb25200b4ae2b41d1306a46dd5f720": "0x26842927c98a50ab1d439ab45f21c5beb6970556e1fd7b52df44977e4344b14810416c69616e7a615f48697370616e61", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf234e0b7a0e3a3903166e63810a9d2a71cee9862cf3f7401d7c82461127102626135ac670ea079780708e1ad2c537d9c2b": "0x02098b5f718885f0d6f0f18359a7d16b44c9229857934efe66daf4d9f0eb7a43033032", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf234f4bb0d555326ab304d10f0e745dffd8c7afec700f1f0c83226176063f349c34c3b100f192e4bc106c3305c1c5e4c38": "0xf00168a3d082a8ccf93945b1f173fdaecc1ce76fc09bbde18423640194be7212073033f09f9a80", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf234f4d45fd1eca356f7713bafcba053589f3218e31dad244bf47477de316c3f46a721149ce003f4514eedc2042b854e66": "0xf00168a3d082a8ccf93945b1f173fdaecc1ce76fc09bbde18423640194be7212083139f09f9a8020", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf23557c6d2ce145dbe718e6e91f686834a5ed6723c4d9632bd0c61bf182c0904ae64fe1dde3f5f1ffc532d41fa14e28405": "0xaed98e15e3ed392e38654215c3d1fa8143de53460386b60139fbb45c036c1b430653462d3337", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf235cdbe003217d4cdb9e41b7122a7b63c1d3635e81c3048b1b2459aefff519b68d0100710ff64578709ca3da808412054": "0xbe1c7627fbc96a38d3a3cf746ae545f60e2510ed80961537d9b4924421fbb56204303034", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf235e88ba6a5b07ce8a43b3b5d55da335cc6df02cd907ad64313666799a84023c8e8025e7f9f5483a05823a732de3dbd3e": "0xea6a0804e0024beaa87fc072eb250446162310017e52147d18fada54a8ddb57b0238", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf235eb66f50ad20fcb207b7adce083d729c89604d1a2388771784ef80c5577fad1e75bb2362d5d578a94e8dfb3d982e938": "0x9c7c545141ea2dd84fe5ef7d567ea450f59967e7afa68e5f1ff7f7c46db19627033730", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf236058ea1f2c5cadae73f75ddb39fc6cc9e23e3588757c7744916bc6b65d9562fd12f807da8bfa23ca354ad5b40bece4f": "0xea524b9e0dd9bd336d31e71bc1a172388b10d4b6571ace5e7e6e8364831102160231", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2361c4486fa7b6b3d0aa538738cb50d3a527638f35f3b999cb645e1e70a49e7b798a89c36b289bd366056d39115c18ae4": "0x2a5bd5797da40fe8be1b94dd3260ef86d6b01cfc891c5c1cd160ad7fa198de57066b736d3031", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf23621938acaf24de980da0e9c3da0446b2c527cb7d17e0fe6df0e0da303a71f3eb46ea5bd309858389666ce6dad8efe15": "0xacab23f327e732756f5d76a43cd32830d5d8a9a489cd9c5c6a8554a3374da0561cf09fa6bff09fa4962057686974654e6f646520f09fa496f09fa6bf", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2367cf7925f6f916680a737f9a92b8452049590cf81393b2630cb72573fff37feee32bc143021d79faf80abf0356d5450": "0x56d629a2c80762d412fad9c15d8cc973b463f600895170d43a10ca504b4f454e16205b32315d20542e4d452f4b5553414d415f424f54", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf23698eaa4401c9aae8e9fa5d181e66f6c3c0579545b855f0070c2ca5c79342e333fe698081f709b7da3c9117b0b6b3e66": "0x56923fcb0c362b333a2833175025883860f6b93996233319503a4ac478b7b1150d494e4449474f205448524545", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf236d6172bf7cbe1ddf739ca148d279129be86d32d322797f67dd5d386d29d8285cb32504a767956fc58ed8f04ff703c4a": "0x1c6d8b40be9990c19e993d238e6e3613cfc6cbc51979d5fa61dd6ea2593856090574756779", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf236f31208a33c3240383aa8dc08cbdcffb06c021615bf00ced6ccd77c0bc8c820a71e819bfc48dff36ffb12d7ba044338": "0x74c76b2bb6e2e4b16fec1849aefadeae913aed26e72e2101a4dc34abb3e4077604676f76", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2370090c69e14b2750bc45822b5040c3fe85558af1d02241a456725d7ae7370cd1a5299713a970a312c99d9b14d90debc": "0x7ec5e89c029a05224b2759566042a94c54966d125934a8ff8beb8e0b017cbd67095472696173736963", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf23712d1f525df891e11270a6023f81e645263f205d321ac0063c4275a7daec9c6b5a34b3f0cb835ca2f4fb22bd9e55e5d": "0xa8a99a7f49f1d3d72656674fea67bc18454325f00c9a5921ec6010c43409d43e0232", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf23786e839ef62a0a379d944c73fbb9273a471c7aa909cc665212bb36003c52c5d3eeec39f96556a8242e861c5dd7dde41": "0x5ecc1b0043fe1fc18950cef3726fa74151bc41f77438ce924c11a9b43823ff43035635", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf237bcea3b60ff6afe7745cfc235b10c39227d3663b23d3565e9f07343f2218b47f60b3221f8bc32692ac60a22c7fb936e": "0x8c8305ff8478e6309325ebbfb81e8c1883d39e65d2ef84f88e4a428615c4927704313237", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf237f13f1af7ea279c40b76b426c29d2e112c0e71cb1a9c147998723d2dc7ef44affbf359be54830a570a5840e2734c47c": "0x12c0e71d326f83f4e6089448e147fdab51b0b7398a7d0cc9a88b0571432e7310033437", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf23815b690fb1e6c01eefa6eda95f10e6f6a92b1cb54e218fd9815b34f7a3a35ed39165a29edae89c7086040b59d074c72": "0x1eb38b0d5178bc680c10a204f81164946a25078c6d3b5f6813cef61c3aef4843066e6f646531", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf238186145093d353002ed83a10cc0283d0a88006a747b712bbac65dc015105c9cb6d29ba60dde6762a881975c6b1b1a02": "0x56aa4370ee3d21b98ec19f0cbf2106a036215937a15bbe517b24ae5fef4d38700f466f726b6c6573734e6174696f6e", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf23844247ae95268c32e9dd2d7b8b7d9a532e223d306f0e5bb9a9d6dcc9023ef06edc7717db691cd8c5d85d33b3a1fb136": "0x36e132f4b16bd325ddb6a3c63562f23c18dfd20bb2c785d391f625f481097c1f033031", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf238741c2654cb50f9a002f53a367ae7f06eaa97150a12560dfe00d1cb77f161ab7c29b6243193186f2d02e933c4c4067c": "0x78c7e23425c0433a78c7f295bee57069c78743b4630161530af5e6e5ad5a7024036b32", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf238931c8176066b77f9aed90f86b97084eb14462cbcddfd07593831e6ebb7c4a2e5f0acf8c052f6d76aa550113bb72b68": "0xf00168a3d082a8ccf93945b1f173fdaecc1ce76fc09bbde18423640194be7212073032f09f9a80", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf23898592d9731c762b9acac9d21e88f7af45cc1889ea605f6e375289fdb22c1acf7e99fc60cca3ba5cad46a21661a7720": "0xe683743954d0cb555a54ab21cfb8161f74e689a051d1ac1dbbb94df70be3d81e034b32", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf238bc4b013bc95d20f02635b88b7009fc204c52b467988d585dd9cb7cebc94d6e56d8b89042ee692b5739f7d78c39a554": "0xaed98e15e3ed392e38654215c3d1fa8143de53460386b60139fbb45c036c1b430653462d3336", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf238dbbaa13c7969b4a463dc1b8a0ad7146a3770dc90105517476a48c8280337f2c1e39dba204c254f7bb51c8d4ebb435a": "0xaaa635f88e75ad58af28925d0c21a804d87a449469e45970c3a52f57aba7b366033031", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf238e589a4f59e457afcd8bc58a8e109c25c97521b3cb9261f89f6b05b6ad17e9d148ba5f2cc03daabbfff35e0bc2e3f0f": "0xaed98e15e3ed392e38654215c3d1fa8143de53460386b60139fbb45c036c1b430653462d3032", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf239385193aa9c5a517717763b381e47a2fdce688a422833948306f4aabf043af4be9fb2be40fc763787f30233b2510573": "0x6610a5024c2a5db3d02056d4344d120ec7be283100d71a6715f09275167e4f38033037", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf239e3ced1badb912f71c02885076ac7979810e91f40b4c50ff66c7d228a9e4109e677c406cd6d2417bfb11f0899345e00": "0xd6030dd61ad78ca1900865d2b53dd163bbbb5b40c82f94d25cb6ecc750a93c25065061796572", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf239e7b84c16f204b681bb1bdf953ca0da0e8b9d19878dc5c50ed1ab180f4e76cf7e208851fc6a869b28dbc1ce6208dc0e": "0xa49deb88afa394b7eb478483a65a8c8f060b7de319dc6f65776a84d9e8f40e7e0e4b534d2056414c322043544c52", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf23a4fe5f633342995c5aa4f049d03a9a6982f4a55b705be63aaa88e069f4f93a955cc2e1c7dab295388d4a739ef6cb34b": "0x60b791f8467410a5ce2e880cc222933ad50705664917bc9d190a52596b9871211246494c494752414e2d5354414b494e4732", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf23a7f65fb5510634d37492a50975e87b00e794356479178e2d043755c671a3db6b1882700744cc0f570a84fd33e257e26": "0x6883b9f834076b9c1368e7692ec0a01ae97a52c5cdca957b5d31103423cfbe45044b5632", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf23add3f6b98a0545125042fb29e39d33968ef8bec8b0e59e7c456392b9f560a48c0abc26faeb75715b1ec4a804f469f10": "0xf6b21d624832094b03aa672e016462a020e217cc67b1434785b99114a2b4fa5a04763033", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf23b04c507ea436bb9a9c93d64e7af6eab55e8dea9080f49b00804005fa39712a313dc6bc21c3de49f172b3f46e9f586e4": "0xf00168a3d082a8ccf93945b1f173fdaecc1ce76fc09bbde18423640194be7212083038f09f9a8020", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf23b3a63572e436f0ecee136c0fa58a4f1809275c61d0a44ede0bb18a54adf2b684d44d1759e516e46634aad562fff1c2f": "0x48ca001326b583070e370be3bc6680d09cad47649584a5c992bd388c693b9a54033231", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf23b418ebcd97f2d989e574d67b34c17ae8aae19fba03bdb71cf735646aba2d56fa5b4b83aad3d96804d70e9559ed8071e": "0x9c7c545141ea2dd84fe5ef7d567ea450f59967e7afa68e5f1ff7f7c46db19627033835", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf23b9d8487e1e99c39710593982ada7fc3caad545c5c3d4c99b7866e2bcf2483dd7cc7cf578886586663aa25a96bc64205": "0xce5c65fecd7bb733ee636a381fa9dd916f8cca91e2e403c8aea2f7ed32b31d680e424c41434b4d4952524f523230", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf23bbe3877e9759bc837101da925889396c34542e51274a1c23c1293574ed5da6a1c28d092ae4362cec0eca403c02244d0": "0x9ee1fa0d8d4e022ed5680b5925d19718a7ecc9f8f2ff77de54f0822978d2775507536861737461", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf23bd0e40608da57a96544da6b957241613051ea9c01a7134f6a3223ea95a09c4dfe0bde5b0eb9ff7169fdb85d7a9bbd73": "0xf01c087c4a752cbf56ae4672f910acad4b234a830818356b8378afcd8e0423600c534158454d424552472033", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf23bd344c9ebf5e59eedf1843847c871d3894b90350435a6f04536b6a1c0f50e83344ac230902f07fd5e69953e8824d63f": "0xe2b3d30136a5bf1ad99ed78efc1c0cfdc6a2c65d3e30d86b3303f3533e155032033031", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf23bd81eff8cbbab65308778f5254bf30df836649df542b24a1b63d80916ee743d4734640aa796648649685dbdd430c362": "0xa02f7333e25590e4f568ae8a2ddc93a879e92e48fa3cf1666ac56e020c106d5504435331", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf23c31353e3949df4431d58a36717edf39c4ceb4225a9a168528d1264733d5b6bb5176c0eb31bb4ca3c962be4cdcbacf71": "0xae0ce04d8021516cbf0a10c00c4e721319c1e91c729402b232942f9e2c1523200953544156522e3031", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf23c42ea17d7eda48361e37ed8dc6ba82888508e0d4bb18e50ed1435a4260541b1c53ed009a64801727c195d1f81c08fda": "0x1c6d8b40be9990c19e993d238e6e3613cfc6cbc51979d5fa61dd6ea2593856090234", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf23c4cda34fbf68b7405466cdd8a800b49c48166c755e708cb83a61db9dc635e91cb496e2659e07fde8aeb09130802010e": "0x1c6d8b40be9990c19e993d238e6e3613cfc6cbc51979d5fa61dd6ea2593856090a6e7034322d726f6f74", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf23c6bfd44c6719b63b3f647bfffb348161ff9f838183843605f88f6b88971f887fd069e00f4a2894ce4249a8a70199a05": "0xc0b881e2db47fb95982cd5c364b87e6cdf5a5c8a336d980156623b53815c597b04423131", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf23c950a22bbbf9f095356cc70ad523f2bd448d47466cd9abc75c90e52f3aae5d03e772ca2f13db8516aad2ec15d341d2e": "0xf4492a28ead0b315fc68069bcc39470c409d12b4e48259384d63da411bad0129033032", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf23c994e4d167380e1e4c0bc4c67a284c7ceda44cb74eae64cceb6393fea849c84b6e7c0c00278b6339b14f882fabae15f": "0x56d629a2c80762d412fad9c15d8cc973b463f600895170d43a10ca504b4f454e15205b395d20542e4d452f4b5553414d415f424f54", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf23c9ef9777fa738330ccf4d6d7937dce0345e9fdb6c477d50a5c7be50ff581405ec6c151ed4ca2c25cf21a510e6bc7e6b": "0x9c7c545141ea2dd84fe5ef7d567ea450f59967e7afa68e5f1ff7f7c46db19627033330", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf23cb413cd5bf22ff85f90fa1fcad2e322cc6bce54889ca98332b8d289e4ab347234a96a1d5389bd183d7f991791a79f0a": "0xc0b881e2db47fb95982cd5c364b87e6cdf5a5c8a336d980156623b53815c597b033036", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf23ce56b1ab8734c5968aceaf9245ee3bb426cf52dc5549d7f8fee37c20ba68afd3443973a05bf692185cb913fac808873": "0x2cf0838b05fb182718de859525fa1e6d53d557e5fcf631ee9ff44c619810d43b0c476f762050726f78792031", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf23d940ea66d0242ab8d2981970f3b3c26b18c6f19f15297b4a80fb9f6f29a37e06bc31c723be672d54b45ed42feba74c0": "0xc5c184f0565e2192d6aedae584ee736cef875f0e1c558ee3ede26869acd0b4d60744617277696e", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf23de0201a5c3de13ca3540b4aa7802dd139083183c6b196c695c642c6e521ecf55a337cc2bd5df2df8fc6d6c0c7d49c7e": "0x845498df40e85e2ba9d9e213d1f476e7b147aab6a9098f1bb250e00251ef8f5c0233", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf23e2605e31335e2ca4270fe35a899521490f218ede5ef0e08fcde53a9913c8c01d7cc28d31d21d89071b6a8d9262d8376": "0xc4516751df2e5803bac3bf9cf7b6d55cf4acbd76f861ad0a2a2b71b7a5ed805407f09f98883131", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf23e75fc80d0f17eeb8214e932c319f810dc0ac1271ef05bf490a482a38512b68548cc3c244285635c32ed242b33d79dd2": "0xc5c184f0565e2192d6aedae584ee736cef875f0e1c558ee3ede26869acd0b4d6084861776b696e67", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf23ea273d4a190071d6fdb797818ffd8f806bd7c7a1535c6be092a798d558a5757ce89567f7cd939fe203163a8c4264e6a": "0x6ee5ad3ea0da40510f11f42c3281fd543f5a6bfad54ebef7381a7320bb509a0d0247", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf23ebba5b303f76f66c0b5a99aa006a1439ef2c74b5a6820a16eb04205a9d177c4244a94cdcfe1275039ef8704480a3905": "0x9ef2c74b5a6820a16eb04205a9d177c4244a94cdcfe1275039ef8704480a39050863796265724732", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf23ee00faf9f453ad7378336788066e8aa00247daf7503a9b41fb6c52c11c760f769266b44fa97bfeea3e0c68f0e3db04f": "0xc46ff658221e07564fde2764017590264f9dfced3538e283856c43e0ee456e510550555a5a", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf23ee0f7de312bddf6b51e8beff38791058ab2f02be4ea327d42477029cd7e8ca99a1b1ec34a9502cbf42c1701cdeee774": "0xa2da2913d7db19baf0a41dc40a73d75bc6001ce1691c3ded78e4e86387881b4c0231", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf23ef44fc31bdb69e29b9d2a4ceab48c96b5adad0de4385f3ad6516e39fd6479b85c22886cb0cb9fd91ce52919fec98bbe": "0xa763de880dfe6c4bbdad18fab60e27002f648c221df5248b7d44a575b4bc734200", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf23f0cbef457ce226c833eb460b5f12fca75a6c848edd2d131588ed2fb322ef45909d4aed3b7ea1197fce14220a68fcfe3": "0xc43aabf384c6baf54ef9712a96be7c46533b538c05d4e6c687fe09b109664b28032d4f", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf23f21975e0edf8d8beb4ac44015a4d67810002bfd652b0ab50a36adb9bc74163a4385c6b4ad8d3cbef794c07716ee0d6c": "0x8c8305ff8478e6309325ebbfb81e8c1883d39e65d2ef84f88e4a428615c4927704313230", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf23f23cebf0963a38a5c625ab1db9c035cfc44a7371ac4b798826aa05df8fd3cd5aa1b62f4a1a7cb9c95b7e83e99633a3e": "0x625a907225b8ed830c16996d75cda73ef03750b535a6d83ca2ba1246be2dd42416f09fa496206269742e6c792f7061796f7574626f74", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf23f36d3a747da18414e4ef43993219d4cf40703cb81f0aeb2691f6069bbb67a5a84b30d392b6c5906100b5a6cc57a781c": "0x5e97f331813198763da88ad2b1f5deb3f42373a93e8895c43de399aa6255da47054b413032", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf23f52876896e0a20445e445dbc940af4fe62bc1402d84b145bae2ce9ac2e50f7f613b7a986734a896af65be8f51244c4e": "0x3a81aea610fd2332295967d1c7846599774a112f2d6cf7e3ebe92392b7b177790ee38182e38184e38186f09f9a80", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf23f5490f034ae5dba86ba90274da5454712c0e71c4fcce3bde2baa598b4b4b15e3674286d0dc2c03441be1bd48408d92a": "0x12c0e71d326f83f4e6089448e147fdab51b0b7398a7d0cc9a88b0571432e7310033235", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf23f85806e0e25965e177bbdd90fefbb705a37c441df3f0fed7ddef5581ff70437b00fb071e0b09537caca8adc4354913e": "0x5a37c441df3f0fed7ddef5581ff70437b00fb071e0b09537caca8adc4354913e094e696b6f76657261", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf23fcfdc11ec0294abb86dd5aef563da3eeaf1654d9143d99dc782d03b496b3801e06a4c6405ae954f40b7e7475f9ddcb4": "0x1c6681030fd4860fcfc1dfad9ae55fc0181229b007b6365dc4c8f5fbe162554c033032", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf23ff37d7df58f34e416370d6f61c5cadb54bcf53ff5d97b41b38a3a5ccda86b3a3b1d7090a20747e2bdfb2cc46a38d514": "0x9c7c545141ea2dd84fe5ef7d567ea450f59967e7afa68e5f1ff7f7c46db19627033733", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf23ff6ef5180de4d2caa0e1267bbd89cda12c0e71c7daf0347415ea3623b1441a1f89b5115bfe82a57a132f72d186a2469": "0x12c0e71d326f83f4e6089448e147fdab51b0b7398a7d0cc9a88b0571432e7310033930", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf23ff8c3f77cb008c342242cf0f5b7a81c0c2fb774bdca7e1b4627e9af2a9a66a0b67e7164af0fa26f20781e4b5fa2dc42": "0xce5c65fecd7bb733ee636a381fa9dd916f8cca91e2e403c8aea2f7ed32b31d680e424c41434b4d4952524f523435", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2400d52bc4847da2f15ebb92c161aff8f78283798169eabf7cd6924745cb60df616354b36e53549fd8dd71e815386f525": "0x78283798169eabf7cd6924745cb60df616354b36e53549fd8dd71e815386f5250d45524e2056454e5455524553", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2405808113ad68224168753ff4cf07d3e086f2422947fdbebd39a68f8708064bd5d9caab70d1d6a51abff895db91f5655": "0xf6b21d624832094b03aa672e016462a020e217cc67b1434785b99114a2b4fa5a04763335", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2406cb41ed80a5299e6f17281fed8e084e2612e76480388dcc8dfc46219130946f276496403ecbdd37a6d1a14c35701aa": "0xc8d887817cd801c256ae0adad712737a18a89e23eb061b7002839d16530fa0d8095472656173757279", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf24171da74e75ab4be68a2140459a359b6d0accc7028daefa6de2f047e4650d3ad13d5e25bb0bf2fae4eb8ff8e21674919": "0x3674aa73951219dbd27b3e3fc5847b806c68c1de38fd4f22f9493a461c80e9030f535550455220574f5720f09f92a5", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf241aaa00e0d099b674905d2fa0df29232b53bdc896b61a0c3facca04307105b99e44841190d41b655c127dce9447ce2d4": "0x008d8404893c7b4b80f397605cc96e61fec3c89676c8c2794a2a7d281d678b1a0747414c415441", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf241d1714dce242e34ed024d261bb002c94e8c56b618a0c3750e9f005d58590bbd6b088c326a1fdb075294a8565b4192e8": "0x83c75b56557a84fe8261cadc0c308577b0709cdc54311afc5ec8d348b939f58906546f646f73", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf241d616e843f204ac501ad5ed7c39b27caa672cf29483bc35d2991a17f143213bba4fdf81050113c483cd205f68903236": "0x9c7c545141ea2dd84fe5ef7d567ea450f59967e7afa68e5f1ff7f7c46db19627033834", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf24216e006c2ffda91e61000d30dcd90a6e1cbdb5c7c39209793cf71d71ccd0a5eec8ee530069837073032da3ec4a5a714": "0x6c335d86444f3189027cd53244265047e52a96b4621fdaeeb9bc12857789867608e29aa1efb88f32", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf242499cdd4b0b387526e607e2c992123950d1a6eb9d16f107a16aedb586c8d08259b212a3c54563f183dae7e1964d931e": "0x8e06bfc989509d6d625c085209adb405867bdbe4f167ded7e61ec126c683165d10416c7a796d6f6c6f676973742d3030", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2424f2a95714746e854f8c59ad6890acbccc49a4cbcaec6b03737d84c907628a2cc104cc75ad817ad38292e5bb76c527e": "0xf4d95d4c5c0131969148d3a16b3d95ab3d051771d971a1955d7e745b0a3a4f1600", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2427bea476838de38dc1fbd13fe407ff51bb5e480e154b39b0e8e272ba015da6daf3f9f634fd357cd5f8611b29b7d4e51": "0x08a23d4b915d29be5d2aa20f36649e004c6ee8df393064edad697934281bd51f063157696e65", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf242a32fa84d9d0a0ceed103e07e2094fc62a791daef6863829ce7969886db050a38050dd52ed6c1a685cf7897e67f165e": "0x6a325e3630266fda0ef7f7725ef8199726e29d569d609f3cf068c4db7e82591a0233", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf242bd09558096b3bc5a5d0b4375cdbea7304e4137516cc6a906f03158933c2430744e602d6549dfcbf5a0d767358ae419": "0x62a79f3b924342c4f634d8ebdf77f50ac051d41387a72d22f2f38155762c125f00", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf242d5132ec9ea541df0aa87ba39094af7645c0ded9084b8186ef4aa2d83ee1c5ab326757267c41c05444e15c657438424": "0x9c7c545141ea2dd84fe5ef7d567ea450f59967e7afa68e5f1ff7f7c46db19627033433", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2434d1f1050ebdd3f71c9cf66caf7d10112c0e71c74bc9329f210cf3871cb0df4e3139420f8cd1260ed214f6e310d5969": "0x12c0e71d326f83f4e6089448e147fdab51b0b7398a7d0cc9a88b0571432e7310033733", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2435ed3017503d4c9faa796b59ef2fc8f322e857c9fc42bcd84f6f4e2d1f7f892baef31f1da5731d22796cfc40e4fdd5d": "0x9c7c545141ea2dd84fe5ef7d567ea450f59967e7afa68e5f1ff7f7c46db19627033232", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf24369670bd3c4a2bd4a51e70cf242e900d84e08c6dda9a41fd1d44b01b65c7787b48723679a1d0c83d1d9a54798ccf01e": "0x7a8b217ad8d80016336be124846210559ebf720aecd25ea0d0d11c10f1839e7105f09fa7a1", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf243b41e55c99a7dbd2733640313257ffec82d85d99021f559a9a4f5387fca2bee170d488b97e00766b5ad19617c52c17e": "0xbcb916e7a7ef77dd1f610ed27ec519b4ec226028eb8edade41f95b217f89f6200845766572657374", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf243ca307dd8b0fb706dac460ef965f751ecfd5be6a880094d44062af80777e61f10e15d6a8910cf7222bb10dcff874eca": "0xceeccdb6802df2253998f9d4f928b120d51110d1d2afd969b95232bc167687020e626162792d6b6f6b656e616b69", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf243edf09e07e0b49da67583ea78c544158e2499f22749aef04333796fe92b73c06cf4e358a552604ff3e550725774f924": "0x3d6d2d20735ec00c7753d3e6071ad1e2280288a98d7d89c2a2b7fe08bf6d05bd07576f75746572", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2441059018251d8f7bac08ff27f40ba5bd7a7116db2d1bd9dd4c7b37c204dc775888f9310a1a18877ee913901bc95281d": "0xc8d887817cd801c256ae0adad712737a18a89e23eb061b7002839d16530fa0d80c536574746c656d656e7473", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf24452eac7d15a4caa1515fdcab047ca67b0820d7db40e2a9fe96c7ef2e810cc51a7da195bc995f329ffde72fae04e7b3e": "0x9c7c545141ea2dd84fe5ef7d567ea450f59967e7afa68e5f1ff7f7c46db19627033539", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2445eb2c87a3389c40f9db79631e28362a08c23158a93a3aa7de94d3ced1c9e1b4ed1efbb1e29dab0363b1c8ca4904e06": "0x5c3739d60301126756a7510e34f9d656d4435cd4fe64bbd001f1f3473bc9c33304563031", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2448cf37c141500505ea658232325c94412c0e71cf41a90f7205b9034bdc9380a95bc18669cd5b4d6b9452f73d468e74c": "0x12c0e71d326f83f4e6089448e147fdab51b0b7398a7d0cc9a88b0571432e7310033038", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf24490823f910054ad342b544618de7e4d545e8064f8898a29d4811e09b207cf3302e5cefef16615f8580fcd8fa63a624e": "0x9c7c545141ea2dd84fe5ef7d567ea450f59967e7afa68e5f1ff7f7c46db196270231", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf244e69355112f106a0108abd7c2b1039c83b401968c58e31e421f96e07dd85ce91d985abbccc84bcea5e8f098d97fab56": "0x6610a5024c2a5db3d02056d4344d120ec7be283100d71a6715f09275167e4f38033032", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2456e2d8e634a3783313096a13937da4012c0e71cdeadb03446fd3519d1dcd4f690e40df4ab0d193b476a94a0b6588c28": "0x12c0e71d326f83f4e6089448e147fdab51b0b7398a7d0cc9a88b0571432e7310033436", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2457b91c185c520b91b93d213b77b021d12c0e71cac0a27a2fd30bc24907dfcf124197d52af6e9c9506f5bae59bf08879": "0x12c0e71d326f83f4e6089448e147fdab51b0b7398a7d0cc9a88b0571432e7310033337", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf24602e5792f844968dd883366d34e6f36c6645597fb2f300ac88b96e8283b06d99319905bc509151e03dc83748708197e": "0x5e1eb942e5f591bc1d902fc6a04dd7ecadf5f4916f2597df0505c6c521412c4b0239", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2462c8d5d6a95e7b844524b1286805b3af20ddf4f2db1f9f800d70ce19dee3812a5d72bc275f413de1ee186ea7473bd18": "0x7042479798003022a5753c8547cb0de8ef25e2471e40889ff3909fe714e24c5d033032", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf24636227993340534dec219349d721d3486d678feab565ecb54f78dcca7036db237002aa86783283b8721de7611d7fab2": "0x2ca8e96b721f074e95a3f7d994c370dab688fc85134de7e2e7d4589d0a306c51033032", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2465c05d754aee83ce22fc6daf8fb9f3ff7034438a748412760539f824f38f3f9ecbf77ced8716de97c5ade5d2444c8c3": "0x66fae573cabe4172bdfc60dfd00dff703a4323854715c151f868293db828190c0f4a61636b20456e74726f70792032", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf246644d0b047de0c1a671d2da7c3e2afbc6a8eba5ee9f02ca31a31bf5de2dd406adc9c55df94001f6efa28370b154544d": "0x9c7c545141ea2dd84fe5ef7d567ea450f59967e7afa68e5f1ff7f7c46db19627033131", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf246c867310f374b9379468cf750904427d07218db071b0b88f5979d57b52ad2b7706856f7be0021d30df75fc9ecfd2f64": "0x9cb0d4ddd32f9332dac7059de238b8e489afb55502d1756d7f50b78b58e20c700232", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf246e6648c0eef3ebc76337a2a651e7f66faeef086f38d55942fa48bacc018724b488f46ecfc2828d879c7b780c8f57b0e": "0xc07040b1be7aedb10ffc0f136b7e147e4a1ad56944c1c76d6c2f6ca089cf316b033032", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf246f2c5f574f732e90118cec8ce8ab2c86a7db4fd5d907242e97c2db57fa12f1eff6a103556f8e99f916483ac6674c372": "0x3073c378b0833da59cda1d49d711f37c9ae20ed30dc3dbb842ead63dde5783310f464f524b4c4553534e4154494f4e", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2472d945308c6256e7a670fee7543b716fca8ea3766270fe9df1ba7a4a7298a908878ed61581b9769100fbdd4164b0060": "0xa845ea35913a0fbdec49687ebc5b1579bb632c080ce61b02919ba40bcf8892760233", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf24748b70df7ee0fcde2805f260815158e6ca5cd252f0f61e8a9c5eb72ad6d9452fcc1de451f7bcffe04cee9ce73c8ff0f": "0xd453b6e497b6a89979fb34eea715720d37c2381c8c51458be04296fd059dcc3a033031", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf247bbf49bc47c17666baa2a0f4bcca5b38ff2fd995727bb6c776dce0c1e127955c1f191db6aff56c434a6738fc83d4eb8": "0x7a895955042cb3fe863f3564e7b30e9130e37b6d905be11c0cf91064de1cd83a033031", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf247d268a008a09e7c814a5aefc77010b5c83b05f03d7e0511d29dca7a11f3631f6a0bf373ee6f96bf99882421dd261a4b": "0xeed08a5b10b1835610d66ce4fa273c8e2436b978c9f65442efb6074871b48a6a0231", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf247df7ffd2ae80267570cf3ff6085dd3326e1393aaa4e42b5d40f234eeeff068825d5cc50a3802e8e2e488694527b5e7c": "0x8adc4e19e79b3d2c744f88fa5aca47ef05ccaae141f6435c2d50df824433ae480235", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2480f693230d05ce7c07079ea1a1a47d0d2ec0a695435c6324bfc9b27dff217e5092e2972b0123529514006e278914c7c": "0xba0518b2408a0883ce26ff4ea90f8639ac05332bf82260fc45033d7b5baa0a200231", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2485cb150126059a2b59f09fa05f9f39c5059875dcee1d4a9908203728cea5bc20ef93a366beac56fa161e04feca03443": "0x1eb38b0d5178bc680c10a204f81164946a25078c6d3b5f6813cef61c3aef48430c7374616b652d7374617368", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf248676b154b078b376f7179f8d45df23212c0e71c47eb3e0eca577bc8ce7ec63eb978b1e36e73daea0449935e5496850c": "0x12c0e71d326f83f4e6089448e147fdab51b0b7398a7d0cc9a88b0571432e7310033233", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2487a39066ca8313f9fc0adfa2e66c257d4c6173852da2969c43006a3806502c5f6bc23e1f3e8d5507baff2b5e2f1774e": "0x9c7c545141ea2dd84fe5ef7d567ea450f59967e7afa68e5f1ff7f7c46db19627033233", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2487c1ea83596ff698ee5c267bfdf1f2c8c6211892518630b6e583e09dd395211035a508358a80322614f9894bdceb605": "0x88b9f3a722747e8f637b2583963ea7f1215adc8c75c3957554fdf92fcbfa50340853717561726564", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2487ed75c2026a1bcfada6827c95c445442e37b2268e7e97d6345f7611dba1f4f58baa27382b87cf536ebdaa23c3b811f": "0x9c7c545141ea2dd84fe5ef7d567ea450f59967e7afa68e5f1ff7f7c46db19627033931", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf248b792e5d55ceda46fa27d90bf02ebd3dd2404caa71709d521271bcd64cb771df96abc1454c1bc2db5be8fd84f9f317d": "0x6610a5024c2a5db3d02056d4344d120ec7be283100d71a6715f09275167e4f38033038", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf248e0f76cea4a67bdec390bbdd0fec4dbe4dc1df8790688cc413fea804c4158d1142db0312e091578306e1ec9fcd6bb77": "0x48ca001326b583070e370be3bc6680d09cad47649584a5c992bd388c693b9a54033031", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2492e02ccc834cd02f4f10c1af60f8b706cbed2071a6b6848b4d170409de00af2da5ce2245166c9a5c32ae79fcf44876f": "0x9c7c545141ea2dd84fe5ef7d567ea450f59967e7afa68e5f1ff7f7c46db19627033332", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf249abac528a6bdd59d4bbb34a70ab50f21a2b2effb22453209445e66e170f7beeffb3b66c900fa8fd49cbe9efe9eb4942": "0x5270ec35ba01254d8bff046a1a58f16d3ae615c235efd6e99a35f233b2d9df2c0bf09fa68820534841524b", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf249bff4cb902465a1f5ba7fa253223c4bf25f7a8dd6b648eac453d60b0052dee3cefce2ff56830eb7cc98292c8885f958": "0x9085297d964ea873a23b63151b4c82189c1314c31fda6f2d71f83133d0877c5c054b534d31", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf249d19d0b0439f08373f9bf84936e2057e57259886f2db2014f3bcf26e8baa581816f49c13e010bff9f52d5d9ea3ae68a": "0xd3754204488186b41e90a93d0607992b9cb992932ff66c2faef8a984dfe4a2340644656c7461", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf24a0dbb67dc3d6cc94f0995925c189848cc4790e6ee2ebf4271fffa10d4bcc2a4460ab377a49ddbedfbb647090c6a97aa": "0x76016fc20a6457ff8953bf29686c5698c28bbfa860669ddd07b386c910f1107d035631", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf24a30e50780aa2b2389a6fb3266118da5f67795750255b9f9c19a23a72960b240276a404d3c5fcb4fde2cf5759e88f704": "0x74422321a842adfae9419ecd3983c4fa2da6e879ccc1db031e54c742bbb9bc030231", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf24a943623aaca68cff5f3c9cc784bd3ee22b6c1ab9ef945b7279a730423cf50ca4e25feeefd4953abdc0fc8caa403f70e": "0xce5c65fecd7bb733ee636a381fa9dd916f8cca91e2e403c8aea2f7ed32b31d680e424c41434b4d4952524f523135", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf24ae3d3d666ae697ff8678369655c590dc94a444165f95b45857e4bf1c4b0f784eb2e6f16054a87dce443de41c6d09c1c": "0x08b3b1930f36bf7fa336c7abc044e75fea45cf1c903081e7e0bfbd664a80093a0232", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf24aeb0d2ce707eab19d2c51b7e33da6486d6f646c70792f6e6f706c730163000000000000000000000000000000000000": "0xd6aadb9a7f66a45224f6f83011f854c0b5758c626b213f97cbffded94830507d05f09f909c", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf24b1c57136faa1b6758e7628008d14b7e5c8bb12c78741c7b0ff4659360c78bf5da3af34e842a60f58e53045ccb070302": "0x5e97f331813198763da88ad2b1f5deb3f42373a93e8895c43de399aa6255da47054b413033", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf24b2797725c20d711c01159e65adc42f44ed4af096401134ae34367a42cf8bb5da1d3c878fe08b512baf5e9a4f7e9bf43": "0x6069548e7913a106991a40988bd63d25996d6788f9302ef0a86ec40b4e6bd36f0231", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf24b4fafaf3feb5179324fe3643c74cdc354e0103cb355b3f6f357104c4cea54675909f687aa106a4e47d741dfde35e376": "0xcea3dabe52b2a665b1e19bf8c6913a5d54e06d6413ca3ddbec8f9a22415ec47711416c7068612043656e74617572692041", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf24b90b65f45d20d5fad5463d00f0112ec0f6987ec94f7c186a7c76fd7792be048d9e73494daaf0f86245f2f68cef20b2a": "0x2e69ac91dc2b3e54afd2d74736e7dfd95faa1e738dab066c80328980c7c9076e0d426c61646552756e6e657232", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf24c0b163e0fc8f18feb22619d1b45a5ede45d4839be5ec40b585c1f08ac284e656075327d7038aaf795d35789ab10f15a": "0xce5c65fecd7bb733ee636a381fa9dd916f8cca91e2e403c8aea2f7ed32b31d680e424c41434b4d4952524f523335", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf24c38722755eaa48ddee7115903105c0f30cca6318e5c3cea1c72f33f541532ab6609b50853627fcd587bd5883d52f75c": "0x7213534fb02c7638d8d7caf1f62b983225c5aa76b8c14d249f7a704b50ba850a0231", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf24c5b05db14954da4bfb354ff674c2f34703d07f2ac096e6b0b998fad5997c7c9b1e1f417603c350e76ad99e5c19aec04": "0x9cb0d4ddd32f9332dac7059de238b8e489afb55502d1756d7f50b78b58e20c700234", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf24c7ceb04eb2bf9b9876b7a27998fcce5f2ee0d3d7e3d57e18249e42d570e163d7f34ac68e81c973b41bfa521f2e99e0e": "0x3c7f40746d04d77628d886dfd469c9bf606232dedaa248f5c219d32da93f4054033032", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf24c8b3f5740c3eb6a6128f0a0a7614c156cdac27581d1f3929bf543452b7da444e03457ea6424f84ef9a372ecfda077ec": "0xc0b881e2db47fb95982cd5c364b87e6cdf5a5c8a336d980156623b53815c597b033138", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf24ca011902e6e9d2b02349d69c7c09d462c249c9b361d3c490f66848e4ad2fe71438455108b3a1f0698160c6d1d27fb24": "0xd20f2ce6c2c876745bbb399c6290cf4e3ee75ce31bbc7ec11342fd5118b98e3c035842", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf24d2c909b13e573d0f96340bcc560415e661712f60a13d05e0c478d73f3a2dea9766c5d4b54a84895ed8b7f6a3f950614": "0xce5c65fecd7bb733ee636a381fa9dd916f8cca91e2e403c8aea2f7ed32b31d680e424c41434b4d4952524f523333", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf24d4c23aef3f039771889d31878ec41333c982ec4375d3b3e9c950f540316fe84dc53191424fd073613cf4dea51cd156e": "0x8c8305ff8478e6309325ebbfb81e8c1883d39e65d2ef84f88e4a428615c4927704313433", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf24d5d05fbf3a4df1fbb2ee0c9d6b5069818a06c67746e98a3cc1680079a706c133d5e77d0c8721728cdd7c8525b42b752": "0x8c79cbd600c63f0cc90b34e7301b7cef8c93f7a404cbacecab96901fe53d46400232", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf24dbb206d3bcc537968224ed4ecddf0706d6f646c70792f6e6f706c73014d000000000000000000000000000000000000": "0xd6aadb9a7f66a45224f6f83011f854c0b5758c626b213f97cbffded94830507d05f09f909c", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf24dcae1b443519203be02a76ce2b1215410a89401749948f217611353ab25e1789474699fc06ed1dbbcf44b7035f48875": "0x78baec43fd49badfce811cbba08b3f0ccf758b5e22f0c4d745452f5dad6eee072020726577617264732e61706572747572656d696e696e672e636f6d2f6b736d", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf24e04bbd20b41540666f251d09ae526c10600cf06f1c8e912c9d968f1de9fe6ed32d033b8e87bfac698602c25604e2b4e": "0x8c8305ff8478e6309325ebbfb81e8c1883d39e65d2ef84f88e4a428615c4927704313136", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf24e2a67fa8f631129a0bb9461eaf8465f3eeebded302e53d488d9b063922447cf63e7638e60abdce4259c72dec9126a35": "0xe2a0a933d2b1e2dfd0c06baf42557bf4aa2ad84866859e6c869733d6baadf1520c637279707465676f642d32", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf24e4d8f095e102658385486802970aa4254f79360caefa910ba4bc6e26760fbd44a07a9fd4244c6fc7f58b0ce620fe15c": "0xf6b21d624832094b03aa672e016462a020e217cc67b1434785b99114a2b4fa5a04763132", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf24e9cb3de883952c0688831aeb26bdd9bf60f07a15346b938937e245a9bc5f757c0a516b249d11c40ba8b0742109d573d": "0xce5c65fecd7bb733ee636a381fa9dd916f8cca91e2e403c8aea2f7ed32b31d680e424c41434b4d4952524f523237", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf24ea43ddc5cdd8cfb0485d7efd8f7ed754662cd48d69f8c1441434bc2c80a825ded8eb41d2c360f6ced694798678af7ab": "0x2c5bca9fd4c92b051e35c47617175d8f28aba000ccf921cb24bdf555662f2d41033031", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf24ecc547cce29c45f440503d562517d9ea8bc182820c46f4dd6bd98b76dbff06f8565f0004eb1a9840ee3f3bcae1442d5": "0xc0b881e2db47fb95982cd5c364b87e6cdf5a5c8a336d980156623b53815c597b033038", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf24ef5bf1ce1351b456611366722a8515d08d3e6f92d4020b4a2a6d4dff33fe485f2883070668660980fdc064f12dcc129": "0x02302a200a9ead164617576a79dded74ccf9094d6222cdf93ed575422e9f5837134f6b74616e6f646573204b7573616d612032", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf24f17cba3fd8f4bd74cb6a2f7101b9c90fca5925e677ffb072b404634eb297becf53c269e32c7393c9b9dec8d256dad21": "0xe26969331bf77ce04768009026a5362d51e5bccc12f788b8cda2a43ef218bd040848616d62757267", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf24fb8017980417d688bf198bf773aed92513b35b8d169fb8f713504d252be09827c6e9fa2197df14bbe563efe67af51d6": "0xbc486ed2f394da6e6b58b130687b48d3d19f756ba6d0655d37bf58ff0f59f9740f53746565626572204c6567616379", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf24fc60dfcaf236a03848d0e7d3f2dee82fc8d39aafef0cd3cc978a3b1354b65853a12b9f4ee0a55af14311a4de76b7b16": "0xce5c65fecd7bb733ee636a381fa9dd916f8cca91e2e403c8aea2f7ed32b31d680e424c41434b4d4952524f523431", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf24fd2e33d55a8d00d82a2b2049384f672a83fc2798fabbdc8d93db99a27dda9b8f6615cfef0b16a3a0aca93a49e527475": "0xfaba4f34d61e2defae2db1f7c712007824c194ad921959efdb4a65dd174a590c0b776174657270726f6f66", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf24fdfaac0ae09eada38716c0b3212ee71407201429e0f6beb3a79213b46c4f59f002ff4da66dbb0bfcb66cae1cc1a5074": "0xf6b21d624832094b03aa672e016462a020e217cc67b1434785b99114a2b4fa5a04763331", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf250794acaeb679fc61e80cee158ad5e26b3c0b3afec6c57fc99dc2656c38ecae97b5c01f2d44bc9da56714141676e3ff2": "0x5a5f7eb7050fb96d8d7895d9afce428a064ce66e3b094805bcad9a8e68cb99340a43524f57444c4f414e", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf250879e5c19596eafbbf169c0b7fccaeaaee302e198305536eef798b55edd01e28516bfd2d16888597da705ee0e74df0d": "0x6e99996cc6c41e39696f7c3bc4248e548473b68fe2ba26567771be07b7eb5b190f466f726b6c6573734e6174696f6e", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf250b6a9fe615c653477e3366ebb08ff9c64f9e43cd95c94ded79fa17bfec8a8d745932f4d7679f8b06aa9e13f915768b2": "0xf00168a3d082a8ccf93945b1f173fdaecc1ce76fc09bbde18423640194be7212083035f09f9a8020", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf250c5e58a66490b175883ea10bf3c8cbb52e2931449f8d897dd10fe7f753414821fc90698d940050169a863db5093bc3b": "0xc229d8ccc5e5650d17760ce2b7c42bdae5f6afc6e8bab249ec77f3f779ee5a651331343a206e6f64616d61746963732e636f6d", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf250fe3047b874e3c5579f29b9e784955f6e63e1f89c023383484d1f16ea1d9fd66d46387f929dcdada62f8e5dcfcc9221": "0x2e69ac91dc2b3e54afd2d74736e7dfd95faa1e738dab066c80328980c7c9076e0a56006f007400650072", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2511494b67f932149a18b93e39dcb486788d38dd7b7e450c426b33bd49db5efe92e702e0c799a5adab42be4fb21ed7566": "0xaed98e15e3ed392e38654215c3d1fa8143de53460386b60139fbb45c036c1b430653462d3234", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf25124fa226ff059a10fe8f24b98ac8b501aa9d3c51f17264aea16d04dd1b899fd311853b2bb2944487ac2c43f1e304048": "0x9c7c545141ea2dd84fe5ef7d567ea450f59967e7afa68e5f1ff7f7c46db19627033934", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2519c4e21e4012a84648aed8d8458e90426acb4e6372fd11f9cf419b845964385848977d6e37b6221ea9d69d58d27d623": "0x26acb4e6372fd11f9cf419b845964385848977d6e37b6221ea9d69d58d27d6230e4c616b6520566963746f726961", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2523d931d34550f8428bb0220ee5d879ff02cd6695698754c7d8a82ef80e87a7c753c95c028557d15c393b9955fe74151": "0x56d629a2c80762d412fad9c15d8cc973b463f600895170d43a10ca504b4f454e16205b32325d20542e4d452f4b5553414d415f424f54", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2529b051995d03c074da080c5a99828db98cafd75bd233ed0674c7493c67d589c4d7e78b69cdb409ca66c0f3a7391ec06": "0x2cba024614ea8ccd1ebf7a634f30b38d65c082be6aaa92551b9c3b4d1f15ae6e0853657272616e6f", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf252a830b1ee63ed7d3f89561c6195b3d6b0495e49f3241a065bbf17983665997e582b1535c5410530897e3889993f711d": "0x1cf3e5e0a3f8f198a63f5f7284fe493c23e88161d92d2cd418e52d050e3bd22b074d6f77676c69", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf252e1519060862ad3aeca7db222e2424e12c0e71ca3fd568c3120f3c6eb7825d957104fd5e9bd9848ef36a1d5de03b008": "0x12c0e71d326f83f4e6089448e147fdab51b0b7398a7d0cc9a88b0571432e7310033839", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf252fd9557943d5bf1c9573d3ec3b6a98b4e9807808e2487f1a38ae21d64de700342dd7feac9c23a7293da4687e668e71d": "0x52e73898bf4601f9c9a7fa052de0cc313b159dd368d458f4cb0341eedcd6d818076c6b736d3031", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2532ab6f6fc026d4a6643dd68667133ce10230b53a6fbe58eb3eacc65cd3ef675e0456529cfb02a97eb43ff93bb6f8064": "0x0277ce02b2ac78ceeb9ae4fa0a595005489bf3f5f77898415e32a3e9504a531418546578617320426c6f636b636861696e204e6f64652032", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf25346ee68fa23361590f60872e6ad00dc15a946a44e88eac4fe2568b67d675983e9617e83d70d3ad6d9ec28707203be7e": "0x1ea86f3c82538c486a25d8abca26760e57e76a01212419c7f1c8b510121fca73042d5142", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2539271040b3fa17a151e18555982ae3460a8e45eea9783d521beeb12cb15c6e9094e5d755749b801ff1a532d0934a90d": "0xaa2b3e0a8702aebcb83d552838a17902b2403b0f16c4e52a4514fe02df532e3c0d303220f09f90bb2042454152", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf254338a78024ae39674bdddb5cd6abd43ea00a7167ab2ecc7f024e26e62a15b24c02f0b30e967cb91621169e3c780ae4e": "0xb2636043fc3b8dfa608167a9fb6fb9d065b9f2f5821dc4bfc9785a244b24a92a04563035", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf254f3e98bd9a69f185f1c099c597a8365bed497470a04ca4c13caccd69c7827e3ddc64473fd2d7c5d496c71061f452b05": "0x6467fd4e7038b925c2422357380d8cc0c5f17d272f639af8fcfd1f1156de704023d4735e3a265e16eee03f59718b9b5d03019c07d8b6c51f90da3a666eec13ab35", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf254f577657837a4e532147a687f23213f83dc7edbb29fe81e5e29f18ee1c35a90b6aad5637057e3087699d38e7eea7394": "0x3839e4be40e252a56e2d7c8e89a0c8eb990df5910714fea61c6e1d3b1c4c550204303339", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf25530d6e304ba2f8eff835adb61de17793c5862ed65c524b7bb3564776a81904218f44f3d7c35162a608e39dbadbcda05": "0x3c5862ed65c524b7bb3564776a81904218f44f3d7c35162a608e39dbadbcda050a6e40544b6172757261", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf255316268e460368587259f3f3af448352ecadcb36865c859f998d5538bc2629b4f4aea6e03dc4cc110bcf0eea4e06330": "0xea6a0804e0024beaa87fc072eb250446162310017e52147d18fada54a8ddb57b0234", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2554e5c145db815f1f77e40bce8d396b6d41ef941dae80043db2c5bcecb8501ff3f159ce810271ab6fdcbf979de7cd373": "0x48ca001326b583070e370be3bc6680d09cad47649584a5c992bd388c693b9a54033235", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf255833fcaacae3503dbe52b27182d70a80ad8b4f94dc8e6229e2c448d995094cdc1bd356dc14c6155467ac07ede18b872": "0x2e69ac91dc2b3e54afd2d74736e7dfd95faa1e738dab066c80328980c7c9076e0c426c61646552756e6e6572", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf255924e4e69574c0cdab46034db8b6f9334fe2832004fffcc1e28aec7ac35d29142b892f10d8d0c301cd26c37860a0579": "0x0cce9e210c473fd1f20178fe889c178956ea1cf325c54b1a439a88bc62fe7851074e4f56592d32", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2559e7c86d0691c4dcfa3a682743b0611063e0fa2cd4f4b448d507f9d5b2ea8c85e8947a93d92d214be8f4b752807886e": "0xce5c65fecd7bb733ee636a381fa9dd916f8cca91e2e403c8aea2f7ed32b31d680e424c41434b4d4952524f523231", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf255bc1197df809de11d807374b141c3eac99cae7c82bcc7d4c6d39b376a3f9a61242bf4ff1225866f5f93acbbf8ac922a": "0xd65d5c1484e5faf8ad32907ab729add8ffc2ffe0f29bc18015bec2c3f8ac7c6604303032", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf255f6e7b996756cc74c600c7dd197ff1066a4ddefa00f74de69a30bb8f6f87c50cbd2804768c367f3fbad5663a98fe48b": "0x1c6681030fd4860fcfc1dfad9ae55fc0181229b007b6365dc4c8f5fbe162554c033033", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf256318734facf3f8a10bd6cf2becc981412c0e71cde22f076b79de5a6fc30cd47be3f5629d4be7fde35d769e7480f4911": "0x12c0e71d326f83f4e6089448e147fdab51b0b7398a7d0cc9a88b0571432e7310033638", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf25671790e3c7a701b2517fd2852b03e5712c0e71d17404deaa91eca3e64e911f5e43ebbfb80fb21f97c4d453ed79bee36": "0x12c0e71d326f83f4e6089448e147fdab51b0b7398a7d0cc9a88b0571432e7310033535", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf256752f9f8d5ce6b947829aafc1b19e944e1f1d2881471357ea697093e5e68d46712d2b0e5b650945c4ecb571ea43757b": "0xd6c29a7c39cee45b0e045a94081bc188ef73be2be086d66aefd850fc7eeacc45164f6e46696e616c69747920486f742057616c6c6574", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf256819e69d1b4e0465ba4450aaea081ee1a746810bc697bd6b464f5115aef1127130712a70960abe590c8a6491f432232": "0xb2636043fc3b8dfa608167a9fb6fb9d065b9f2f5821dc4bfc9785a244b24a92a04563032", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf256a45fb05964445f6dcd067c402615abe69aa84285f761bb1942735db2c3d443e29dd3f3da5aa7a00038bafdf93abc57": "0xb2636043fc3b8dfa608167a9fb6fb9d065b9f2f5821dc4bfc9785a244b24a92a04563033", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf256d701a119a1507819cf606313cc66cca82cd9ba02bdf8241a35d6a434c019a6078547e238df7a55c6dde5c4deb2f12c": "0xbc63ced3f8fec642128f2aa9c37e989a9313a67e9635dd85e8bd689ae8d0ce1d0232", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf256ff03eaea16c8ebf5d4c014efdeee2e166a40c58fac1476b58784d0ed59ae59fc516a4b072ba8daeda31d638a53023a": "0xc4516751df2e5803bac3bf9cf7b6d55cf4acbd76f861ad0a2a2b71b7a5ed805406f09f988837", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf25716b10cfb50c5acef6d1a0858444291e2af982fd853bcdb276d9be46e6bad4cc8e1af153d82638d2bc829e6ec3e2a6c": "0x0cf88657e8a5e5005c67c0ae58b0ea1137b817f32d30d80aba618a70b13bcc6605504f4f4c", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf25716d5eb2b434059c3a47ed674f3c80e41593cf289a037eaf22bfa42c5f10c5325340bd4f488cb37fc72f65cb83f51cf": "0x44da8d011a0f821b2e39d6151f8e17c417c0e09b664587dfe2021a194ee95d7404303334", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2573b583b387a3bd826c32978ea0ed0e8a9c13c25dc960c282ae2a76f4e315ed20c60cbdd08750fd45cf5b2790f7ef045": "0xc0b881e2db47fb95982cd5c364b87e6cdf5a5c8a336d980156623b53815c597b033131", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2577c29443c8aa9c98a578dedce880fddbacafb0ea22a692dea279a648b8cb44649ca71629f9fce6d69e03a4869cd9383": "0x3c1db08dfc6786bee3b0e1b4aaf51e80b6f2ec9badbe3da87d30ad7605a2bd1604303032", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf25795523df7d9eb4aab5fb0b8b47f2a921f81e872efaf12f97f5a40b31afbf874bde9c0225e89511734f749b4b1d680ae": "0x8c4c81f382ae2c201eed4b0b519f352aa9c0c8593122418b30ac9760844de2fa0233", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2579585ee165f6fb748e8232dfe0d0f2ae541547dbea2dac6e485f82ea71b8b1f6fb6696aa65cab783b20f9a6c574e644": "0xa6c5f0595d6ed85d6260bc682d4a68a4b4e605d43c67d56f2765d196985497720b636f6e74726f6c6c6572", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf257d195f17fa6af701e4f6105769471d19406aac741b57c529a2b06b06124a2a9b8f8374e072e4b251b13a5c0cc9f617e": "0x5e0a4ca74bbb4da39c79954e7875519fa67049795c02a360412f3ee41a020506033032", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2581e8ad688578056d036cdf1f8d33b8520f949b07ac91763cef16c15fb78d5370271add31799ab7ea2e940a89af4672b": "0xbaf3f15b9e83dcfc18b50fe91e601fdf446c008c72c3d17799c21a64877e8d3a0b436f6e74726f6c6c6572", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2584157afddf0916a8942604846c9d7108688b96ed623770a0b2712dd9661b3c1280da83237db214ba698be7783731b12": "0x482a9a411b630d2c3f850f435c4566a6a93143422e6cce181320f022a74512360232", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2589cf380e0b82377485dcbba553646f4acd510542672c65c7c05d56c4c6424a70a0e426f3899f2eb86751cc2e08ef124": "0x6edfd181c979c11a1d853c8fdef7b18e85ec39bb67ce723130b25fc24232c3580f466f726b6c6573734e6174696f6e", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf25932753fa6c22debc1bcae3c80c551ef0650217af71d75baa1bbc577761208886a474cfe4c24435b0295586f2f66a571": "0x7a54e6a55c0453407909789a06c3ee6719f8735ac370d6f17dc342717fd76819033032", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf259867bf87f39d463de936989455b2e82603ebd73cf850b644af5650cc070cf1328601427c712b21aa9746609de2ad447": "0xf2d0eed0f21b82d4b15802153cde2a229f257f01d003694b2973ef785a7347660c416e6f6e7374616b652032", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf259a5cda96b7e066af61a618e2ec7113f106b2d295a9a3de6efade304e1efcd123cc66ec27ec92a075964ecac7229f54b": "0xce5c65fecd7bb733ee636a381fa9dd916f8cca91e2e403c8aea2f7ed32b31d680d424c41434b4d4952524f5234", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf259aa4b30d635834bbe3b17ffe590e01bb08c0a54f1f153adae9df1b746cab08c40e3b949cf2458f80ac43ff256f2c17a": "0xb8a40f17f9fc62194fe1b12c10e8a2bfb5efc7057b119f4ca3b05ba96eb7da6b105354454c4c41524a45545f4e455854", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf25a19a249f9a9acc87e47c4448779ba642cbc13e6be77e7af272d495780c1b51130e27e41e95d8d651733b53630b3900e": "0x2cbac2d6ac81d2169fa6e455b0497cf0389bd5dd2a11b24a53e6d94053765a7700", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf25a31cf95fda855a49f008d4fa2ca66f8d2f17cc6203b5746b14c65b94077e29f02d0b1d56a0ba445458c2d7cf9d55a54": "0xf6b21d624832094b03aa672e016462a020e217cc67b1434785b99114a2b4fa5a04763339", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf25ab90ffc9708d1a3176157121ed81a65203fade9dcd70e45da97d67ec48f8c5d8176be2e27cf3a612b6d6d7473c05577": "0x76739ac0320c03658b64366855bd6ab037488fb23fa0d183f53b989106e25a2d04303239", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf25ac5336faba0796609159ad9c88a24206d192ca910ffc54858d1b7f553cae619803b55c69af50ee3bb1846f1715e6db6": "0xa763de880dfe6c4bbdad18fab60e27002f648c221df5248b7d44a575b4bc734200", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf25b59008062bf10ecaec566e66e5af6531cf675676957827846bdae1e0518c92b31a6e0759b3616955445ba3cf8a8111d": "0xae9749dfdee466ed67835efa51f04d74db27d75e919d7050e4f5b7f481f77a14094355524154494f4e", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf25b6e148db97bae3ff6e9959f16d4cfca72020fdf0cdf3cd952082b52fd11ac0df4cb360850efbe0d096126efeefbb6ca": "0xa26c51051a9031ebcc5ae2a4eb9a72e444a5bff59b995ce4612ed8cabe8a2a700e4272616c65205072696d617279", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf25b8db23b5ce4c505699e41e822e0455e4e3bd152d910b6c892f23f85469cd64bef5d7561d69475207c60f4542cc1257f": "0xc0b881e2db47fb95982cd5c364b87e6cdf5a5c8a336d980156623b53815c597b033034", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf25b982a12cdee42e465dbb9a6466dc88e92b53a95c31152cb0d95a968db4dc8e14cb7f4495f4b3215db38d0fb6b8a8287": "0x83c75b56557a84fe8261cadc0c308577b0709cdc54311afc5ec8d348b939f58904424f54", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf25bc64ab2326698f1348a2d90fe95f824868615ece4f03d149458a8a54f26f7b3992f687e066d7c50e6713f72dcd6285a": "0x8c8305ff8478e6309325ebbfb81e8c1883d39e65d2ef84f88e4a428615c4927704313134", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf25c3f8ab5a0972dd662a3e2166addbfb0cc710cc1444b51d4cb4d22fc47a446df6d8371a8831a515040a52d7cea1fe70d": "0xa0c077265fa8ebb05329c968fe13efc415460cc5c379fb392a652ac07c9c2f7d033031", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf25c54999bc9fd8464af0dbf1573af3117e2e0c7c189cf04f3600624f5fed3a2107ab6ccf9625663babd571b492bb27cf9": "0x08a23d4b915d29be5d2aa20f36649e004c6ee8df393064edad697934281bd51f0831436865657365", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf25c717292043b8b023d37d0055112c7278ca5a28e878867689b757883005b39b269cc76cffb757bc672bd9cb1874cd505": "0xf6b21d624832094b03aa672e016462a020e217cc67b1434785b99114a2b4fa5a04763338", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf25c997a05fcaae1f7f8c43f9f6d36f666ad3ef6399e4bf49bf0ed9ade88ec40ef21be714cf9efc112306cc85c194f758a": "0xc0b881e2db47fb95982cd5c364b87e6cdf5a5c8a336d980156623b53815c597b033137", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf25cace6b06122487f6899edcfde030e4e9e992661473c1dc00ad7f67b734bec003561ebddbb7fe0db3759b717ad20fd25": "0xf01c087c4a752cbf56ae4672f910acad4b234a830818356b8378afcd8e0423600c534158454d424552472035", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf25cb0e538cd996389baa4717389419eb9b4105912d0268f239b12bfa0aaa290903ccbb52e0ad2126b73a4b20c9189bd1b": "0xa845ea35913a0fbdec49687ebc5b1579bb632c080ce61b02919ba40bcf8892760232", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf25cb2a48982d22b1a6679694abacd9244bca1d58132476c8e285668c7c1505e248d79821cc2244724f026d438a27d470f": "0xce5c65fecd7bb733ee636a381fa9dd916f8cca91e2e403c8aea2f7ed32b31d680e424c41434b4d4952524f523430", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf25cbfe699cce3ea3a42b238084f199e5a26e07a9cb1d3b8827960bbbee94197ad2204ea98db2d54da63b57bd9eac4374f": "0x3284bc8ce3083b62e671d1c5bd61db5b3fea95a77967341ca8834a69cffcfd5f0232", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf25cd5604f22dc70a5804a812a435574025ae96556bd15eed67a54fe5f9191835994d94c18a764ea4280bd03faaba61774": "0x9c7c545141ea2dd84fe5ef7d567ea450f59967e7afa68e5f1ff7f7c46db19627033634", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf25d1943fc0a7b557c101e38228a007d3a12c0e71c9267977ff8cfbf27005fca3918833daf0d77537e8f879fb9fcdf2b09": "0x12c0e71d326f83f4e6089448e147fdab51b0b7398a7d0cc9a88b0571432e7310033931", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf25d7fae57fd76b925f7fa0a9c2b6c4ed28689cf01de26619d9e77cfb38911661940f6fd4b6379d8bd5558b8b967d51db6": "0xae963c00a7c164fce3f4a8ed94ba0a87e83cc1a7b192726836819cf1f63c522b0c56616c6964436861696e73", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf25d85bff0d6337213ea348d05c4c11c7f84c45682961f27cba9bc64fceecf20016338daf42fef5cac7fd229d7727db168": "0xce5c65fecd7bb733ee636a381fa9dd916f8cca91e2e403c8aea2f7ed32b31d680e424c41434b4d4952524f523534", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf25ddd4eff4ab0da0dd3bbcdcdae2a84495edf939d9f238bce8f74fdb215d853697a5a515b0f8b3a9a9d64390265f2cad9": "0x983c5a0d1f1e697c1a0f9798bc25543603751b41102d41c3b0e23cbc6e3fdc0b0c566978656c6c6f5f4b534d", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf25dfccd679a8f331c1ad6d882e30936b512c0e71cbbe5966e17c328e1a6f43729e44d4dc326af5ea40f9c0e103b19cf1e": "0x12c0e71d326f83f4e6089448e147fdab51b0b7398a7d0cc9a88b0571432e7310033732", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf25e40ec9d74f1117534a8fd748afed5bd12ba1a34fc5e9b81ba8d7e486f223a2cb47e30c8dc185888aaac0eb25c5f605b": "0xde7fc70edbc29190008415c3b6122dc6390b738453c6f1213b59942b2b76e54a0943757272656e7432", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf25e474e5cf89ede702aa65a076ba4571e72a136cbd146b0596b9cbf73f4f2e402dda2683568e33d1a3db791ddfaac6a4d": "0x7c4e144380357ad3e690e74f5b7bbbe4b7d6ab1579d4c6d7c844ef003cad9a24033031", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf25e5c57f7e74cdafe635452961c31d13aa7f6170f731a0acda2c9edc8ac9fc21a0b33e448378730b2392cc0bb76b55546": "0x0e038990f47761a17f45c2bb01c4c7746f4ad67c7d0c1dfbd6915372faae911f09f09f9a80f09f9a80", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf25e748e847adffd35d3d3855748c2aac549f2baaa065d3e927f265702cfa8d8eb83cbea8c64bb01d19c5c184b8e2f5d10": "0xc0b881e2db47fb95982cd5c364b87e6cdf5a5c8a336d980156623b53815c597b04423033", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf25e9a622d499eca2b47da48307f31c02a599aa7c71c2716d534f7f4ec936d9bc547b4e32fad199466a389b09b139f3f8b": "0x1c378d545f64248bedae80ec34f8f29551fc9f814f8491f8fea50f10fff6e22904303232", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf25ede6d686847e552985919cf30b1f997af5a44d6d0b15f2cf84afdea4c76b1321f84da230a61b0c73d755d9cf5171a6d": "0xb8a2a7e1c5807c9b5241a00382d483537eeaac2fc756dfde564af6a368fbc27504303134", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf25eed85774e7cec34e3739c21814420858bfca4af1ecfc9a8af84f239f3f3198d12a666452d0658069c451723e7d922a8": "0x2c5bca9fd4c92b051e35c47617175d8f28aba000ccf921cb24bdf555662f2d4104303263", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf25f2351b0f60616b6095d656542dd3fc0a8070648f6e43b7d8a8f10418b696130d2046c10645f10085de80e6098b85f09": "0xfe56be5933800b45a21ee8e9817eae9f49099fdf4a20076718497092ed43c62b00", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf25f6101fcb7a75c45db167543a3bca4c7f444730a05ea7fe71e53277384e8e78bc1c8b8c6858d2b177e16d6d1b05c1265": "0x52e73898bf4601f9c9a7fa052de0cc313b159dd368d458f4cb0341eedcd6d818076c6b736d3034", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf25fabc3b9626c2002a6b0d28adab59c3c12c0e71cfab0ec8e02f65d8114492d2c9177d3add541219bd8ddc00ef4e9b66a": "0x12c0e71d326f83f4e6089448e147fdab51b0b7398a7d0cc9a88b0571432e7310033935", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf25fd8f37d0ce437a9a9ed9b00ac09770c1244669ebe06bb78a7513e888ab43c70dd2f0c80e90189b02fbf62ecfdfdf66f": "0xf6b21d624832094b03aa672e016462a020e217cc67b1434785b99114a2b4fa5a04763336", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2600940c11f4d4aa49291d6c008357ef840de8fe2227bbb0358570c01c31ce0ebb4b7540c1302ab6a6d021cd0ae5d5942": "0xfaba4f34d61e2defae2db1f7c712007824c194ad921959efdb4a65dd174a590c0c62756c6c657470726f6f66", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf26056c060af5f5b395e8dfd029bcf7f1b8c216c3e8fe71b422c34003bcb536257a3ef17928e93792f8d8de4748b81446a": "0x94b3d04ef219a8970ac5f76658fdee1005b4b7ffee3fc02355f60db1a778f8260c46494e5354414b494e4732", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf260a1a9e3215ec9f15089823cb1803a7da849df65d3f404d80ceae8a840ec60cdfef83ae70df3a6d681870c87d5a78f31": "0x78baec43fd49badfce811cbba08b3f0ccf758b5e22f0c4d745452f5dad6eee07033034", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf260b1ac8161a811c84a429eff2c631eb50ede8b484ae583e43b011ee69f561cc3d145aa542269304d76b034ec0df99f3f": "0x8adc4e19e79b3d2c744f88fa5aca47ef05ccaae141f6435c2d50df824433ae480232", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf260b68962a2d002fb573f996c7e0d736dfe0dcc8db8a90eed611a4510a8131240174ca310a563a343fdac7fc1060b0b04": "0xc4516751df2e5803bac3bf9cf7b6d55cf4acbd76f861ad0a2a2b71b7a5ed805406f09f988836", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf261307e87e8bc1566f901b5dbed719573d85148f0fd5fe1eae1bcafc4f9d970f692415245ce7bb7988bbd76b8dffdf02d": "0xfcc5b90bc1891b7d905423f7a00ffb4e8f3d59aa97491b5a1d45b82548639936033031", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2613dd8bd2041dae29093cb68c280dcde8c600da2883fe70c639e6375b81f45d5225acf4777c4586a3672c2568b9c676c": "0xa49deb88afa394b7eb478483a65a8c8f060b7de319dc6f65776a84d9e8f40e7e104b534d205354414b454d494e455231", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf261df5bbd34ecc0ecd2cdf77f33ca1c94c24dc5f34db1ba52471ff7e38158a4dcc3a19b6137b8e6023b72f889cacfe535": "0xce5c65fecd7bb733ee636a381fa9dd916f8cca91e2e403c8aea2f7ed32b31d680e424c41434b4d4952524f523337", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf261f0b29fac740e620484b5e17f2e611612c0e71d133bb870cfcff34b784d933b5ab71a4f90987f854522f076bd23f214": "0x12c0e71d326f83f4e6089448e147fdab51b0b7398a7d0cc9a88b0571432e7310033035", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf261f255051a4c31354a9d2001207b656246d59d9963c62e1d8f82335ec3768bd5aa4cc268abdd209b779d139d99eca26b": "0x78c7e23425c0433a78c7f295bee57069c78743b4630161530af5e6e5ad5a702404676f76", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2621a5cf9ededa4315a266d7bf8f75286468a99f3bf7d3a5ec5cd3932ffbb436ecd78a9c635286d544661acd5f9f8de15": "0x629c17f4f4a24ec53f85a7beb1c70b13379fb8e4f969560704d2c25133ba8d2419416c7a796d6f6c6f676973742d76616c696461746f722d30", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf26241081bcbf46fe6d72b580a1e76671a20912c81e6895f7b27bb4be5f6cb4750a326d3deeaba95ccce9a6bf6d1b9fd29": "0xce5c65fecd7bb733ee636a381fa9dd916f8cca91e2e403c8aea2f7ed32b31d680e424c41434b4d4952524f523332", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf262682a6865b2c4c690d6bd023106732e43dde39c254993375b5d7905319e7700ebdbf57acd84e44b3025d869ba7d8e6b": "0xa45d1343d565c182e0e1cd3da2d6c0b1ab5b17a77ca165457d9620db19439a6404303130", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2629f18110946927e208f5b411e43b06f6a4aa384952d2245b6c439c833edb350c0ba7e31ca423f081ee6a0d79596c658": "0x5a6e6d7f1f5af2300c1b721cde7f08238ffef321bcb45cce819b00557fdedb00033031", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf262a75c46816254a83804a42ec946520712c0e71d4911dde07af70a1bafe6ae84ef07a43280a736d0c19395a587935412": "0x12c0e71d326f83f4e6089448e147fdab51b0b7398a7d0cc9a88b0571432e7310033533", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf262d67377e6d52bd6cb6430a85978e4b04a4ad21f7448e3183c18b8314ffecf0b382098635efdd056e0af7c53228ba426": "0x52e73898bf4601f9c9a7fa052de0cc313b159dd368d458f4cb0341eedcd6d81804763031", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf262f7a72b64f01a4727f71e5fc6274dc2d618111c1eb2afe48d95bf0501243748e399e23a538bad0db61fe474f4f2b90f": "0xf6b21d624832094b03aa672e016462a020e217cc67b1434785b99114a2b4fa5a04763034", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2631c0679800402b1fdd76bab9f679f7ce26969331bf77ce04768009026a5362d51e5bccc12f788b8cda2a43ef218bd04": "0xe26969331bf77ce04768009026a5362d51e5bccc12f788b8cda2a43ef218bd04074265726c696e", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2637c3843530e14f1b15fe989582f41780ee022b7052ed281ad71f8cf98ddc2efd5b5fa45d741e4861c225a2bcf22731b": "0x5a9e357de87525b67cf9ed1d0f06a15a6363665ca1c9f43ff527c87c0945597c0231", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf26389048d2b55b0c66fca6515bdec995f3ee307326a809fbca23841d62753a3aaa5d3ef29e45a4f810ea1011c178f302d": "0xd6c29a7c39cee45b0e045a94081bc188ef73be2be086d66aefd850fc7eeacc45064261697264", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf263e1a0f7f5269ddf76106255a28ee08012c0e71d5287b03cc78c4c2faefffc4cacd47bf65ba7bd0bc5d4facc08cf9323": "0x12c0e71d326f83f4e6089448e147fdab51b0b7398a7d0cc9a88b0571432e7310033532", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf263e842b733bc16754c05a3c4e27b82717291c36a6b23990b023acb5bddedf227b9688372d4ae99b442b031cadf13f66e": "0x8c8305ff8478e6309325ebbfb81e8c1883d39e65d2ef84f88e4a428615c4927704313037", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf263fd21194b7a0ec0fb9dbb1029a23d80f4c68c01b58b381bcb8b1fe58cab96f90271910ec55c23214c68815130b5a81b": "0x18cf1686419c41dc5d3e76d373e3176c32c6d23c755fe1fc357f9c755ffc00190235", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2640054d8fb17c225857ab80a22e4183126842927c98a50ab1d439ab45f21c5beb6970556e1fd7b52df44977e4344b148": "0x26842927c98a50ab1d439ab45f21c5beb6970556e1fd7b52df44977e4344b1480458595a", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf264c092a725415d558ca5ccb0f490d780f45c6d9ac359665373662814fb3b30355638036ee2aee6807b2f2b228ec1d6e5": "0xd53c9c6e61431448ceef1eb49542ddee942dd3d6c81c19d53efbab8acb02f00f0973656e74696e656c", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf264c398d291c5f649be6d6d75b4781aebf206c1276f16bd43aca4fa9d596a7164a310b83bdf34350c1480ed4854cf9729": "0xfaba4f34d61e2defae2db1f7c712007824c194ad921959efdb4a65dd174a590c0a6669726570726f6f66", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf264de414e896f1d1d91e9a01ea473cca0d0ccf4cb7501417f0d7bdb6d577e026612d02579686f0ff1137a10c843f5c963": "0xfc5d04e7ff3965c8285a2c23aa573117deeed886bbe5e3be0974f1cf0a2ff216073035f09f9a80", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf264f2cd21692bff61795cb794b30944a21cbe59b1e375a52b9131fdb7a85c0992b8c5cdc3f4b4d90e19185972cef58b2a": "0xb2636043fc3b8dfa608167a9fb6fb9d065b9f2f5821dc4bfc9785a244b24a92a104e4f4d494e4154494f4e2d504f4f4c", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2651fedca233a66d0898b07888f9526db8478f51feef5a376deda20303e61c855e0b96451f692ead53d838130bce9cd08": "0x8a320af9e031a3396f15acdcc65c43008124068226505ee7e12bbb0a12012e600c546563686e6963616c2031", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2653d347f7ab0616e9312fe3ee15167d1815e86a39ceed754266101e55e352c131c877e72ba6f9652dc45fb3fd3757be4": "0x7cdc1a6a5a7f23437b6528edcdf553d0685f940a4e6e85579727ef3dc574563a04563032", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2653d4fb685eca06fcb8b63a86aae6c65aa5cd92797a91f08d3feb5b497e3e329800710e13726accb52d2cec9f16b0164": "0xaa2b3e0a8702aebcb83d552838a17902b2403b0f16c4e52a4514fe02df532e3c033130", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf265423f4616ddca5dd11b3260bf8a0b34e34c880765bf4cdda6ab2045979a9039544bbae925cfba4d6421286296cd9bdc": "0x3c1db08dfc6786bee3b0e1b4aaf51e80b6f2ec9badbe3da87d30ad7605a2bd1604303031", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf265bc3fa2aa63b50cd345969f8790d552a42184be9cd7657a019c2624c045f4ef80df884576b0f2e1eece434410537a37": "0x9c7c545141ea2dd84fe5ef7d567ea450f59967e7afa68e5f1ff7f7c46db19627033638", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf265c6ea578befcfb5b2d2affa63df3b05860a5fb3fb398d56fe3180ba927cc0f0c9308cac7f6af98d4fc7624627343c4a": "0x1c6d8b40be9990c19e993d238e6e3613cfc6cbc51979d5fa61dd6ea2593856090d6e702d6e6f6d696e61746f72", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf26691bb6d27adbf3d894c5c905b40c202fab7ede8984030252e6392d2201f91bcd558470d35785c4bf89f6d7cd86c6e66": "0x040298f71f02d7b6a67c0ecee7d7a62ea51dc6daecebf4dd9ad72e0510537a580474776f", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf266d79d3fccdc1cb3873b9f7bb80812bbfedd35f51de7e439bf432926351c41500f30fe78941f325c69dbb642f3509547": "0xce5c65fecd7bb733ee636a381fa9dd916f8cca91e2e403c8aea2f7ed32b31d680e424c41434b4d4952524f523235", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf266e7b15209329fb5f45d8d77693f527d9f7951a3a51ead847837ceb367ad2166b0dd1411c860fb01cf7ce94cad08022e": "0xca5bc1915da74aba3aadd7ce7b809045d5eb5b73559259755fdcd85a40a5dc6e194a616d2773205768696d697363616c205472656173757279", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2671946b010703f7d896bcd837d623f0c5e4a7f6fd9a8525d277f96f3e758e51fb673c6c28a7203b1a57f6e90c9f81349": "0x8c8305ff8478e6309325ebbfb81e8c1883d39e65d2ef84f88e4a428615c4927704313431", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2672fdfd5b424654eeaa13d2aea739ac0bc56d28e12b54fcca3e2c3e90cd0d8a991718bd2fcf9a65dcdcd1bdd04be4459": "0xc0b881e2db47fb95982cd5c364b87e6cdf5a5c8a336d980156623b53815c597b04423130", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf267482cc726f02add0a3f6067d99bedf2aee65bf22cdf1f98c91b6c176854d8072f1328e027d2e84d23607b517b1b9429": "0xaee65bf22cdf1f98c91b6c176854d8072f1328e027d2e84d23607b517b1b94290574657374", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf267833ac6e29d30a5cb45c4b75174411ac2e34786dcde41bcaf6c5c3dedd1320c792f0a0bf3c448e03275d7f9cefb7653": "0xde7fc70edbc29190008415c3b6122dc6390b738453c6f1213b59942b2b76e54a0843757272656e74", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2679801cf4c337ea779bcd260fcabbcb712c0e71c8bc9217a6448d34afd0c1d226663a864a4141b65d13f8bbc743d1335": "0x12c0e71d326f83f4e6089448e147fdab51b0b7398a7d0cc9a88b0571432e7310033838", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf267d883de78b7fca5e136b2e623af15e9051e046a4125b20b4a9df6a8d1d5f81f6155279dfaa2050c7970d4470b890e8b": "0x081c465a655cf27eaa73bdf9554abcb46ca2d56fe7fb0a20835c1a5ddec4a32504303233", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf267d9e84f6eae02484804da8f9eb7552e483ea32669fca11e7415c4e24e088cb3df49defae82f0f9d069ea0aa75839e38": "0x48745d28d9e9596ca41b7f7bcb03f874757f4f0716a7237e566662a6393bc1250232", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2682f326dc001feaa0af173c9de66ed310cad33c225bbc550c7e1b89ff2feb2dcc8993f2e3a8dea40898fa8f54f754b00": "0xea6a0804e0024beaa87fc072eb250446162310017e52147d18fada54a8ddb57b0233", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf268435ff8a551e9a6b809aea31b22c1650ac2e966527ec0e3076ac6ae05402fe763d6cae60a8c01e108dfbb6e92d0863e": "0x64e05e73625f3f0991e3062733ad8480c5589a710a24beacbaa555f1c4a7f0640232", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2687be05f69f6f8f84f4b954a8981d6ce9c674dc7b750bf4d5d5d0db23578adbd9602cac61f6292fd788879a44c87256a": "0x66f7b3f3db597d3032c2d767568aa550249c946600a61276910b9c1d21a933710f466f726b6c6573734e6174696f6e", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf268a30cdb6c7b150c4f0fbbfcb62333fe3e4473a8a5c626a2b1eab5002c13537480b487a04ce85ae09292a7c458b3be06": "0xee56126859de69a3539f0e8910ca7e775243f18c6257954a65e020eb229be9120de29d84e29d84e29d84efb88f", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf268b65cc0f7d23aee0aeb082d9170bc585058c8963e2b60c6f1e6c921a3893414f370b48ad0c2d2d937c7786febb29003": "0xaed98e15e3ed392e38654215c3d1fa8143de53460386b60139fbb45c036c1b430653462d3034", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf268d8e8420dfda8f984220ccf7a9965693c84672d8f0f25ceea258d980ca234e25ac03cf2d78f925340ce77237844147c": "0xaed98e15e3ed392e38654215c3d1fa8143de53460386b60139fbb45c036c1b430653462d3230", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf269086b8dd50e6fc95ccaaadb185440188224620901db3a08a236f1417e7f865c079b41c0b2e6cb0084109e4be3fb1d0f": "0x707c9246c1c227f1495885cb2f4c59297248ec5abeff2d0f68495075a16bc17a0232", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2694dfeb03523adb4381226d98475f9ac12c0e71cad505181147127f5267ae6187fe470ce00c91bd1d1adfd0227a7333a": "0x12c0e71d326f83f4e6089448e147fdab51b0b7398a7d0cc9a88b0571432e7310033737", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf269c4dd017da84e735cde3739503ed184821bc7f162ddbc6418c08a018d072e2980a4257c8584435e5b6251f6e27cdf19": "0xb08b555a5a3b2725e01ba15eb40aa32dc5b781532854b797808ed45e752b047c0232", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf269f011c50eb507802ebe2baf74a0ea66b6d4569e33bc6763785b94b98ec57d07573650e35e682492dd515e0a064d8958": "0x8c8305ff8478e6309325ebbfb81e8c1883d39e65d2ef84f88e4a428615c4927706706f6f6c31", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf26a078f9501f9c92fd33584a668e8c3a5845c9d99f3070604aeab0b883b0f8774de633c1e7b91a0376df2342122fd4148": "0xc46ff658221e07564fde2764017590264f9dfced3538e283856c43e0ee456e5105434f434f", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf26a1408806f270ef20161776a9ce654a724102b17c177cf80ebd64796a17ea2c44b68aca3a03fc35be96f6d3ffc60716d": "0x3acdfb6cd734dd3e624b6512e0903724c1c90a516c03c81a9af756491ea8e15e0232", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf26a56028c7f51d87f63a6d86e42f64be3d296d443e8532e4977e9d78145f6ec9eadbec4fd2b10158e82985549046fe568": "0x882a9309f1e5f87abb745dc51d5dcc338e3dbe7b818fd8a9768e27d97e57ec130232", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf26a7ac804917fd14c1c58048ce7e065790efe4d35b7d336d66f5ae2cf6969014428415b9d32d8eb2c17b58829d5054667": "0xbcb916e7a7ef77dd1f610ed27ec519b4ec226028eb8edade41f95b217f89f620134576657265737420436f6e74726f6c6c6572", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf26a91019b51c62d22ad66a4f15dfe72742ab01782078bd1515a3027895439f31237792568ad0eded4af3d31cbf30d9517": "0x9c7c545141ea2dd84fe5ef7d567ea450f59967e7afa68e5f1ff7f7c46db19627033935", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf26aebc27682321ba956951a5c3e2e2d925c05d424a33d6e9ac92c3863c26aec3515226a439192e9fb28dd47db38dff05f": "0x5e1eb942e5f591bc1d902fc6a04dd7ecadf5f4916f2597df0505c6c521412c4b0238", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf26b67a834ff44be6104f436a0795450ce12c0e71c651e27773fa58160878f81a68b7b054ccdccad776181f757e763e514": "0x12c0e71d326f83f4e6089448e147fdab51b0b7398a7d0cc9a88b0571432e7310033430", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf26b6eafdd82bb367c496ff30495fa001ad6c6649ddfbc12a755845a05072148efc0d82ff7cf4491ba4e63cc97495b3735": "0x80a135db57d4d35273d9a4f661d3dad8f153a1b5bad478f9b0e5223657aabc0b0e574f4c465f5354414b494e4732", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf26b8a79cd1758e7292121bddc2d2aeb5cebb515975618eb35e252200dee0fc30b3db265686c72ca22708ad304084b975a": "0x68f6e4f77f043dfcb9fe88519996ee25ccae674ccda259bc49efec6b6eeb96070530322043", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf26ba4c9db27e4bd17f30e37e935b673842cfde9047614f815e566dec170152a0e9a7b163f94d0a59e8abc4b84dbaa2e63": "0x482a9a411b630d2c3f850f435c4566a6a93143422e6cce181320f022a74512360233", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf26bb1d27c505d5ccaf1b88cd5511903d81ac5cc7855b95a4ea69568546a9e38214f4b6dc5de6cf1351649afd6b0bc800b": "0xce5c65fecd7bb733ee636a381fa9dd916f8cca91e2e403c8aea2f7ed32b31d680d424c41434b4d4952524f5233", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf26bdc0ff56647d1ce1c6a6d0b4b836e3eb43ec7322956d133d41e28758fc64d2da34d2888d93af64eb41f7afa26967961": "0xb43ec7322956d133d41e28758fc64d2da34d2888d93af64eb41f7afa269679610a617274757273206964", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf26beffc5029c1f65bbdd549396e486bb52415e5310193e362840035d0283a5911d358c1553afeabd87ea4d66d35351128": "0x3674aa73951219dbd27b3e3fc5847b806c68c1de38fd4f22f9493a461c80e9031541524354494320425245455a4520e29d84efb88f", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf26c0e8e3c208d8a94bf73eb953a3c6e46688f2dd2918739ffc90f280131b7d8bbfeaf9f0e2bacfe952a88bfa3bc168045": "0x688f2dd2918739ffc90f280131b7d8bbfeaf9f0e2bacfe952a88bfa3bc168045033031", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf26c3dfe8ae17a27ceb9be0a86c9319a75ce304677ff08c2d76d65ad5bc3adacb74b685907cdf72fe0f155c31dc4c8b047": "0xaed98e15e3ed392e38654215c3d1fa8143de53460386b60139fbb45c036c1b430653462d3037", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf26c75c149f8b3ad90d61d9519f4d1cb53ce26c4cd5d39e3dec824a79059cf0746e3aaed0821017aa493da14687d5e550b": "0xc009ab06d6b49cd62f2801c4b0029a5343c51747f6716c788780bfeb2730af66033031", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf26ce6b594ad15fd471e6f5eeef2ce735e1ac452bda8e177f52bae23195e506bee27b7007bfbeda4f2010fa6220e029940": "0xce5c65fecd7bb733ee636a381fa9dd916f8cca91e2e403c8aea2f7ed32b31d680e424c41434b4d4952524f523537", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf26d1fe1c743f8b472aee824e1f69711dec0d4fa6e65eb6e8de70d275bd49773f00fa1c385a21608fe2f94a13036ce8661": "0xce6e3dc917919ccb44e66c8a5d4c693b96265d5e7072433971fb38d083d0587e0232", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf26d3f300520dc0d16c9570946cc6b670504961a29fdfab26086e085f26198e4839826299adf5158e0de4d266528642b5a": "0xce5c65fecd7bb733ee636a381fa9dd916f8cca91e2e403c8aea2f7ed32b31d680e424c41434b4d4952524f523134", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf26d5112b75bf01c0d280bdb0da16c359812c0e71cb50b65d27c7147f5ea52a5a805f8f75301ecb5d9577244659659965b": "0x12c0e71d326f83f4e6089448e147fdab51b0b7398a7d0cc9a88b0571432e7310033832", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf26d5499cc650d3ff7095b51b827fe7ed1c0dd6bb9243edbd211dac2b9b37fd29003be77cf21455af7c2c680af8812b604": "0x18cf1686419c41dc5d3e76d373e3176c32c6d23c755fe1fc357f9c755ffc00190234", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf26d6154ebc6adee15904e184473e1bda32e05b8c395e198a2efa9bcdf3ac31424d984bb2b9a1cd6635a6e60c9b6a0097b": "0x845498df40e85e2ba9d9e213d1f476e7b147aab6a9098f1bb250e00251ef8f5c0231", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf26d6b9a24b605db49b90dfde2329ae9512cc63957be519774cb72783eef49a4a1dd53905dbf49a4a6f180a957e0563021": "0xce5c65fecd7bb733ee636a381fa9dd916f8cca91e2e403c8aea2f7ed32b31d680e424c41434b4d4952524f523536", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf26d6c9cd04ff6a263d7cf4ec4b679b030ce384d806d03a4618c1365850015bacaab7b19a86849f627743dc2b1b6c90573": "0x56d629a2c80762d412fad9c15d8cc973b463f600895170d43a10ca504b4f454e16205b31375d20542e4d452f4b5553414d415f424f54", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf26d6d8a60aac223aed9c676354ddeb9aaf8f71fd7d5dbabcdf5a640f194881f3f16c13e2bc18e54cacd08dd60fba0907c": "0xfef5977196fe3fe5c456a767e6b06013ca62762b282de97040add4ad2c53db61033032", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf26df4ad1e32752726b5d14d23e6c0f2b548a9cf978cdd6826ae8be06a8a4c2b5080eba18ed88f5a01cd4db7b947515d71": "0x482a9a411b630d2c3f850f435c4566a6a93143422e6cce181320f022a74512360234", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf26df5e87b58fedb8a32ae8c35334b088b5055807b7c54a1143ebefe17d711170a5971227a8a8b593c769fdce803812028": "0xf6b21d624832094b03aa672e016462a020e217cc67b1434785b99114a2b4fa5a04763330", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf26e16b58ef6482e68e69ecbdfadb1c2a52cd1a4b07571dd2c61dfa5ffd65b190a203d082e9176e791a25bcf242de28501": "0x48ca001326b583070e370be3bc6680d09cad47649584a5c992bd388c693b9a54033234", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf26e268d93af6f8ccbe753d9d7aab0dc5aba823c07ebdc12f850eb5dcc7e39971b34d5fd6643064e0394cc77cc0fea6718": "0xc0b881e2db47fb95982cd5c364b87e6cdf5a5c8a336d980156623b53815c597b033133", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf26e497e650775b5009385bbae39687dba346c4cf9a3d4e2bbeeb47694406ec7bb64e9c25e695f5a9051cb8119ca8e216d": "0x8adc4e19e79b3d2c744f88fa5aca47ef05ccaae141f6435c2d50df824433ae480231", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf26e4b64ce649099fcd204d308365b0a013a5dfb7d614cd20d8ddf555c4a23acef0a71bd8723463f36f89e603211dd99b0": "0xf00168a3d082a8ccf93945b1f173fdaecc1ce76fc09bbde18423640194be7212083037f09f9a8020", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf26ebba2aea637e98146839de88adde4c4fd82c8f29cee3c6170e1f21d2d060586e2508f5a3dc977f2f179ed52d33aa923": "0xa80ea94af8a39eb7ba8d9afb913147e67eae84f48aad7b9ce6ee05094fe0394e07476f4f70656e", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf26ebeacaba92514d9ce59b29ac9021c9bfdcd5afc6aaf6c47e499c5c21097386bf5eeda93a13448eb7b9ddc4fcd0e13a4": "0x6610a5024c2a5db3d02056d4344d120ec7be283100d71a6715f09275167e4f38033039", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf26ecf2cc935beea7b1c3cfe5594654765d10cd1c9ae335b7b25abad42b89554a8d9c9fdce81a11b856604cdfa6edccffe": "0x30fd1beaa72357f61ba1fe7e90aa8c5080fcd49b2c82e1b8315bcd9a223cbe4109f09f909df09f909d", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf26ef9e6acacfa82facc618c0deffd2d74547be45207a849ca9ec68e16de6964b581b36449cb04256febdfdad833e7e670": "0x9085297d964ea873a23b63151b4c82189c1314c31fda6f2d71f83133d0877c5c054b534d33", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf26f1d383e98d0d081d44c4db9b00e30dd163c64722e9d2ead4a7d5d88e4a3e565737094f0d4bdca0fc90d6870a8d1271e": "0x184d701295be7bb38b2c0c58a35bf8edc592671c53d149d206e037dc7c9beb7b0233", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf26fa1bc3177deab3c13c2d8ecd2eb3706e81628fe7cf9e8c5e313f1d418b48778051a756de0f652496423cfb3f1be2836": "0x8c8305ff8478e6309325ebbfb81e8c1883d39e65d2ef84f88e4a428615c4927704313432", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf26fc5b71ea1415c8d7c07961675275143463fb9341e83f58071dffd0feb3915815e4f7055c74f0e4ac002214cf06d6588": "0x0650a2e41ea97b60bbd3f87aa30d605562069075deaaf79559959230928a248700", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf26fc806dc65089ae91187a1fe690b09db24c295ae61b1b902e08f1b4939f83aefca9d3cf3c6048f1bee7ca71dc5c20a2e": "0x8c8305ff8478e6309325ebbfb81e8c1883d39e65d2ef84f88e4a428615c4927704313337", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf26fcc51b405d6f6f727140cd71d9d06855034c3e43599377576fb1fb81c8410fca61070ddcff4484cae5e57de2d084f6f": "0x503551a752e49ebef1b6988ee561cbbfe0f442a56fe624a58ae80ff3b3b9cd7d0545505632", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf26fe1b129c78493f32f9865094f231f9c8866bf5337468c1c81b265c4d9f352ad6b0e50b7fe77c4a660fa9ce31e45154a": "0x9c7c545141ea2dd84fe5ef7d567ea450f59967e7afa68e5f1ff7f7c46db19627033839", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf26fed3a5a88d568338cceb3c0f4696f43cd1a5def7ac55b1ccf202ae5de75a02a224d939e1b8d84f54e5d03a714d49896": "0xc0b881e2db47fb95982cd5c364b87e6cdf5a5c8a336d980156623b53815c597b04423032", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2701f3befc036e16f64d48c6c8d26cb7deaa9db4e448cc0b93c4cc1d5059f9bb7e017c51964e21916f2106cf56b702f64": "0x83c75b56557a84fe8261cadc0c308577b0709cdc54311afc5ec8d348b939f589084d61796f726961", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf27051f48905e9a91b8c8c33367d55ed3e3472a370eb332c43576f14f315b219aac6f86795a580d50cf5454b4c293b811f": "0x868cd54faea1a0e45836635b2bf658733436ec69c5567d651be592392cbb69dc0233", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf270866c46dcd9148458dfb322e71add45e2c726e24b6fd7c2bf7bd253448f03cbe350cd0e36bcd621a82fd2732bf9c206": "0xaa220871834d1f214169691dfd97c70823d90d192b246378dc01a59daafffe0d0e48797065727370686572652d34", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2708de677db33cc55b0055884cb832c7a12c0e71d122033fe390632d7275542273a8afc911afdba254ba4b7f330879064": "0x12c0e71d326f83f4e6089448e147fdab51b0b7398a7d0cc9a88b0571432e7310033630", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2709054a2d4d5d54351c6d9732c95a37eeabbb97403ae010a1fcbbc9cf50529f27e0eda03efec95e29b6ed44dcb075648": "0x1aaf37daa4afffeb0d84c47f52330d8293ea648e1bba5fe0e35355057e63c1670d73656c6265725f70726f7879", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf270aa73d429acc44140f13964c7ac109c92a409f971d4db36b2d2d520adc5ea15c5ac9c012d22e4e551552d250aaae57d": "0x54efb33a98824d6330a8f074481df98b5123305473559bef960180791f8492520a426572657a6b612032", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf270cdc84d725fc107ff788b254c7cf112016768f8ff56cc85e23810144f87fcaad260080c7547bb6d3c20d0b4929b9d73": "0xf00168a3d082a8ccf93945b1f173fdaecc1ce76fc09bbde18423640194be7212083239f09f9a8020", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf27115e3fbaa2944d93182c99cf8826bd3ae8c6dd7bf2e52a684bbda1831b6eea8040b7fa459da6a487a9988a9d84f6b0c": "0xd4e6d6256f56677bcdbc0543f1a2c40aa82497b33af1748fc10113b1e2a1b46011f09f8d80204b534d20303220f09f8d80", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf27123dc060c010cb7b13ee5f37af3faf62c0f99b106126a14a19ed92af1bd9055ca4c39fd9ed5ed2305d18f6730ac5470": "0x9c7c545141ea2dd84fe5ef7d567ea450f59967e7afa68e5f1ff7f7c46db19627033836", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf27163dd1626fbbeb9a80adc352bda4ae55034b9af07130a1799cbdbfc0c2ff2fbafaf47fc4cf70d82dadd9e606f23085f": "0x503551a752e49ebef1b6988ee561cbbfe0f442a56fe624a58ae80ff3b3b9cd7d0545505631", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf27168afacb6a98d528a357138dfb05c28f2b7e775b59951428fefeac1c8f7f40b24103e02315552065e37d58ea80c7d77": "0x929aa2bfe7b52500b288c943b7c24a90928cd8a6f7ec8eec44763d9f741984011043727970746f2d6275696c64657232", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2717475f84a4c9b87440120beaae13c364c70ba4d71065dc3bd0d11c1fff6bfca26d89b5c3f406eef2e5de8ac7334866c": "0x8429c11f2ff4fc700087c7fdad402d6e97c6df5e73988c3a36c2b6fde7daee210d5a4b56616c696461746f7235", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2717d75ca6d64dd31be997b22d763da311ae31e3543602bdd7fe69218e5c8d16c782f96969e2f7e323ec5096ffb294e44": "0xdc86d7e1dba377a90f087a942c0c2777851b447a16af68cfac09c2e58ecf7e1d0245", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf271993737254d0baa3517a60a30837c2f148152531de95b53fa605b79b786c7f16397d3226ccc2f0beae85e2d73770937": "0xce5c65fecd7bb733ee636a381fa9dd916f8cca91e2e403c8aea2f7ed32b31d680e424c41434b4d4952524f523238", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf271a9519680428dfc91bfa55e8853a73a70f955feb0ffd847cc972e17e979619e0bc0739673db8604848204bf61af0071": "0xf6b21d624832094b03aa672e016462a020e217cc67b1434785b99114a2b4fa5a04763333", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf271c0517588bb633aede2620df6d0989a20188a2097650af57e7cba4be37d595ec1884b69aafc65961210f295467a5313": "0x02b2b0de562a79b5ad9c666c3f9e7752955f3b2c2b4a17c71125b2668ea9ce5a0a617374726f63797465", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf271f70b1d97b96cb0f9d8831ab8e8ef2775c4d8aeb08fb3e8276a09141d8139b74d6a76af72acf6955617309dea176a7a": "0xc0b881e2db47fb95982cd5c364b87e6cdf5a5c8a336d980156623b53815c597b033039", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf27205da583a65e8897ab5db17daad1ba84ad44dc061d183f5adb794ba6708425fd6a3e1c306152fe63fb22075d1f7347d": "0x225c1cf2356a5a5cd7e13c8e5dbee6c4c89e1c5f610c1050131cc58b4d96e75a0232", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2720c59a42b1a2b4c7d2139dcfb90529fbc79ba52668a29f5a5c62044bf72f6c666f2ea1347cd1d23c3e54d7a5dd0614e": "0x1aaf37daa4afffeb0d84c47f52330d8293ea648e1bba5fe0e35355057e63c1670d73656c6265725f7374617368", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf272384e0b39da7c6140d723845b82629ae293a27231ba1550c3767df641d03102ad153acf8b4bdb7db7f180fa9d544d65": "0x9c7c545141ea2dd84fe5ef7d567ea450f59967e7afa68e5f1ff7f7c46db19627033230", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2724c1e316dcad867c557f64623c896ae904f9054a49d973dc073e09bdb9c9e49213558cf7b5a29d6f2671d8f6999656a": "0x36d7b7a05501f3e93e7eec83c53739147dd9824554e4907136371ca062820e3d0e4d414d415f4b5553414d415f32", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2724d4850ebab3bd5702fb9c234ab0f86386d313e669622ba62d89b48b2d4e7be50308ca20ec56fdb89ca5844952b3953": "0xce5c65fecd7bb733ee636a381fa9dd916f8cca91e2e403c8aea2f7ed32b31d680e424c41434b4d4952524f523137", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2725a8418b84a405c8889b8c32fd59d2ce28ceca047d61c081d502fb5b66527b2dc7438684d607682e9dc082640667213": "0x48ca001326b583070e370be3bc6680d09cad47649584a5c992bd388c693b9a54033138", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2725dcb5bc31ffd3143e49d886f5a357afe96b7fa8b193f73106d03bd579b5cc090cb75640ec8090d19d96a3c3d5d8c7d": "0xc0b881e2db47fb95982cd5c364b87e6cdf5a5c8a336d980156623b53815c597b033134", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf27287cb64c5712f2c170bb9949647ac356579df1779da496305c30a43dcdd9277e4984df2b941343e1086706c613db393": "0xf00168a3d082a8ccf93945b1f173fdaecc1ce76fc09bbde18423640194be7212083034f09f9a8020", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf272dae82d2e62eaf973cf7a3da5592630769e87de4b843adb49b3de1ff29ce837047c48023aaaf9c6d3abc6e66b4ec34a": "0x600e047c97181ac8d0b9d5a6372f6018f556d68b2b4cdb529d87da365f718d4006f09f92b032", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf273011b2d1b3498c3c4fc781f8c5d49dabea06b45bcad97ae3126af1a6e864197180af4b7e6513da3032228b2bdb26368": "0xda01077bdc025fd779cc21c9760727ec07e52aa132410b82e5fabacb6f45b0550232", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf27354a2780866415377a9ca2bf004daea1f8ef3aac7ddc528f500ac380bfec2dbe0c58caba4540adc427fd3e3186bfeea": "0xa215ba2d1b408fd5350b93f2566124331dabc06e94c16d7080d3cd5771d5995804303037", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf27367a138830fe89180766e60d91a6fb938684912197a8fb0da1f815281bb2f52f170d07b4d96450ac6ac06cb4bd42d6d": "0x28322946bfaec48af9564e56ee4134655dc1748ffc206c3694a9c6bddbe8332f0231", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2736afac49fff50e3afa239555b5dac3166e499f4ab6510c9b071eb403111b1d51b97195af9cc2aa65db79f3b84f09762": "0xc229d8ccc5e5650d17760ce2b7c42bdae5f6afc6e8bab249ec77f3f779ee5a651331323a206e6f64616d61746963732e636f6d", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf273a75a5cf4923c0b7ab99dc4eb485dbf848acf74babbd40295e54caaaf41e505891996968bee93eedcaa8e5b4105c779": "0x16476866c0074663b7d9046023a2b3fbf447c833f4fccfa3dd7a482235f1ec7f0c454e444541564f55525f32", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf273e7252fc1f23216876fa58e3aef25ea4194458149444dc0e0ae7addb00b669d89f3979309ef9eb635f148c2b879e878": "0x34a3f0845fecdf74f7aeb569953da8cf8f8217a9a167a4e7d6b3438d8bb6d82817414e554249204449474954414c205354415348202331", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf273fe8b74e00be2d5b1eb774c777767bb4415d4ced8c9de7ba415022d5b356f25eeb4d9dcd522732b2c87520e29e66044": "0xaeffde5a4dc7117e4cdde2d3fb3d2afc7b2f710d5d66c55c5d1d7c5873598706033031", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf27454aaa2b1424e886ce757cde7dcb36ef295175d63624a3f6e510b8c189db808a049704c4b99f49c2638e9d963d1a3ca": "0x105c06afbe01ff98801bf3e46b96d61d0d7aeadf7af7d6c39a20dbf946b0fe4104303234", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2745f3ed7b0f17c656c3bae95e64ef524e64a8c8a0cd5301afb20483923ad8427c597ba471a6fa868947270768bdd2713": "0x1c82102e4554587f23cbd4bfdb0f43c9d2879d18feb6102bbed977930f695f220233", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2747c62d525d486a49a8f716dc64ddcd512c0e71c62cf1da0300cb62510765cc22eb8eaf487bd2abe160f4c231e28a340": "0x12c0e71d326f83f4e6089448e147fdab51b0b7398a7d0cc9a88b0571432e7310033338", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf27491b968ea371852883ad125704b0ba48e81ad73b19ae9a28e6e7020f70d862a8e379ce88dc1546a2a8724a7c4b5601e": "0xb8a038b439b411fb7c6cc2d7315292a3d1649601641cbbe0825ab7fa90ce30020231", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf274ef942dc8366e68b9e82fb8def4a0ceeccb809fabe7f585098c7e61345f71c2e651c9fb61f16ea74a5ed6279a644d74": "0xdcb38c186bf97625f108b4832981d966ebed50d939349d4437a6f538d40d56760c56616c696461746f722032", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf275051bd70eaf7d2946e25174a25beafc1ea9ff7a769863d12182a9439c3666f3fbbaedec8b5427d3c3e93633cebb4ae0": "0x2a5bd5797da40fe8be1b94dd3260ef86d6b01cfc891c5c1cd160ad7fa198de57066b736d3033", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2750913f60cd84d201ee1959670fdf4bccc2797a71c48e7e7f6defcf2dfe8c379a521c8500c9bbfbc13c8513cd5cdfa3b": "0xaa18b3cf52cb27fd19d5b80fe7982ff955e0d5124dae26ac360056f401dad84607416368696d32", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf27529ee72bd431508bde3a88f3aadf4282c35a5568d679cc0a70e5b714a16a87450270f8ed184d35e961629aa7c364f72": "0x8c8305ff8478e6309325ebbfb81e8c1883d39e65d2ef84f88e4a428615c4927704313334", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2754b24bc7acd0d7883e296a775c5b9002c85e23060a9c8b4598f2927a796f8062aa3843dab76f9eadd8b2f36179c263e": "0x9c7c545141ea2dd84fe5ef7d567ea450f59967e7afa68e5f1ff7f7c46db19627033630", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2756ebea7da8902d2c48177e3dad442771644a3ce3456b8954eeca77a5b67d7e9d26eba9f922b82daff95057f543ed03f": "0x447326399643ec639a0bfde97d8b37f8dd0ca9fcb3c74a1ce017f0476f3e2770035631", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2757504984d0dbf6cdc735ad4736bff8b1560de907974c342ad34bd99ba8b530cbf89b39a10be019f9abfed3649470718": "0x008d8404893c7b4b80f397605cc96e61fec3c89676c8c2794a2a7d281d678b1a0b4d454c4f44592043544c", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf275935d7c517e7fcced318f2d4a6e422e92f63201ab158aa8283fe585a2bf19ceefb00c45eb7b9eb6063b2ee66a108532": "0xf6b21d624832094b03aa672e016462a020e217cc67b1434785b99114a2b4fa5a04763130", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2759f06bc58e1ae9850fc3babcd69da0278c0205b88370e3af02a0d22ff0411cb0335a823f02f604c692a9bb1914f2262": "0xcecae006fbf10a81337d87455340ce6112b125a971482490e02d75a27bb2c33c074561726e5832", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf275a6fd6a3d6602dc9139a95d8168f765dc19a1fb8d9519f281e155457a5ae5e30ee6cbe81b70db34a18c3bd72c67244b": "0x8c8305ff8478e6309325ebbfb81e8c1883d39e65d2ef84f88e4a428615c4927704313135", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf275d6a7d09d797ad493c7ca42a7857db7461021bfbc5b35676c92f37d8cc0205b39ca70fe448ddf0fdcf203e2b4ac4d07": "0xce5c65fecd7bb733ee636a381fa9dd916f8cca91e2e403c8aea2f7ed32b31d680e424c41434b4d4952524f523434", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf276051d7964744016a036afc75a97fcd2384e257ac2372c996a4180f6d9a9a0e16631cc76929c600468583e8d798c1760": "0xa43b2797bd4dd454d7fb0870a2a4edd62b39eea0801f6baaf09b05c8634b5a250232", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf276221853e4c1fd94a1341840328ad4fc12c7ad0576988c680601696eba2ec9b035e6f99fc5579637089d06a24d3ff650": "0xf6b21d624832094b03aa672e016462a020e217cc67b1434785b99114a2b4fa5a04763138", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf27638143342a9b45d19e9cdd58319a994282272e3e8b07aa02117d8a80fee926dde3a9417a2809b971623dcad89445a3f": "0xf6b21d624832094b03aa672e016462a020e217cc67b1434785b99114a2b4fa5a04763231", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2764e423366369b346b5e82456f9d99d1b8296804203c1734a4dd445fde8f702f106965c6a6b33e44896af15ad093c069": "0x82299cce0c148ac684639df678476effcae36c4eb8cf15592c511512a857e745034956", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2769ae8816d1222b582a1348663326c6ef201e84471e485a37aa3988c97ad57db1297d862ed5405d864708654e430260e": "0x5a5f7eb7050fb96d8d7895d9afce428a064ce66e3b094805bcad9a8e68cb99341050415241434841494e2d52454e4557", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf276d8da789c2d622987b4e50b56a1e55312c0e71d3ed7229dfea16555ba040cce63fba1fa33cd5296c4393fa61114a86d": "0x12c0e71d326f83f4e6089448e147fdab51b0b7398a7d0cc9a88b0571432e7310033537", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2770d044f20ae77f080ccbe3e419c5ca706b7a79b3d933c72bb9ae21b97fcb67d5dc1811af6d5d9c412545e6ce7eb9a03": "0x8c8305ff8478e6309325ebbfb81e8c1883d39e65d2ef84f88e4a428615c4927704313439", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2770fdb80ff3c5bcd4c5167cd26bd98751bded8b683a29a0938bbef126bd9510acfc57f2332a8009a305e94190da89569": "0x0c841e6aea307d8704d5b7b7b71afad58548ce47dce090e25d01b84925e5c48d0b43686565736563616b65", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf277c381130cdc1fe938d65794a88bc78e541a4100aab4ff5eed5dbb5245c488365a4ebe149b8c3d5462a8e7609dff226e": "0xe0d744a6f291a2dc1e6d744d5ae0747e314b046739be170638ecc185ff4a9b5f04494250", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf277ed5108a91ff85f2261e35bbd060cee6ecbc9b76728dae4396541cd517384e9898d5bec4875bdd1971c97041fa28111": "0x48ca001326b583070e370be3bc6680d09cad47649584a5c992bd388c693b9a54033132", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf278090b2e15597b078bd62990fa1fa65862d4ad80a2a5cef99de5288c0f299cb7fa7a3e41fb2db1a4c23fa44892be1360": "0xf00168a3d082a8ccf93945b1f173fdaecc1ce76fc09bbde18423640194be7212083231f09f9a8020", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2780bcbbc406269d4486f3e91d23769d672795595ce1298481aeca61391ee534ab7955411342e091fcb079401a784d438": "0xeebbde3ff2bb37ca11414154e92c0521ac8051ea48d0d84b39714b2347763648033032", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2784b955388235e67e3cea884004e14e01ca9c1ffaaa251b220fbca62f28d6936272e11d052c4e995ace722bb6c2e8d26": "0xa8b5707defe6889dc178861ea7b68861fd0ab5427b54119950e6788afe1cad2f07594152494b32", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2786fae82b1deffc5248f74a97f59a999109507526c7136932a5129122ab622dd17ca59db69ebb7ab94ede6f7992fe854": "0x52e73898bf4601f9c9a7fa052de0cc313b159dd368d458f4cb0341eedcd6d818076c6b736d3032", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2787acc23b92595203a1f562dafb922c42d3568072e73e8e73a9a8cab58e10779bcca9cc9d3da70ee41af6b5682fa1170": "0xd8004911e882a05affdcf81aea45f611077f07a29dacf6b754bb69ab118ae06704303335", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf278be0cd4c442d1e710bad9e7d0695b0a055acee05be3352c7d09340c8c6f76c87170f1072bc0ce873e529381c4f5c8a2": "0xf00168a3d082a8ccf93945b1f173fdaecc1ce76fc09bbde18423640194be7212083236f09f9a8020", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf278c49887fde38ee6df46e120c93d927c2ec9fc5a5358c74ffff03b8712e8dd1e50e93ca0babd01dff5de303a64f07f3a": "0xaed98e15e3ed392e38654215c3d1fa8143de53460386b60139fbb45c036c1b430653462d3038", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2791c146ebaf5b389673b0eb9e407ca3f6e5b9e2cbd37299c34a07fe45c6f143aa715e1bfccc4db8c82814dd82a0aa35c": "0xeebbde3ff2bb37ca11414154e92c0521ac8051ea48d0d84b39714b2347763648114f70656e476f762044656c6567617465", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2795efb02ecdcb5cae7e9002b6f14e18b8056875c26b0b99303e102f56af5b7cd6494578bfaf7eebc0f251a93a98c0710": "0x90174218ad9d5531fc97c3b347e073d347d157cc40a470ad89b75604b0d9dc3316544f4d41535a2050414e5441205248454920424953", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf279c598d130209ab0dea15637a5b16be71a7938fede32e1275281b3eee5708706d88444a6dc898a4dec463f1eb298463f": "0xf6b21d624832094b03aa672e016462a020e217cc67b1434785b99114a2b4fa5a04763031", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf27a126218545699437daa58d9f25c746812c0e71c9f53cee8937a8a3a30c639efe4e9e61faa222953bfff2cc0a782956c": "0x12c0e71d326f83f4e6089448e147fdab51b0b7398a7d0cc9a88b0571432e7310033335", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf27a35572e7224154ac488096cf4fe0ab4c21bde30a8d12e4e5d4dd612ff510d84e23afe81bdb222e1037a7c7fafd8962b": "0x4e908afcf0fb6b394bd1a043bc8b226fac33b4742731b9cde5d324f450eb3006054b563033", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf27a4588360f2c57b5fa61037c04a5855ca4242b97bcc4600c1de9c6f1a6ddb74b69d9521127a377d2717f6d9fed5ddf4e": "0xce5c65fecd7bb733ee636a381fa9dd916f8cca91e2e403c8aea2f7ed32b31d680e424c41434b4d4952524f523138", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf27a9c318a8efd0e10f68cdb5cf293f637f4c6e1ea78fa82de3a28d27e20c93b4b8109fd93489d864a73fe7bd4eadf2061": "0x50ef3cbba6eefa5127e662a1286c69c3f8cd10aa328d394df9e69919af449b450231", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf27ad4a6fbf90015403b4eca241d6ec123d8c5a6bb60ac4bf7517a02c2612d122e389ef4684a34b5f7be058113e9e74c75": "0x98672c4edf6d578c3151aa2e8d55431cc874360eff95c4592d917fb09a6b63160c4d41474943205441422d32", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf27ad71cdca583260a16b707fccc1b613812c0e71cdc8163ee018634a900a6e973a87e8740b6c9c4400ca1fae2ac8f4e04": "0x12c0e71d326f83f4e6089448e147fdab51b0b7398a7d0cc9a88b0571432e7310033730", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf27adc950ceb58a74605150858156784c4f69837f9346b574bee364518dfa08ec7723533632fbabbab594623d83157a67b": "0xface99d3401cb9b45ee1bc0ec52f4cb35914dc5ad27806230534230eedb8413d0546756e32", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf27b7491e2d554325cf8c4c05378618e11d6ba1aefd3bd5f72b993e0b6c5f9ab818e96e654e2500b1a547f5104896aa660": "0x2843d91b23b106e3020b7a903da075113d1aaca1db7ac30e119d6250fb6f5961075b315de28fa9", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf27be6559229bff0883cfccecdd480b917822adab3c579b87a5731f551e8f311cefbffbf514b27b94a6af35fc23562c945": "0x18cf1686419c41dc5d3e76d373e3176c32c6d23c755fe1fc357f9c755ffc00190237", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf27c0aa307ca274a979d8506afc7cab4d55c05d5f192c927b30b33c85470b53474f2a736a01c3c5da905384329a430f22e": "0x5c05d5f192c927b30b33c85470b53474f2a736a01c3c5da905384329a430f22e074a6577427265", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf27c41a20a0334a703bfaa50967247e53003a56ca86460efa365897ff7affd5f6d280ab3a0d857b37709ce67f551d1f88f": "0xb2636043fc3b8dfa608167a9fb6fb9d065b9f2f5821dc4bfc9785a244b24a92a154b5553414d412d414e4e4f554e43454d454e5453", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf27c7140bfb738fc55d4104789cb6dd1f00d32b36853f65bf42ac0bdd182edd4601c8503e927fcbbd1f34f1f74048cee6a": "0x08a23d4b915d29be5d2aa20f36649e004c6ee8df393064edad697934281bd51f063257696e65", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf27c7591c39b0c5a92489bdf587bba9f6db466b09ad7c824d88e8548f5587ba158415f7514a0d0dd7c18144f6503507f47": "0x12d9c0035dd422388e6d346f61df3d9f3667f8ab761c8c57120dd61917976e10032d41", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf27ce410244078329893d4dbdb2ea4a0517cecf08ce1f6f9fbe70156ec68ff04ab4ad0dffd5f39fe72c955b7f319d7740c": "0xfc5d04e7ff3965c8285a2c23aa573117deeed886bbe5e3be0974f1cf0a2ff216064c75636b79", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf27d96139d68d6f7956c00115557f1fd35402d50604742f5071645e00cf27f318d0a0fa805bda1daeec21e11ff9387e923": "0xd453b6e497b6a89979fb34eea715720d37c2381c8c51458be04296fd059dcc3a033032", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf27df1fb605d3871d347ec19e8fe964f32148e8ac56079d875671a8e379e8ce3726be04f32f36a3f8237c2713dd354be1b": "0x9a92ad7c6dcc51fec9f6d98f8316406ca42bd04dbb029d3ce454330a20fac0770230", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf27e093143bfa10910f74f3252829f6e8ab4b4df0af75ca82e3289a23c6c32eea3d2ad337ce4d335029798b3735c8d6367": "0x0a439f839504ef07c5cf8daf62beb17546e808ed1026c8a683be8207245f300f0b5374616b696e672d3032", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf27e0fe6cb9da98d799af4449535ba0076f87bd083c89d247ea03cac2fb12a410b3f44f87c1b523b0bd0aa3375d4dbf193": "0xc0b881e2db47fb95982cd5c364b87e6cdf5a5c8a336d980156623b53815c597b033139", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf27e3adb9aa8682e24ce823aa226cb8123b47150da85f064599455634eee628e2f775d06bad83bb3631130854914e96d01": "0x5ecc1b0043fe1fc18950cef3726fa74151bc41f77438ce924c11a9b43823ff43035633", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf27e3d25abb9b49e97f19f73e27d4537613789e73dd3cb036f57dda3ed96e000aa87721b8e19205610d2625e3847f1a06b": "0x2aa53f55efa82a9820f3c2569d4e52dc467475a1a11cfc9861ce5440316edb7a0231", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf27e65087dd946c27bb1e415ac33130b0fa65bbeb4425c55a611da4116e848b0cc39686a11f88dee6aacceac6bc5eca657": "0xda9f7fd3d9612a68d2ead69dde53297b172b7db514d0d261e7c5be987df7f32a0b56616c696461746f7232", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf27e67883c4dafba8127e1226fc8e17468de4a3a5ffb49ce7652bd6a9f98cb78bc68c2360c6e55fcbd6d6d5aa6b0f2347e": "0x86b7409a11700afb027924cb40fa43889d98709ea35319d48fea85dd35004e640a4d6f6f6e7269766572", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf27e6db057075a669d13d6945b30d080b0ca4acfb773d3f44cb7ddeef0caf203eb82d3366bef8d775a0533ef152431b633": "0x3870abfd18505f673c1808b61dd0d7067a810a9719c2ddee18f9b879752f4c500b53746173526f76657232", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf27e8190ad4d57e14b3155b7177b481444b8774ed1e7c90fd0dbe40fe7c6a8d810484ec59624b59374a38a8bbf9d91ee1b": "0x9c7c545141ea2dd84fe5ef7d567ea450f59967e7afa68e5f1ff7f7c46db19627033731", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf27e910be4fc1f76c8e2dab1e55ea0497870d7ff9f5cd0e46762d7d7d1c8dc840a4026755fe13c51237ff8601377d4fba3": "0xe8b2603f6baee5bc32a9b9e4eee9168499fa553d35edb56aef0035ff7e1f165e0c314b5620f09f8c8defb88f", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf27e9c08143156e82cf22a2ac64d702035d376b1daf289d513fd22426812d5a7c48a58dd121e4c043627e00fd216557873": "0xd3754204488186b41e90a93d0607992b9cb992932ff66c2faef8a984dfe4a23408436861726c6965", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf27eb0fb5da726390701ee9c4cf250c0f162ef7ddde3d6fa33e5b617265ea9af26a64e1248c80b7ac1cf2df7b171889b6e": "0xbe4bc35b26cdc006c69c1f827d4bfa75e4bfd4ac0094ceaeec8ac70469cac51f065374617368", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf27eb5e19af9fd94f13790c96dd5753144ca5164772b835ac12c7e86d391ec217e65f05be0f43b75a059fdb0b3e8a1c44c": "0xcea3dabe52b2a665b1e19bf8c6913a5d54e06d6413ca3ddbec8f9a22415ec47711416c7068612043656e74617572692042", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf27efd2aa9904d84c78e70a8cdd10accb1a46e73069e5a05c232b0487e1523e7a426270e43445d0dbc1744222fd4f6881c": "0x60c6e940d5c74596755e6bb1b31ec98958db10d841dfaf66954b5542c95c462b0232", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf27f04a065bd619df1e2c308279dc9e8525b7812d3e31417cabe45153f522a4047b09e9662795cc7c7372cfb02f6dc3919": "0x04c73bb4b37fd89e159ea8dda26c4021a4af572826ad6397d8fa9942c18b356804554b32", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf27f1b8c1c56d4f27630206a19c89ac452809246069a0bc7cee32210e5e5c1a523e10db11d0d86abd29a3979e68dc01725": "0xc46ff658221e07564fde2764017590264f9dfced3538e283856c43e0ee456e5105444f444f", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf27f2b05bc2867bdc02f22b17c1ef504f412c0e71d4b14d52ccb248e416cad1ddfc7283a09f2625c601528d29f9a294b4f": "0x12c0e71d326f83f4e6089448e147fdab51b0b7398a7d0cc9a88b0571432e7310033139", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf27f35b91401ce6524d9a9c7fb9ed03b7e9c322a9e20637c9a71e4d131e647d597b1c600dbec94bfa192465e3991a15b63": "0xc0b881e2db47fb95982cd5c364b87e6cdf5a5c8a336d980156623b53815c597b04423035", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf27fa714c6ba99619fe4c576dd89b53a722c61317ffa5f84e38eaaa44e333ca7be9924b445ee9e6e275421200ecc58a9b0": "0x0ce0bbe155c5f116187af43bae0bd493872f436a139e23d9b26289d0721a310e0c56616c696461746f722d31", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf27fb6191430b9e8731f77bb822cbcb63631918cb9b9c9414a2cd4dd7f720cb98fe98cf852636fc4860845767989127e7d": "0xc5c184f0565e2192d6aedae584ee736cef875f0e1c558ee3ede26869acd0b4d609436c617573697573", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf27fb74f09333c1c1f27317b348c589ac9e66afee7026bccb1c5ccda9ff095c278ca0c40c7d44f645a9e60d2c1cf49a305": "0x0e993f475e1085cfe2d313b1089c3fbc33c78c178ed19bfc94be3d7937709371033031", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf280129ca7dc0d15001bcc0788918ce3522e4e174e782224c6e32c71c85d399497af3cd209216738baf31130ed860a5877": "0xfc5d04e7ff3965c8285a2c23aa573117deeed886bbe5e3be0974f1cf0a2ff216073033f09f9a80", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2802d367e89bc722851768bfc9c0b56e54ab3e893de103d05f3e6e5f210faf6fb40fddb03be173eb3723cb33a074faf34": "0xce5c65fecd7bb733ee636a381fa9dd916f8cca91e2e403c8aea2f7ed32b31d680d424c41434b4d4952524f5237", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2802d8d6177c25397d6b472b80ee0fd824680cdf69422609ddbb2cd596ee4366b84a50a3f17c0a88b9fcab7263852cf6d": "0x0cf88657e8a5e5005c67c0ae58b0ea1137b817f32d30d80aba618a70b13bcc66095452454153555259", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf28045e484681e088d0d62e4869fc4bc8a45276fb671d5e24c15c73f6766680b83e94bd709644fec1d5829f1126ef1fc2a": "0x1c6d8b40be9990c19e993d238e6e3613cfc6cbc51979d5fa61dd6ea2593856090b33207c204b6172757261", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf280c3b7f80f0fe6e3c42e1c83a3f87ad94ec19498a19021a78fbf00ef07d366245bad3cc89f5837a7004b97a50c4a5e0c": "0x128e3b8a2d3b98071ba399c17206f84350e65653537dbbd646cb5908efff9d49095374616b652d3032", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf28103ec254905fc4b190f466efa2a392ea2fa6c11ee56da6d5e51439a0d0ee776c8b4f0f6a914cf6bd9ed8af27db80252": "0xfe6c31fcff28694469c3d4c1681270bdacf6edf7ec39bda6c68cf25738268b79033031", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf281126b31c52b0e9c700b2d2c99137dfdd6e2246ffbf94311de0e749da628bfe1b40ec0251caa056fc6c2050b09074a3d": "0xc46ff658221e07564fde2764017590264f9dfced3538e283856c43e0ee456e51054a4f4a4f", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf28118461768bfed729087b69e9d3a933188d38e0b14f3b08bed993ea4fe1b8ab124190191340fe8de0466ea642fd56511": "0xaed98e15e3ed392e38654215c3d1fa8143de53460386b60139fbb45c036c1b430653462d3235", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2816611c9bceda771f96e2dbd296f1f5fb0bf0c9e4095ac5ab829224395315bc4e298b21b180d6e9a86e698f974d2fa25": "0x8e76c9299f5a2046beaa5266ac0ef8b7b310c929704f15d8e6657b371302202d04303332", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf281665f2c6a2d1f21c042ae5f12abb684e852fc4a048379bc123ee21bdeb4c6a4d94ee131b0920ad219d6cc280b0a0965": "0x9c7c545141ea2dd84fe5ef7d567ea450f59967e7afa68e5f1ff7f7c46db19627033137", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf281c1d78d5b5076693f2571911f26503212c0e71cee9f575993304f4b1b5dd21ab495dbad0b4613f39c8c4f49ef241406": "0x12c0e71d326f83f4e6089448e147fdab51b0b7398a7d0cc9a88b0571432e7310033036", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf281c389c2b60c4655dd7ef61ec53a85f9aef5713b3583a5730c08c16d252f9fbda97536c8a26168256b998f7e9fc1c602": "0xc46ff658221e07564fde2764017590264f9dfced3538e283856c43e0ee456e5108504f4f4c2d3133", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf28209abec313cd5f943ac7567422cde1613ea937fa9da7a04ab5ae026b321323ffbc3f6ffd24898500ef3eaa6b2353613": "0x008d8404893c7b4b80f397605cc96e61fec3c89676c8c2794a2a7d281d678b1a0a4d455a5a414e494e45", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2822c9bc287e6aebbdc3e6070407a7ba1c0f326fa9866f007e8ea4125d5364b3d7061ebbbd9a24341c40a3ad8de3d113c": "0xc46ff658221e07564fde2764017590264f9dfced3538e283856c43e0ee456e5105544f544f", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf28239334393b581161cec98eb71582d7ac0e9ec31daccb76e9baaa030b5780a85787b3f1e2ef54fa8f4b857c64552a4e0": "0x4ac4eaed36e5c54f045b46cb54f533b2d3949c0ca7137e89ef03ee3f56f8155f05f09f8ca0", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf282c93184ede0ab8f89b93d497d0e4c4c12c0e71d1e59aa52904247d6ede8d053ec5c65dfb3dc8c1e632acf34c030a255": "0x12c0e71d326f83f4e6089448e147fdab51b0b7398a7d0cc9a88b0571432e7310033134", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf282db2fcb58fad99c289f7a86656931e12eab66a1c3116f15f55dd2996db419e367106043a4c5491a5eeab1d33a17460b": "0x02bf32e061073c44300056b416cd66a4fde1e6c120dbc0089bb65134f5693a3b14636f7265626c6f636b732d6d756c7469736967", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf283189914382e0e073a81098c8a4ceb1ace4f4b5eb5e648247f1796de1f52ccb6d6e763684ab786e21239f26af6d8d252": "0x9cb0d4ddd32f9332dac7059de238b8e489afb55502d1756d7f50b78b58e20c700233", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2834e3c780f4d8c7f3fd1c165f191c43040d9bfa0963116a9e97d84f9888882bdcb6faa12332997b7f5b83c7c75532216": "0x8c8305ff8478e6309325ebbfb81e8c1883d39e65d2ef84f88e4a428615c49277067465636832", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2835fb70434ad8c544e7161ee304031d7026d79399d627961c528d648413b2aa54595245d97158a8b90900287dee28216": "0xa02f7333e25590e4f568ae8a2ddc93a879e92e48fa3cf1666ac56e020c106d550c53797374656d436861696e", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2838555451ee7fa38eb18cd328263423ff67e4658ee318d7985399480025fa332958346cd623a025948cae8a7db36a81a": "0xec8c97edfab0a07c37625d53be2075b8ea64a00ca71d80cffe94edb44d215e000e6e6f6b6f676972697372762d32", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf28388939cf4687fd61cb25dde536b3f654aaa077ac4202f4f7e1135489106099452441129dc5aad89cd5dd4335918fa3d": "0x48ca001326b583070e370be3bc6680d09cad47649584a5c992bd388c693b9a54033033", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf283afa21b810c73cbc3a8c068a6fefcd912c0e71c9d62c402a345adadf6d07c72b92a9df6035128105150414c0f759a23": "0x12c0e71d326f83f4e6089448e147fdab51b0b7398a7d0cc9a88b0571432e7310033731", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf283e226ba71020eb0449b4752d08be9c9ae3aba9a0f0d03d9fab3ad97a367fe66aba07ac0f7fc58d8dc18eed82f8c62f0": "0x6c335d86444f3189027cd53244265047e52a96b4621fdaeeb9bc12857789867608e29aa1efb88f33", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf283efe88997adcc154bb4c4b7506e2b55463b64f13f694e789b1c89d219210b4aaef27fcaf8621ce8103f88e3951d054e": "0x9c7c545141ea2dd84fe5ef7d567ea450f59967e7afa68e5f1ff7f7c46db19627033536", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2840512958b7adc1d1931d8b4abc0d5f54caba24b45e5bb6eda6ae45de9e1fd6aa64fb43bd9086694c4935d21872a5502": "0xc4516751df2e5803bac3bf9cf7b6d55cf4acbd76f861ad0a2a2b71b7a5ed805407f09f98883133", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf28418b12c5d61f6e70ec0578815a44633a8c96b926e3a1baf17e8f1cab2e0df7229b36c661e9d29f4c005b2dfb0835218": "0x6a1e7cf7558378809fa376f7eec7b065d30759f8a4e7b721ec2ae74b313f08550232", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf28424750cd8689f881673991db45b14823cf08a632438014746be9061a9a74ccd8d79204032cf03d8fc605d452647c133": "0x1eb38b0d5178bc680c10a204f81164946a25078c6d3b5f6813cef61c3aef48430574697073", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2842add3765cf6536011a29b408969bec8e602e63afb364ac583747b0a8bab092d5b20ee98f0495ce7562a8c992ac9f17": "0xe4a66ee66171e3238670377bc9ffbd7cb4bda47baf25e6ed80c2070942ee3f721070617468726f636b6e6574776f726b", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2842cb762bc9e90f859325df5f7a1b7f5dcadf01d571672f755b4032af1cfa3784d389da711ea341209b86f840784937a": "0xaed98e15e3ed392e38654215c3d1fa8143de53460386b60139fbb45c036c1b430653462d3331", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf284dd8e83e4115e0710c4a6f92f8ef075f2e0c893582b2b34b415274bf95b65f52ab82079a097a9ed28349eb9a7bae745": "0x38a48b1b98077c557c474ad091c854286fdf929b0e710299b16daae9e0ae4a77064d61676963", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf284e13b8771645bb9c5f38e0d81e31dd8c0d0a4ad7841c483d4cb7813af9550c9d7c1b182613bf27a900e5211d9b64d68": "0x9c7c545141ea2dd84fe5ef7d567ea450f59967e7afa68e5f1ff7f7c46db19627033134", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf28505622504ca5ec69b4ee65beb5a1d47bcc2112d8a9de4645c4ff651aa6efa2f301c9d6a2355f1bf0e6a80826f50016e": "0xc4516751df2e5803bac3bf9cf7b6d55cf4acbd76f861ad0a2a2b71b7a5ed805406f09f988833", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2855c311b5e502d7a7a2071f1b2e5875ce26714e05311dfb5e182d27b7f0e2c399c96ccdd81c25cf47e9c61315274631f": "0x8c8305ff8478e6309325ebbfb81e8c1883d39e65d2ef84f88e4a428615c4927704313038", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2856044625ae62eaa06af331bef9b4bf3e848eff972706bdacaf38bc657028f303d44bacde7b359b8595fe7a4268e7418": "0x008d8404893c7b4b80f397605cc96e61fec3c89676c8c2794a2a7d281d678b1a0b47414c4154412043544c", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf28572931292aec8386fd2265b8a2ff8b68aa121a03ca81740284a3d24ea4bf49f22578caa58441527a76e8464a319a015": "0xea6a0804e0024beaa87fc072eb250446162310017e52147d18fada54a8ddb57b0236", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2857bc767f3c97fff988fd0f41b34e326b8d56768e91cbccbdf754d7f60db1fedd96eae27b591e65d2fc8afb99b27c20b": "0xaed98e15e3ed392e38654215c3d1fa8143de53460386b60139fbb45c036c1b430653462d3137", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2863d51a50e2a040df6b12294462b8073067a2e439cc384440cf187331543175270b479ba695e2c4d6ba9528bbb6be460": "0x5a5f7eb7050fb96d8d7895d9afce428a064ce66e3b094805bcad9a8e68cb99340e50415241434841494e2d464545", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2864c5bec13d1ff0385cf6d3d8593552798672c4edf6d578c3151aa2e8d55431cc874360eff95c4592d917fb09a6b6316": "0x98672c4edf6d578c3151aa2e8d55431cc874360eff95c4592d917fb09a6b63160a4d4147494320544142", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf286a26c691af61a1cf897f552bd881ae68011fa4c76d86408e873beeae9385075b1f735e05b59dca7fee6147c14952770": "0xbc63ced3f8fec642128f2aa9c37e989a9313a67e9635dd85e8bd689ae8d0ce1d0233", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf286d609f103e7771c593f381b2d26a7fe03460b53d4200f03a8183f00d5ed6c971942ddae9065693b4702f0f782e5c553": "0xf00168a3d082a8ccf93945b1f173fdaecc1ce76fc09bbde18423640194be7212083134f09f9a8020", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf286dfd59b7c01c1691d8f25c46f1e638672b86a19da9f10eab2fffdb74143afea62356c6896c265dd18207867f2575110": "0x8c8305ff8478e6309325ebbfb81e8c1883d39e65d2ef84f88e4a428615c4927704313130", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf286fc3cf7a3b78ef39d1b9799193dafecf063c0ba3d0dfdd209dc5b98dee86531ad264283fce758952e49f8e6b7f85c7c": "0x54ec6a7bfcee3ac00ab63b98e084f1a1c4d0e82ff63c31387aee91c9a721a81e124e656a6c6570c5a1c3ad2073c3a17a6b61", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2876b89c310e3d0ec6ad7349ca30194ebdeaefd68c861d01a4472a1c518bdacd7f99b6c4a0b64ba32d74995a21405797a": "0xc4516751df2e5803bac3bf9cf7b6d55cf4acbd76f861ad0a2a2b71b7a5ed805407f09f98883132", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2879951c2d47788d64c265a580690d0e4c0c86652faff45a0e4a86f5749bf813d9d40aac848b8c672123d7ee2503a6d53": "0x9c7c545141ea2dd84fe5ef7d567ea450f59967e7afa68e5f1ff7f7c46db196270239", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf287a93ca2110fca6305fdd39cf046eba06c6ed8531e6c0b882af0a42f2f23ef0a102b5d49cb5f5a24ede72d53ffce8317": "0x9c7c545141ea2dd84fe5ef7d567ea450f59967e7afa68e5f1ff7f7c46db19627033338", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf287c93e4e09c3118cc211d3fbf53f8c1a305b166542492b1615c15fb92c573ee387b90427312d08338b9c211b85a27a20": "0xaed98e15e3ed392e38654215c3d1fa8143de53460386b60139fbb45c036c1b430653462d3135", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf28810385af8152cbd391955134fba2fec81a73b784a15727dfd555a15f61575f5f1b8323b8fd41416dc9eeb4df87acd23": "0xc0b881e2db47fb95982cd5c364b87e6cdf5a5c8a336d980156623b53815c597b04423036", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2881932dcd906c93391a3670833a85edae8e0a4bce889b5d71d9c9dbcd6687dfda6458cf22bca0a342f5db49d8258ca6a": "0xf6b21d624832094b03aa672e016462a020e217cc67b1434785b99114a2b4fa5a077061796f7574", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2882e5f9d02a3ef933907e7b8449417cb12c0e71d4ebd6afa6a6462c87da8f8da65e320b207a3958a76e854432b5cdd02": "0x12c0e71d326f83f4e6089448e147fdab51b0b7398a7d0cc9a88b0571432e7310033230", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf28869befdaf019f3f68978f837aa0a6b95ad7885e61fefa8373066bbb08ffe85c08ecd11bafb3a9f85af75a4eabffaeae": "0xaa7880fe9ca2bbf331fc13e40525dcb0da661f143df506fed76d8ada3db8f55104303031", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf288a6f5506c390ba1d001f320e2245f4328e219b7c6307a185ea3d7d203fcbf5b78176fc0601cd62b1a3ab95e81e06116": "0xbe4b9973a7f6a5586a38fa295ec8e64d4026aa878c840630a7ccfa7f3914d1620d474f424c494e53414d412d32", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf288b83d271455307fdb42a6decf23918a920799b25e259ab600be83eedfa7807ac27a842f005dea4a2bd49799840f4b3a": "0x52e73898bf4601f9c9a7fa052de0cc313b159dd368d458f4cb0341eedcd6d81804763033", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf288babea6cf0a5b1540770a29aef8469f6cd55c3ecbc354fceb81b0ac3ae860ef4a3794e1aa9e31477de7c2cd36ccf11d": "0x8adc4e19e79b3d2c744f88fa5aca47ef05ccaae141f6435c2d50df824433ae480238", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf288bacc16a6990c6752a600138df36bbfa620a613e0049a85c71fab0328f7449b0a9963195eab763760e1ff50a10d4404": "0xce072084c159fb3547381b718ac1660d14030e7bcbe9db68eef0f7c0e340f33b04303035", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf288c132aed752df1ffc83e682e8cb9c0ed228fd275f3f92e8b6ccc56a9437582dc59db70153ab33cdd77562661adda60f": "0xf4914e62f037cdb798c40ea01fd56e555b77635e0e9b7175b98bc9514021756c0f466f726b6c6573734e6174696f6e", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf288dfcf7145a2d07dbc6dc199850afacee00e404cb030e7bfb50b9615ea9a2f8f75601ac9f6128d1263a7fb5d22de741b": "0xfef5977196fe3fe5c456a767e6b06013ca62762b282de97040add4ad2c53db61033035", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2894d6ff01ce98efb73b650a4b774379fd8900a50ea497ab51afd5227503f91b03a91584b72146c2e485d149cf67f543f": "0x8adc4e19e79b3d2c744f88fa5aca47ef05ccaae141f6435c2d50df824433ae48033130", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2895a7e0c21e153c5b1e9c8ab30676264196375cde4e10495687128f72d513b94bc323bbe7dc36f305133ad7cea4c6da8": "0x32068fb3b800c5df40df16619761b3418e40d9455784b6a293d2425e35ef2c270b434f4e54524f4c4c4552", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf289a5c85a2b62855cb64f81d7b447d8c3449e6184747b236ba5577c3560b7739e35718c65039b8997b7e723722512b310": "0x52e73898bf4601f9c9a7fa052de0cc313b159dd368d458f4cb0341eedcd6d81804763034", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf289f0c7284252c2b2bd6111539764c636ca0ed2d57f858e89592c76cad4ac00258041aaccb971171ea43b6fc39a4c4c1a": "0x9ee1fa0d8d4e022ed5680b5925d19718a7ecc9f8f2ff77de54f0822978d277551253686173746120436f6e74726f6c6c6572", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf28a02d541d624e3f86986ab3c97423cd412c0e71c89b2c75caab9eb9b3ee5a918dc734c5c595ee569e64ed37a306de974": "0x12c0e71d326f83f4e6089448e147fdab51b0b7398a7d0cc9a88b0571432e7310033837", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf28a2068796da680669082c83b0d8ddc6aaa580379e5714c790f17e4af93773d158e30eb08f5a4d24abe4f535776b5721e": "0x4edf81ba4fbeb6ea13cd45ba93cc1d689a6e2e5c6dfc35a458a971823a3242180231", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf28a2569fac8ce42fae78d6bd23582abeb927f1c23cdd2161cb6bf0da7abb4dd94ce6a98ff07e9fbdedfe96acd3d7dbf5a": "0x8c8305ff8478e6309325ebbfb81e8c1883d39e65d2ef84f88e4a428615c4927704313132", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf28a4dff2cbc5c84c220d46b8114c4fcdba27a87e5999ee8830465b09da09f16adfaa168d3aec122953b44796a9db5157d": "0xea6a0804e0024beaa87fc072eb250446162310017e52147d18fada54a8ddb57b0237", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf28a92e7bb0410302274121a546ca7bfe212c0e71c9fdf776b26f8b4def79ecfeb98cf14bba80546f54124e4725da6036f": "0x12c0e71d326f83f4e6089448e147fdab51b0b7398a7d0cc9a88b0571432e7310033739", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf28ac86cf8a962a3e880c844ddcf10c77a611f3cd11a51748d355ff0686f5c5bbc2a7b0e91b6efa0fb4f9aae77c53942c8": "0xc43aabf384c6baf54ef9712a96be7c46533b538c05d4e6c687fe09b109664b28032d4d", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf28af49ed4bd7a685e31f6b770f74980cc305b166a309fbb4a05d24e70b726218dbb1b5d3e8d4e1488524481032e0acb00": "0xaed98e15e3ed392e38654215c3d1fa8143de53460386b60139fbb45c036c1b430653462d3132", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf28b40ffa4ca5650f8c82e80d8155f686124edcf58959173bb907319517828c0e5949a178917099537bfa4895695e5d00f": "0x98989f74514aeaf57d4f41069770242a83d619c9ae5d46cc05b85136edd537760231", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf28bf47da292b8ad6c3110455ee972d87afeddac420e696be2b3c613261dd7d84a25b6410eca645efd87d9f4030c7bbc9f": "0xc0b881e2db47fb95982cd5c364b87e6cdf5a5c8a336d980156623b53815c597b04423031", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf28bf7bf3e9db575299831af37682643db6ec238210f082cca5552aa2ce9a0d1c4be9c7bf44c04f4524ded21f8cbcc611d": "0x8c8305ff8478e6309325ebbfb81e8c1883d39e65d2ef84f88e4a428615c4927704313232", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf28c09f47aed688f8039f80ce6956097da3525a2d8318f0a082d428d90eeeccba905e0001fdad3a04d6abe49dd79e15186": "0xac33b989d0b4dd35d2fb8af4cd04cc5a3831e59023cb884044f5cda0541f1064033035", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf28c1dfcfe0f7184d52ec4bee559507653b2f0176465f8cf99c213696538dac784ba8c59e4f577c6fa88555bb5f28ecd35": "0x749ddc93a65dfec3af27cc7478212cb7d4b0c0357fef35a0163966ab5333b7570748656c69756d", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf28c5e4b05bb62da0cbac68ac69e5ea5acfc0b298393d72240ea0a06586ea1227e8c84f786c7fa05879e1ff28422017370": "0x9c7c545141ea2dd84fe5ef7d567ea450f59967e7afa68e5f1ff7f7c46db19627033932", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf28cad469349d96aebe667315ea8c7f907daf0804d1bf147f716661acb2ce7c796d0d655e2781c22cd138c4e6d6edb9b0c": "0x9642d0db9f3b301b44df74b63b0b930011e3f52154c5ca24b4dc67b3c7322f150573756232", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf28cb23603f98695797808da60a37bd11f97a78ac6bd50295c46bc350d252714c70dffccdaa6c1740dce1da940acbec1d1": "0xd2cfdfb80cb90a4a5826c98846a367489fd25d3a2561838fa372f39f3f7fb138033031", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf28cddf503217fbb2c01228e3df0cde1322efecb509bcbfa0ebbe40f7bbc6a74d4a90cfd7e982ce06c2f11fdcc70efeb5a": "0x7c7d2fe83c4af79c49136f0f8c5f1a00cd8d0aa91c94fe74d0145cb96d688f66032332", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf28ce13b0ca6e2330d9c6c2ea7d714324cb4f54529b00e5295e6efaacfad2de17a22cfe1466f2ef142caf1328b5a701005": "0xaa220871834d1f214169691dfd97c70823d90d192b246378dc01a59daafffe0d0e48797065727370686572652d33", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf28d07f92145d67784590a148189a6ee5d9654bbc25d7891d49151110003c37da87fce6eb551768c02e47eae754b61b466": "0xc50f089e43c19f3f4ce606cd994bbecc50bf8dc53e970c0c1c592304f651966f033032", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf28d219622e65973214a92fb842af92ffd4a18d3235c574d9f25aa3371f0190be83bdc423f5b77fc310390e753b229a952": "0x8c8305ff8478e6309325ebbfb81e8c1883d39e65d2ef84f88e4a428615c4927704313234", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf28d3a18f5fc9112db250af9b04d92a7bf402b7e0857f31fc28e9c6a0f0970cc810b66ad393edbe120b4d97f5ce99261c9": "0x88e89854ec5f225c9a3b8889d4b1afc0cf6cf473d4265a96463c08cccf38905b033032", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf28d67a84b4069a6f636ed06dd005329f1120460743583c4ebc3076d422b73bef41b48b87e6c07aeecb07df3cf95565eec": "0x128e3b8a2d3b98071ba399c17206f84350e65653537dbbd646cb5908efff9d49095374616b652d3031", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf28d7e3c6390768290af1abc5436b80b2c97d5a706146081fdd5ce77ad4ee232f351c4bbbce94596c12d300efae588ce9e": "0x142eba87db082b693b5f35e88d7a70409b0ddb61d430abf218884d4467af102404303331", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf28d8c1c92a879346f1453f6ee18eec0a51af4af68069a4772fc4e73cba9d1479943982c64e124ec73bb1cbc70f66bcf3f": "0x00f53cf59ee4bae1fc47b5df521d48a3cc2d02d5c15fd5d3bfa3d6a4a2e6a57611f09f8c8a4164726961746963f09f8c8a", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf28dbbdd354383e9438731c56ffca55a16ce10c51e89ab2907983cc8b846d9d1afa2f9700db18e176c7fcfe709d0406339": "0x86b7409a11700afb027924cb40fa43889d98709ea35319d48fea85dd35004e640a53746174656d696e65", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf28e26c50c3f1787beebe557f64b5fa734289fad9cb619fa9f9b77fd385d003476fdacaaac6ba7191bf5486aa09e1d8329": "0x707c9246c1c227f1495885cb2f4c59297248ec5abeff2d0f68495075a16bc17a0231", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf28e94df84b52d02aa15ea48e0b82af07954ec418763624a46b49693114ba91a0137b37c1e47cc3fdcb2db75c9c4b11c79": "0xaed98e15e3ed392e38654215c3d1fa8143de53460386b60139fbb45c036c1b430653462d3033", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf28ec2e6f95318a0783a464b6de2c96a7a5ac7f6af5aeb5364188840d02f0e74e813e6d9cc0398d6994b66727658a4fb30": "0x9c7c545141ea2dd84fe5ef7d567ea450f59967e7afa68e5f1ff7f7c46db196270234", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf28ec9397fb62b151d82d56c66fb216bbcc20f540f6c1dc4dba60d21936788a5bc5628f26333e27b14cd091145d92d8f25": "0xf6b21d624832094b03aa672e016462a020e217cc67b1434785b99114a2b4fa5a04763239", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf28f312e4f679915416400fdf70a92471ffa98b8b13a1b03a3f86748ad19edb237b86ce74b4c4dcc08492907df447f7026": "0xfae63fdb20e3ec7589586b14ea019731b5089e2d1b22a7911e48603a5939780c0af09faab432f09faab4", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf28f3a49f3d43586e2ce50911aea0140960002dd621e14bf09425ab305ae1139310c1c0f78f2d3632c7ea507feb7f82900": "0xcc9f261e20561ee1a137a7c03770706d09a6f85e36e7a313f04d92faefbd3d43036b32", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf28f7d791d3aacd3d0caa46c42e0da75e3463e61911efe5b07ac64fbdd0b388a7b9569d067a6a34f01ce88bbfd9357f29f": "0xac33b989d0b4dd35d2fb8af4cd04cc5a3831e59023cb884044f5cda0541f1064033031", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf28fb4051b925d1271466358365212b6bd564491c88a293f54f2fe2cc09b0ec63f226bc77ebf6df8f998fbc7551d0fa10a": "0x4ec0381e4427ed6567f7a5c328288ced36c33becea6ececd8145001f4230ac1b0d59542d5374616b696e672d31", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf29025a41e3f449cd46ef58c63f3e1b6f936ed432555d82a6fe15f2517dc871f1d02c72d8d5aa1bce703288d180ff1fdf6": "0x1c6d8b40be9990c19e993d238e6e3613cfc6cbc51979d5fa61dd6ea2593856090232", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf29043b6de8dafbecb9dfde02a5b7f5431b65d8d7707042e22fbf2213c687b330cafa3a792598536cb5fef7aef40cdf07c": "0x9c7c545141ea2dd84fe5ef7d567ea450f59967e7afa68e5f1ff7f7c46db19627033933", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf29065839bd178183fbfb7fd12220824f968ae914b1cddf602f7e775099eb62db646dcdabf6c32fc0bb1b951e94130503d": "0xc229d8ccc5e5650d17760ce2b7c42bdae5f6afc6e8bab249ec77f3f779ee5a651331363a206e6f64616d61746963732e636f6d", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2906e1529cc4bb4c08bcd87af5938145d5aa67923621f3a3395c3e2a58aeb89756e2dc11ba9ef1ac8bd4953cf2a220134": "0xfc5d04e7ff3965c8285a2c23aa573117deeed886bbe5e3be0974f1cf0a2ff216073130f09f9a80", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2908b71a779b8f1d7862ce857e0e002cf2494641f85af0c7f9d2e3c942fd250dd7c2ecc7e5dcc401fb3ebca0573edc571": "0xa49deb88afa394b7eb478483a65a8c8f060b7de319dc6f65776a84d9e8f40e7e0a4b534d2056414c3120", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2909433256e5279bada3397b9805dd81195d056d702a9431c14cc2c46634fcb656e162dca4b5a2100789373a07695f6b8": "0x6a81f13352076dce1dfe8f357fd805bbece6ec16efabad52a2c24e6824e163150fe29895455350524553534fe29895", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf290a1cf6de13c900c2fcaae9a03136c1012c0e71d5e85f0442d53fd7419af7a23a2908f88ebcced94150e396bb64ef644": "0x12c0e71d326f83f4e6089448e147fdab51b0b7398a7d0cc9a88b0571432e7310033631", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf290b3eac6dedb823eb7dbf9f5615bc0d412c0e71d2ffe345813bd81eea02b361a65b0b88ef0e5ee8a0a2268a8ad9bbe2c": "0x12c0e71d326f83f4e6089448e147fdab51b0b7398a7d0cc9a88b0571432e7310033538", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf290c655b3d9ca5d7affde1fa4a89e43b13a29d1002e1c81fb779d11e082da66b45a355067ab816aa015f5d5ce3d927068": "0x9aa6373b24df370b863773f45f2bed6ebd80c886c58b4232e655a9b130b6d6150b626567696d6f74696b4c", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf290cb66eb914dabd4d48b3ddf423383cd12c0e71d0f4707cb93bd1de1eeec36c3e1f995dc51eeedba0cb52287d2fd3c7d": "0x12c0e71d326f83f4e6089448e147fdab51b0b7398a7d0cc9a88b0571432e7310033439", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf290d41166ba1e5993da33382795bc0a692c1800d8039258f2722009625f77a8203729e8770d6ea72358f165350233ec25": "0x4e531ab22f712634089201978511b49aa987322314dcd8f16fa241f0055e37370c4172696e676f74792e3031", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2912b1a223b3e6999688bbf8a97215ab4b2dbc35ccf086294a0d24e1091d08ca3b5c2a487071c4fb54070e666cc99e02d": "0xa2da2913d7db19baf0a41dc40a73d75bc6001ce1691c3ded78e4e86387881b4c0233", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2913af7f52e6a8ea6b296177ebc40a7007a0d37cd4a96cb4e0445c91d19d6c84856f994d5e099e0f911b6855605833860": "0xf89b361ea400867da22fa6a069fdd840819fdc24fee6cc3763b6cf3a8a20246b0d4441524b2d4b5553414d4132", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2914a0e6bd3ba3602f18f7a4d6319f53d70610bb9d4abd640e545cf56c9be0e8886b9ec274ea2e4d7facf8dbc575a9447": "0xa02f7333e25590e4f568ae8a2ddc93a879e92e48fa3cf1666ac56e020c106d550230", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2918147e4e0e94d353be1c6c52c222f2944ed131039b1a6d98896aa12e996d928f7adb00a832fe5c11b719e7d4a4d9b0f": "0x1a903015b9ceaaf0f183eb409d3a38c4f0c9a685066ed90b32c834940c689e1c0231", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2925b7f992eb3af442a5645737c1b4e09216959aedf96ab893d8b8d8c66abeab8ef62940b1c6a6ab7228099d72291c72a": "0xc0b881e2db47fb95982cd5c364b87e6cdf5a5c8a336d980156623b53815c597b04423038", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf292602536a51c4465ab513af925e2592514a4ee7a1c85e78b96211b9af1d020030203a9d13c0eac03f4106dbe42d68314": "0x8c8305ff8478e6309325ebbfb81e8c1883d39e65d2ef84f88e4a428615c4927704313436", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2929707b74d7370eaabcc6859872c2e319ac3a89771d2fc8c62e9d37bc6548f67306caeeb4ba49e7aef7c09b68a260665": "0xaa220871834d1f214169691dfd97c70823d90d192b246378dc01a59daafffe0d0e48797065727370686572652d35", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2929a52a46b17027d6d5846b66bf982e3d76236f0c5d432f6e6b99845a7eada1491dfa6288c36dbafe21b45a0d90488d0": "0xb45b073f1e692d18c2dcebae861b2f166a4dbfd95d9780ffef603c9e61d009350a417461726465636572", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf292b9e3cc674216db6bd2b3a683ed65d66eb0bb735fa04cc282b87141ed4d60afada62fc213bda5ea0d0569c2a8c25d25": "0xcca9cb5657907dcb0bb01d335b17564e77994536edd05ddd50524a9355c2221e0231", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf292c8146024721c651afec91539049cff4b514120fe1efd6da4118dab0e2b1fa66ff2eeaab54af205b2ec6c506b52fb76": "0x2c08cfa5b2dbfcf6850a3b836596d82a9ed7d2d743b42aa5c69798b502b29b57033031", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf292f26db9e1a10596464efc932b402ef1e5c49f7bc76b9e1b91566945e2eb539d960da57ca8e9ccd0e6030e4b11b60099": "0xd3754204488186b41e90a93d0607992b9cb992932ff66c2faef8a984dfe4a23404537973", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf292ffa09d38524f9c0d1aa774b67c212dcacacf100cec1782c4f9342566de5b4132a012335481dc83fb4d42bcdfcca853": "0x3a0b67c6e4b35133a18ff9c3b56d6cd28662f9e47f38afbfc508543087966870094355524154494f4e", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf29328dcfaf4b0ac7a274e9e4316053205886a977a6d8063db1b9c58daf3906841f3e2577b07cee9595c5c7e98f7b3aa66": "0xf6b21d624832094b03aa672e016462a020e217cc67b1434785b99114a2b4fa5a04763137", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf29363108295e372daca2b92b7cbbbebc64c9984b5187f51b9b35d16a7df5b38a2e069e568bf813532ba08068477772205": "0xfe7d71599a2b67c5085142c626641ccfc1f44919270fcac28d2ecfd41e0c7e3c0232", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf29368de12521e294d422942c4cf48ccf200c703a1cde92ffaf1f8312c1fdb3a81140f7e76789d55ae1f0683025c428649": "0xe0d744a6f291a2dc1e6d744d5ae0747e314b046739be170638ecc185ff4a9b5f1543686164f09f949750617261f09f91914b696e67", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2936f517cdc5783a821a4d40c671d88ab5c975241672d5275044da23dcd085d64949b82c83e963a2bae2230af259f527c": "0xaed98e15e3ed392e38654215c3d1fa8143de53460386b60139fbb45c036c1b430653462d3239", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf293c3d393cc9dc062cc10318cfa90edf8f2c9cf52ac4784de6db0c160481ae4ebf7ce0d7066011e36e18948172c05d059": "0xfc659bba6d3985002708101d9c2aea9155bd520c105688751281cb40e4d37163033032", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf293ccb275d05874df082d79db1d3bdc3076c26a1fb9acbdd56be00d4c44901856929b9d2a879caad6119ad0417e994949": "0x9c7c545141ea2dd84fe5ef7d567ea450f59967e7afa68e5f1ff7f7c46db196270233", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf293e0b349ed966efe9d44b24fe04ba87050bf01d23906f2dd19d8cd71dcbd3033af5fa1dd042dc4dc1f3f5f86c2e9ad5b": "0x9c7c545141ea2dd84fe5ef7d567ea450f59967e7afa68e5f1ff7f7c46db19627033830", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf29425ecf1d7477bb6ee5778054833e56cad37814b38fe39243c36ec13d832f06e178267058a03d5011f4e06ab78f67e0d": "0x56923fcb0c362b333a2833175025883860f6b93996233319503a4ac478b7b1150c494e4449474f20464f5552", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2943fbed7900a24332c116cd5ed62ee005a718199b3c87bd8c24c35f027b2b4ba2789a85782a79cc6a924f9e4241c3005": "0x5a718199b3c87bd8c24c35f027b2b4ba2789a85782a79cc6a924f9e4241c30050b536b79736b6970706572", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf294a5e7e6e250f2265bc0fa25d357064c9a992b67797a09bfa4fc79558b14bff0e2ae2b20207ceadef50ecef31d120a15": "0xb85d101c656fa86dc284f34f7583b5f178d9e9b619df6031fe2c04b4c5f07e260d414e47454c41205354415348", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf294dd2b48f94bbb72fb6066cd46e1a0f57cf5689832c7f3a596de7cf58e6d764884c33fa5bcadc7038e65e9361108b10f": "0x7a895955042cb3fe863f3564e7b30e9130e37b6d905be11c0cf91064de1cd83a033033", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf294f1ce732f38340d83b0fffd53be934a373d025abe0b6342867c03f3772e5e3fcfa7b13d7d5451ddc934efee37894a6c": "0x7cdc1a6a5a7f23437b6528edcdf553d0685f940a4e6e85579727ef3dc574563a04563033", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf294f66f6bcd95b7eec2b2de1cf9b5e39f50e1946cc920aa86edf541dcd4bc35efbf4b28671b87c68b5abfb22f655de453": "0xd23f678af47c89d76031edc91e43784bcf9991b131f957d312fced2c5187fb470c5354414b45435241465432", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2951b362994cf98a76d2f525c2b9d58a8e2cbbeac13b1017c8a5a32551d77e89017551a2f9438743446de2dc2ed13ec4d": "0x7a54e6a55c0453407909789a06c3ee6719f8735ac370d6f17dc342717fd76819033033", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf295460da598e0f6061cc2d1d6889c2796ba91845c6ce9f14ebbb24f008964bd395a2c1f92149810d6f6133a905706000e": "0xce5c65fecd7bb733ee636a381fa9dd916f8cca91e2e403c8aea2f7ed32b31d680e424c41434b4d4952524f523233", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf29577ce8ae8e1ccdd44fdb9bb4cbeafa013dbe68838d76d77ca594e3e55c937ef7886fe2e8e46de8fe11f20cdf106b29c": "0x6610a5024c2a5db3d02056d4344d120ec7be283100d71a6715f09275167e4f38033130", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf29593d3dfe56b3baf292a5b3d6e830c04607b422f959ab305856c1621be625a1776d2ffddfac9a03446da3052d7cd3a58": "0x607b422f959ab305856c1621be625a1776d2ffddfac9a03446da3052d7cd3a580c434f5645524c45545b315d", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf295b01a64976c6d22df38d3ced3df87cec95dfabf99a55a128f0cc1a12a58cdf161e58872515ee35cf87510536082d53d": "0xf00168a3d082a8ccf93945b1f173fdaecc1ce76fc09bbde18423640194be7212083233f09f9a8020", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf295d48737b8979b34a23569551bcfdc2a969b1c4800a2e1700fc49adc3228a1faf72543f36ef784991a2a25d74632b26f": "0x6a325e3630266fda0ef7f7725ef8199726e29d569d609f3cf068c4db7e82591a0232", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf295e555b62758cc7ac3b0144e37591dda9454a3dfb574a6756a307688f156f4ebcfd72b63515bcdfccb50cf7f7bf92c12": "0x0ce0bbe155c5f116187af43bae0bd493872f436a139e23d9b26289d0721a310e0768616e77656e", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf29638f6afd44aeba3d7752935d82d39f7f657af299a3b7d16d7c4d27876099924e5905d4d85d683988726e31b25037cb6": "0x1c6d8b40be9990c19e993d238e6e3613cfc6cbc51979d5fa61dd6ea2593856090236", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf29652101d72ed67522b8a8646680a61d080de9a994f4ebfe1053baf13182362e06fe78b159c319be596fbbd8d027db576": "0xc229d8ccc5e5650d17760ce2b7c42bdae5f6afc6e8bab249ec77f3f779ee5a6512373a206e6f64616d61746963732e636f6d", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2969cc64f0f49a2feb2096e17db454ffe16ee0e830501e14db6f33efb672620f030b65bcd30a91152c9b9abb66f4c117c": "0x48ca001326b583070e370be3bc6680d09cad47649584a5c992bd388c693b9a54033134", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf296bfd6a3d3b57d99a0b4224c1e28ee46a8e2730b18be41205e5d9192603da3fc19d7d4b951519509cb32458ad622ae33": "0xea6a0804e0024beaa87fc072eb250446162310017e52147d18fada54a8ddb57b0231", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf296d6c7bceed20143a9bd871ea4607e2d6d3ffc8efc1d719ddf99d29c8a1b285ff855969c4fff0668f9985a6b41c4b499": "0x83c75b56557a84fe8261cadc0c308577b0709cdc54311afc5ec8d348b939f5890d4772616e204d61796f726961", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf296db546d80b94d272e5849041185281b54c3bc9063fba6c75163f3e051f1387121c0120d3bfe764e68764f02ea33bb48": "0x206dd955d4ade8d59bab18cba031e664ae888491d173084bc9a0efabf0be195e0230", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf296e6536073707345fa326cc3764d0545c016c699321be18f86dd04415e6f3152fe5b3bc13f4808bfb4617b9bedc2e129": "0xfc5d04e7ff3965c8285a2c23aa573117deeed886bbe5e3be0974f1cf0a2ff216073038f09f9a80", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf296e6605eb771be4cef81797aa0721253269fa27098d88ecb1640185c91860fb62d92ae9a6ab7713c79485bae49862b39": "0x269fa27098d88ecb1640185c91860fb62d92ae9a6ab7713c79485bae49862b39033030", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf297157ac5f270300f55c7fbc4161c36e98bbf421fcb86d5fd3e28a4762d295b722fae2260d0f3d548fe6eb8cd741c286e": "0xa06446b3474c3d9dcfb759f3df134cf4b6620b2559c4e1b99d3be4d010378f400232", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf29743ee8b8a0d5acb6a9232ff73ff5c26da466dea606e6a603356cbfece746254c6585b90647714222fb59e42ce45c601": "0x9e0bb283b2d2522a090d71d9c8fb484c7966d3e28b21bc513419ef7f70d6a5630f464f524b4c4553534e4154494f4e", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2979823f538d5bd1d523893f8cdaa15b2ecda6ddb746609cf2736a0b70823b52b11b15b1bb35a4021da70126290bbdc64": "0xeaab0cb55c147ffaf184a4c00513e85f6d5bb6416994fbdd0dd168f3c59a291b0558454f4e", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf297d1bd2ad87be06432a6596dc8e50db988c3d536bd6f68f296a34c8c3df53f1fb5321622d5f21739b6a76670500e413c": "0x38cadf9abf7492ce1df73d8b7ee82e10c2a0571970e2aa5ded4b9a6f91a498330232", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf297d7395bbd0ea44ec2a47571a9ab2859803f3ff57158c1e5483e88d4dd5d04f7f8ca3c5203c6ac29344f314099f96a31": "0xce5c65fecd7bb733ee636a381fa9dd916f8cca91e2e403c8aea2f7ed32b31d680d424c41434b4d4952524f5236", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf29815f036bb71d34b99b55524d5bc83aeb8270b6d0325eac9f3ffd34032017f7848eaa460ca9a96a90a5296e34af91f96": "0xac33b989d0b4dd35d2fb8af4cd04cc5a3831e59023cb884044f5cda0541f1064033033", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf298160c29cb485d50f2de0a12d611f93f36a8ff1b35d2750c1d8482b5f8290d835f5e497bcb9ebf11928d9de622fc3053": "0xc4516751df2e5803bac3bf9cf7b6d55cf4acbd76f861ad0a2a2b71b7a5ed805407f09f98883135", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2981b64b19cd5827afcd4a27d56826450fcdc5fe2f7a0789f42175567fe656b9121815763a037c761ef846f0d97420239": "0xa81e54507ca4f6fa30932b96d35e8f073556c99f4e3119e5f67989345019210904303032", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2982fdfd002ceea52e57a6b775006ec4e86b81e36ea46dc1b355c79bf38968367ed63d58e7b61e9aa5c97fb6fd94dcc3a": "0xce5c65fecd7bb733ee636a381fa9dd916f8cca91e2e403c8aea2f7ed32b31d680e424c41434b4d4952524f523532", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2983f6d2269a64d9c6bfd7ee3a26ccade600786fada3d88a3e440751d50f3e522f9b7b28dda4e0f674c9faa24360a082e": "0xc46ff658221e07564fde2764017590264f9dfced3538e283856c43e0ee456e51064f4e452d54", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf298b8e5323878044027edf2eace12a3d6b2f9413214ee983786be59b316ce9fe3848ca7cf5cb20f109b3e31d09f213274": "0x7a895955042cb3fe863f3564e7b30e9130e37b6d905be11c0cf91064de1cd83a0530332d43", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf298c35ff9c09ca50254e3b86d4586ce9ba248e7a6ef290c55ae9f1383eef475298bf04a1a78fc22f186cce5a797ebf508": "0x1a41e8f79310cf5b804b038d19f28b535261fc5c1c3d1dcfdc49e6bf5a946d320f7a7a4265715f5f636f6e74726f6c", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf298d8a7a39e5d3be19e11c4fd292285504c50bd7cf1308738e5758e3f5063ffbacc50d2944f95506b8b4710d1f7a03536": "0x169b1ca15010ef10b423afee4c0fca7e42f745b39e1fe4197436ec352b7f17080c54525553545354414b4532", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf299b08381cb4ebeb70490e94f7b088eb716bc1a5fbe6783b4c4fa8be371150435d5cace22115338b33a9966b4de2ef82d": "0xf6b21d624832094b03aa672e016462a020e217cc67b1434785b99114a2b4fa5a04763236", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf299c3e4571dbcb08a3ba8de93413ff91512c0e71d56bc0e445558b892aea1eb53639aaf99ec6f51aba44607213c3dfe2e": "0x12c0e71d326f83f4e6089448e147fdab51b0b7398a7d0cc9a88b0571432e7310033231", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf299d617edf1fb6836d3fb1d281c3082e9ccbb21d7b5bf0b08630681c37ebda5b98b5454c8916463a9c2b50262466deb76": "0x68170716ab7c6735dd0a1012045d9ea33891b5f6596cf97eb217d0962d86a51804676f76", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf299e7a835913510e319671e6e48424e90d6bacc09599d6647899ed6734cc33a655c56e6bf08d2273ba8464eb1d4a0830b": "0xeebbde3ff2bb37ca11414154e92c0521ac8051ea48d0d84b39714b23477636480970726f6a65637473", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf29a033bf2a2ff16545abce4209cfcdbc02a646f536fec9eeb72210c0a5ae166e0b0853846f4d052ffaf438696921bd725": "0xa8cc040d5d391967b6c50b54d81dbc18acf06fd13a704decc7df6f464679051b033032", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf29a1c41ab23706798d628389fa84e65c0661242bc6a8ea761d8668371ad17f9d036982ffbc68af2c28ebcbf2d30ad16e1": "0x6610a5024c2a5db3d02056d4344d120ec7be283100d71a6715f09275167e4f38033036", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf29a5cb01d226018a91e06d985f1279f6412c0e71cf317d94584299468b9a292c7e69d3ce2ba40e4819166c78dce18e859": "0x12c0e71d326f83f4e6089448e147fdab51b0b7398a7d0cc9a88b0571432e7310033039", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf29adb7651c6ddb15f52fdf2d547a6fc7dea595939a7255c7eac3f67f54c75929152fb73018a56bb468445373c17200447": "0xe49a94c01d7c0511480422e00ef7030ff64f314591b50d7057deadbd6411112e0474776f", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf29adfe05e86f52238646a6221a4950f03f4243300b12f9067d1fcf01c8e05f598ec2dfaa142a33398177f8b6e32ecfb2f": "0xe4a66ee66171e3238670377bc9ffbd7cb4bda47baf25e6ed80c2070942ee3f721170617468726f636b6e6574776f726b31", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf29b01e8742be34ae0db08438a76542115109e87a012b2754d0b23501fe1fa775db374927f09c228f07948f81ad84bf617": "0x109e87a012b2754d0b23501fe1fa775db374927f09c228f07948f81ad84bf6170a736c75736866756e64", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf29b04304c1d352f9d8819b856e042349c0c92d4e41eddd3bec4ce4caf3610213e3b3b143a6c0319766961aecc27e124ff": "0x0e038990f47761a17f45c2bb01c4c7746f4ad67c7d0c1dfbd6915372faae911f05f09f9a80", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf29b1bd5ce8a3bab3c40e1f31c3d91ccdd70375a0d07a2172cf390b17cce40e34997aa99c1762e9fe3f96a91ed60c7354b": "0xac33b989d0b4dd35d2fb8af4cd04cc5a3831e59023cb884044f5cda0541f10640a425249444745485542", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf29b99595fff38df3b6b595984a8507bd7deea74425ab90f984007c4324ff21437aaacd212a1a5f349d31f03f735cce907": "0x78baec43fd49badfce811cbba08b3f0ccf758b5e22f0c4d745452f5dad6eee07033032", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf29b9b06a2624ffd2e996e4e2702db7ac0739b4e65cbeea7cadf808f0df0154218982008f8cb4ce04a18b89625e69ab6b1": "0xf8d542920fa20b0dd5e126de37f7c0142db98b51a6caa4968922467b42b95a7404303133", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf29baac3b430823cc6d06a14178999ae3c8be18f3fe77e8807a0fc3201a7689f4742a12ff44622e1dc241d1a08088ab6ec": "0x4ac4eaed36e5c54f045b46cb54f533b2d3949c0ca7137e89ef03ee3f56f8155f033032", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf29c1917ea5d48a42331709192836f4d6355a7b1fbf19d76a12b4cefc4009405905cbea3fc16452627e6a01ff866e9b6f1": "0x14ce4e09b999c54351c75b74d0bafdd17d86d98b6aab5176b9068e1be13e096f0242", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf29c2bc3d8255e38d782f633ed2c3642f047b5dc76e7833045cd155547da3afa84a1fe6b9f8d8556e8c7187c3b2f50a467": "0xf00168a3d082a8ccf93945b1f173fdaecc1ce76fc09bbde18423640194be7212073131f09f9a80", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf29c65c97b9960b1ab50e8d1b24af7d44d0033f9ee5f550181bf234c12c2e07ef74652d9323c13ab31ea9c2b053eac7458": "0x8adc4e19e79b3d2c744f88fa5aca47ef05ccaae141f6435c2d50df824433ae48033132", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf29d29c9439c87f692e75c9704c292bf0a602d88c1c8aef782a7eba2fc345663405cce57081d4a34003b895057d96d8e42": "0xf6d6531d9623034efed118d00dc62831eb6f017dcb45d66ec6af44947ef41431033031", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf29d62ec2f1c1a1b440508c50c06d174f058ac509e6e93bcf6ac0800a070f28bd477fb9e9717ff7779d035094e361b1504": "0x04c73bb4b37fd89e159ea8dda26c4021a4af572826ad6397d8fa9942c18b3568063151554944", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf29d6591f67423dd3eae30b13f892a6d257c50145c707078b4d38802058b2d16fd80748729aac222af64be9e55e854da2a": "0xc46ff658221e07564fde2764017590264f9dfced3538e283856c43e0ee456e5108504f4f4c2d3132", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf29d94cf5c11bd3c262179794562bc10a274e6950dc3144fc86b2f190216b04dd5f75c5ee52d7d3d0a949bb697d4843007": "0x8c8305ff8478e6309325ebbfb81e8c1883d39e65d2ef84f88e4a428615c4927704313333", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf29da5eaa72e0f6d6dd9732513dc7d9b7be7934d8edca47f33d004647a350aaa7ca31871f8ffe6038f187e1689cf34dcdd": "0x09ed7dc92692f6d1b8bf5e71b68f9019a16f825e4eb71bb22c5bcbb9fec300d10c30786e3030627a2d737562", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf29db6e5981adfc93bab5cbedc92feb8b4cc9732afe3d57624b8bdd1afdaca3f940d0010ec54c6eeef52b15ee1da15b069": "0x8c8305ff8478e6309325ebbfb81e8c1883d39e65d2ef84f88e4a428615c4927704313336", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf29e2195a6551f5e80ca943326e7136a6b58a72e119fd6922255ddcb1b3f89bab2286d43b9bb3f5b3fd1d3df6a6fb72767": "0x8adc4e19e79b3d2c744f88fa5aca47ef05ccaae141f6435c2d50df824433ae480237", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf29edc61902d52e6b186a7d297baed279c7a43965f93ab8e28323fe1c19ce8156b9d0a941e56661f2b172da1bf74a2de64": "0x184d701295be7bb38b2c0c58a35bf8edc592671c53d149d206e037dc7c9beb7b0232", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf29f0984a5859e139849dcc9578dfb6a99de38c0e7726f26fb4ce2b3bc8a17ded6197309efbf24d70d0425728eff597d50": "0x48ca001326b583070e370be3bc6680d09cad47649584a5c992bd388c693b9a54033137", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf29f12fc9430779ecf768f55ef08254e86d7a15c23db646cb253f769875604c28b184a2487b5dff9c282bd65087e7b4238": "0x92536c5469fd64b2adaee0a10c5936bb0d4c8e4c5e4d31185fbc0c9136e1f20504303038", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf29f2c660e85e746236d5bb3e2a3e2ecfe99a833467b3227e480dd06ccad8eb537c399e3851d8acd1b3d1c3e711db83686": "0x6482a21b7e92055e74bc9b182ded5b0cb86e6f7706090c916f60e8235b8fe51a04303238", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf29f32f4580e9268c1d68e167f1631232d38aa672a41872f698aa995f14f0bd9e54cfa4efd97350e742d68a0c44da377d9": "0x6c335d86444f3189027cd53244265047e52a96b4621fdaeeb9bc12857789867608e29aa1efb88f31", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf29f6c8fe35aa3f4db319cfda3f707659402881d4f53d1205e5bdf3864a12c724927270a38a1139e0d6434eed97b930163": "0xd2eb07f02043788e254d9e2df57be11566d241c56302b91199b4647947af30200233", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf29f8d27205097c0fc77fb50bf2bdb69b796413aaaa130817e645a00e8f380264161aa37a6ef35c2328f4c79565ae9e408": "0x82299cce0c148ac684639df678476effcae36c4eb8cf15592c511512a857e745035649", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2a023661e103f148d838160e6ca67efd4f4ecfa7baadacf1a3aa65baba89f28312db782c43e750e677dc40fca086f7b01": "0x824651190f1d20237fea2d5953bb53ec59df25d581e54f291d6978c9a80177410231", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2a035199af9b75d26986371519d122b7d4e346e6bb879c076c4b6290aaeec0a06ebc5cb198245f31343ac1160e16e942b": "0x8c8305ff8478e6309325ebbfb81e8c1883d39e65d2ef84f88e4a428615c4927704313031", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2a09312cd7e7d60aa00c36f3dd70e9475e635bb7c13379f6b759e79aa78b8852d750afe7da16ec7f01139fef08849147b": "0x9c7c545141ea2dd84fe5ef7d567ea450f59967e7afa68e5f1ff7f7c46db19627033432", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2a0a92f1ab233e621803eb3692eba355dfa6bd8e8fcf8cd5be5d5cf808b5b5cb20aeaf43d7cf5551f1b33b0f029120016": "0xe49a94c01d7c0511480422e00ef7030ff64f314591b50d7057deadbd6411112e046f6e65", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2a128862a321908a2676eb04870be1e83be03f2946dd310eb0212bd2c44122eb48cf77c834699f6bffa88e2697e7fe04f": "0x9c7c545141ea2dd84fe5ef7d567ea450f59967e7afa68e5f1ff7f7c46db19627033530", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2a16440a443fbf60e13b7c0767af70dae9061deeb89b61291cb59efc126c4add37ce655a7954f8e2b246fdad18c07d358": "0xce5c65fecd7bb733ee636a381fa9dd916f8cca91e2e403c8aea2f7ed32b31d680e424c41434b4d4952524f523432", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2a1825eaaa48ce221369a3de522058a2212c0e71c8c7444fd30b0ba7ccac70112280c31a7b57682c59443918e741b713c": "0x12c0e71d326f83f4e6089448e147fdab51b0b7398a7d0cc9a88b0571432e7310033734", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2a1987de2aa0c33e9cb255d957a55085ccc2db6639c1895e08c384f618c9f215e32e0fd23f2ca0ff3b013d1c658287a75": "0x688f2dd2918739ffc90f280131b7d8bbfeaf9f0e2bacfe952a88bfa3bc168045033032", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2a1b15a955920ab51bfdb77c757fc2a4f9a48686506ea99e3f79e0643854fd07392d8e59f7249b61557e1662de58ee059": "0xfc90e922a45ef6a5dc3c8abed38bb0aae5b9aa7efcd388fab60e329fe9c2d945094252554d4d494532", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2a1c36adf3b3ef482c569689f17c1b29adc7a8f82a2faa5ec9326f6970edcd577f8ed603104845ad07ce5c5d8f4a49d55": "0x9c7c545141ea2dd84fe5ef7d567ea450f59967e7afa68e5f1ff7f7c46db19627033632", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2a1c42ae62ff0169c3e7d42f1a4bfd73c24d573f4df9151235e457956765e6446cf33077033bbca48d8d5c6c9a1d7fd33": "0x28778f95bd35e3fec4ee72a0d252c47097380c3ffdf93a9600b364ea119c05020c524d524b204d696e746572", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2a1c8c938e388a473d04f4274bf82f47e4416405ae9e2ded76e049abaac98028161a04e23bdd02ed40fc9e1e0826ff65e": "0xe6247d2909686256b09006b07e758ecc128364a926f1223ef04b38628a5a3a5e0232", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2a1def25ee807b27b6eb5b62a2cf92bbe668103daef522e6916064ee8e27db33ab950e2d4f065276f7c9d86efbdab3b7d": "0xc4516751df2e5803bac3bf9cf7b6d55cf4acbd76f861ad0a2a2b71b7a5ed805406f09f988831", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2a20ab94b438dc5cd312a7a4f775108c91883cb0c880e437370dbe0ab6747e1d6fc6decf1e0ef4f423b815f14e3ffc009": "0xc229d8ccc5e5650d17760ce2b7c42bdae5f6afc6e8bab249ec77f3f779ee5a6512343a206e6f64616d61746963732e636f6d", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2a20d168569c6ac29c25f2be85d91be8e8ccd612df568bb9b459480879224e360d0d8c3caf9365f1fe7d54b458b010b50": "0xce5c65fecd7bb733ee636a381fa9dd916f8cca91e2e403c8aea2f7ed32b31d680e424c41434b4d4952524f523533", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2a21a585b9bb7683f0ab2d1b21ab3b528bd19630ce7a6e94431c5f771e66232e46a034f3cd18006febacf02baad831132": "0x14ce4e09b999c54351c75b74d0bafdd17d86d98b6aab5176b9068e1be13e096f0243", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2a21b7ddbef861f5d3180da05262db8ba0a16d6fd4dc2954c449699e5f6e3c7d2f0dc64df5b8008135fd60eb3eac61e6f": "0x8e111a2e445cc0f64b5809496887b3130718d969db6637c0ebf1118c39b15c550a7733636f696e732f32", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2a2e00997517152f7c5a6a1916a7f1677e040d1b984526d7e5222ffbec6cbe8bdaa73f9190a9e3d7244a54fc99cf37a65": "0x9c7c545141ea2dd84fe5ef7d567ea450f59967e7afa68e5f1ff7f7c46db19627033234", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2a2f5fbc17674a2ece961c4f66cf723b42482fd4f47789ed517ae4bf2672eba2895d1b6a85e5d963e82cc77c48e57f176": "0x8c8305ff8478e6309325ebbfb81e8c1883d39e65d2ef84f88e4a428615c4927704313435", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2a30511bcf2bdb11e5753ecc63e410ffce2c6bbc2bf8ac332d8f9f45013049439bd2d31008db521ffe472e8c4c4e0c348": "0x7a54e6a55c0453407909789a06c3ee6719f8735ac370d6f17dc342717fd76819114272696467654855422d4b534d2d3031", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2a345f357db50388185012839eb399bef12c0e71d2f08b6d34a5103c892d4baa26995bf4b184eb7507f9e111014e58b79": "0x12c0e71d326f83f4e6089448e147fdab51b0b7398a7d0cc9a88b0571432e7310033534", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2a369a0e2a7e74a70c8e44ff8e9c77ac4003afd6023b1888ca027ee106726fced92608aa111486ac2b82717744009ea04": "0x78baec43fd49badfce811cbba08b3f0ccf758b5e22f0c4d745452f5dad6eee07033031", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2a38a952f11746a2911b0532aed30d9ab4c08de8a66557f63521d871087a9290cf8032705cab1ece83bc4e5a230f13020": "0x9c7c545141ea2dd84fe5ef7d567ea450f59967e7afa68e5f1ff7f7c46db19627033339", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2a3b65d3ae78bf54868139cf1b48f13ca42d7c710711e3f6a4d282c46bdc093a1796b6878a45c805827b838756ef78e18": "0x56d629a2c80762d412fad9c15d8cc973b463f600895170d43a10ca504b4f454e15205b385d20542e4d452f4b5553414d415f424f54", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2a3bbb5a55aa80e890a9289301ba092ad486e705093cbe54e60dbb3e63ecf3ffbc84bbfa2a1efd0a3a9282585e2f50772": "0xbc63ced3f8fec642128f2aa9c37e989a9313a67e9635dd85e8bd689ae8d0ce1d0231", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2a3c36c06b110b23a5f4efda988e923e486434ea1ed238bc9c3106178b9371fda26e3d4333adc04513d188844a789c844": "0x8adc4e19e79b3d2c744f88fa5aca47ef05ccaae141f6435c2d50df824433ae48033137", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2a3fc3d89e3a83adca320ca843b0d50f6fc46341527cd1a52b60dd5884d8ac5aa272c27cd3b3cc6750ffa51ffe6b34ab6": "0x0650a2e41ea97b60bbd3f87aa30d605562069075deaaf79559959230928a248700", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2a416a53ddbb72fa299d2d271242163459862f63cee080f43d1d4de935b51b615cd7a15682e28e41f0bdf6565deaadc06": "0x2033f1e89095d22a9c51162dbcce5e28a6b12957fdcb4c3cf11ea8def5ea1e220232", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2a46112d3948e95f08c4e5bd2916f094fba5a53f10121888c3b765d7a0e4ad64209bb08abed45cf9b6f72eafb3af9782a": "0x8c8305ff8478e6309325ebbfb81e8c1883d39e65d2ef84f88e4a428615c4927704313330", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2a55918795f90eceac4c224477edaa15cd237627616a57f2897c778f501c919d17ea969251d6b46cae60ba3f01dc0c72f": "0x5842026fdfe358c9320e35012deeedc83c1e19d2b677eba10a1fad0d93c82b660a42617261636869656c", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2a56319aa32365b6830690093fe1ae148d38bb685e02bad927a5425d733b7f89077e5b2b6c09e8e8990c98dde3275067c": "0x548dcb6c3aabe041e7f7ee65af37818dc7ff1ff1a4300008100322c39e9c610b0648494d4241", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2a57580a9416b0fbf23202acd932054ab129129bd5eb2ac144f5d28695aa11f2f14153863409d08656f7e34c2963dc112": "0x9c7c545141ea2dd84fe5ef7d567ea450f59967e7afa68e5f1ff7f7c46db19627033838", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2a587a8f0f48d85c990398429f01f6c909eed509e1b9e0f45b24942e75abb7aa6fa306d0e52c74fa8811857d54d0bd03e": "0xf287534dd5ead6c0247a1b0d3ada5588e578602c2ed64caa6f6fc2a5efee6f23033031", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2a5fa68b8d15856164c9e0cb0185972757c24bc10ff87531a3d2780dd51b94ed0b85818f4827ddc09ab394a53884c6444": "0xb2636043fc3b8dfa608167a9fb6fb9d065b9f2f5821dc4bfc9785a244b24a92a04563031", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2a6046f086be7cc791eeb3ad97f12368eacd6b218c883c8ecc7a71a6b22a74261f1c2394399818ad3f3939ef31e463e23": "0x9c7c545141ea2dd84fe5ef7d567ea450f59967e7afa68e5f1ff7f7c46db19627033939", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2a61efe1bf1487d89d2f762b254ff43ac9fb287e33d2e6433438c3584150a857912afdca0c065f86275b53fe95d3f8192": "0xa86620314a174486a9938856e3b939de3bcd73458780f542388be0cd66379e28033032", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2a63ccf38a7ebdf295ab7eb6f05f851b8a28ef91b1509ab5a2d494b230780761fb5e5ea00e01f7ce4296907b8b97f4c1e": "0xce5c65fecd7bb733ee636a381fa9dd916f8cca91e2e403c8aea2f7ed32b31d680e424c41434b4d4952524f523130", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2a659e14a22da42c9feda53098784cfe2121cb3c0a7a70ec5db8b5e2ba95aa0320ece6b999a593c146471df768adad97e": "0x482a9a411b630d2c3f850f435c4566a6a93143422e6cce181320f022a74512360231", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2a6db3a194fcd0b3fe07f2a594dab431ba00505eb2a4607f27837f57232f0c456602e39540582685b4f58cde293f1a116": "0x008d8404893c7b4b80f397605cc96e61fec3c89676c8c2794a2a7d281d678b1a09495354414e42554c", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2a6e457d13fc9b43cbb67310a31f93951007b26343e6ebaed9459ffaae9358c5b2460902c2a0d63d68a748e1d8eb15033": "0x56d629a2c80762d412fad9c15d8cc973b463f600895170d43a10ca504b4f454e16205b31395d20542e4d452f4b5553414d415f424f54", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2a72f6673ff72d0780e6235664d747ad9502d8f8870937f44fb43dbda57dea5b07eead72982b0712bd52a5e033be3b031": "0xac1d2d82c4a69b16c3ce9eb5d0b6f34f948a34efe62488879a514bbc837e0e500232", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2a74699a0ff32c2ae10dffd64b855da39524c4404c14e7fbda3e893815a3eca9a05f453ff0f73212319201a2f46d5382a": "0x6ee5ad3ea0da40510f11f42c3281fd543f5a6bfad54ebef7381a7320bb509a0d033032", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2a757e639e4b51ed97c4e339323e1500d3a365c988f1b8bf6c4574656c803938a4e0250e25837f74fa6046f0ccf225123": "0x9c7c545141ea2dd84fe5ef7d567ea450f59967e7afa68e5f1ff7f7c46db19627033239", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2a7964c423dd9e3aaf5da9f04822e052f74b215d61cfbd296a81d6ead301607072d2bbf9dd308c3606eb1b795a62bcf2f": "0x9c7c545141ea2dd84fe5ef7d567ea450f59967e7afa68e5f1ff7f7c46db19627033235", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2a7a9263bf47daf8ed2eadbb65c3705a302c1151878ea5c35d75c7d4f879fb48ea7a4199e2d3ac9ed79d686a157384d2f": "0x9c7c545141ea2dd84fe5ef7d567ea450f59967e7afa68e5f1ff7f7c46db19627033130", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2a7b19e02e279c0b393f41c2279f9c727fc1855c2c5d97b41f55fd7b122cabeb3c2529f1e27dd836d131e88f5d6a66a09": "0x5e1eb942e5f591bc1d902fc6a04dd7ecadf5f4916f2597df0505c6c521412c4b0234", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2a7b6572087649c1090d7aedd811559775c975226ca9eedc6f15bb8f513c0fe5a3e813c4ea2fce105febce11d5b89ff01": "0xaed98e15e3ed392e38654215c3d1fa8143de53460386b60139fbb45c036c1b430653462d3334", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2a7c645175479ef806888faf606eb4fbbf227ec6d922254e93c2342a87fe0840cecfa015478fc5ae7b28bb18c66c3a70d": "0x5e1eb942e5f591bc1d902fc6a04dd7ecadf5f4916f2597df0505c6c521412c4b0236", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2a7d9456f949713292865fa0e300e5a6910448cf888bdc13a933c0d1d33653f83d3b34bd775038e0f5900c5363aafee01": "0xf6b21d624832094b03aa672e016462a020e217cc67b1434785b99114a2b4fa5a04763133", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2a801c1088a6edb2102bdaea9a3a7f30caef53be490b506e8e00bc24809e634fef3ed2b1f8f3bc9926a39e2b40c3c70fb": "0xc66f4d91ebc7dd0065a5a2837014e5f4cef5d36d36d4ba7c915137d885dd76400a626c6f636b62757331", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2a81ad72ba738a6cc677caed9e0f2df5d26104ba050f385c19450c62d2adb3e9deabed8783eee0059d582ff8918c03b10": "0x26104ba050f385c19450c62d2adb3e9deabed8783eee0059d582ff8918c03b100a456c64726f6e414456", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2a836828036088f3f615226f382327ffd12c0e71c73acdcfb922d6d2daaca383ec2d7a0cbcfe42ac84bb16da1c25c8c2e": "0x12c0e71d326f83f4e6089448e147fdab51b0b7398a7d0cc9a88b0571432e7310033334", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2a84152135635ed4add79867174ae34bfbc1e141bf6afbb7224e41e050c296f264e8c4c3cabb0d91a5594f0585be05714": "0x0cf88657e8a5e5005c67c0ae58b0ea1137b817f32d30d80aba618a70b13bcc66033032", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2a8760e5f4b12aefc09bc776ef8d705d1d6ea41749ba9fa1ea5fb094593de0726ce6c1ae997e000b3bbd66ef09298f92d": "0x6c335d86444f3189027cd53244265047e52a96b4621fdaeeb9bc12857789867608e29aa1efb88f36", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2a8ea09bcd3fe2111d755f045fc38132964aa224ccde37501e8661ac74a75eb9c2a6793b13e40828860deae744d806346": "0xd425daddf60b2545e07c695d32d6bea2b9343f1528052b4edd1a777e93058565033032", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2a95fc139939688200eeb51ec25bd87d012c0e71c782aad6c734c6714946bf965fe464aaaf2e15c7d43409f936540ea72": "0x12c0e71d326f83f4e6089448e147fdab51b0b7398a7d0cc9a88b0571432e7310033833", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2a984484f2835a3f41e2ba4f61bb3a323a6e5748915493258986746cb3e58f9e76c69bd65bab4fc620dc649c102baf716": "0x8c8305ff8478e6309325ebbfb81e8c1883d39e65d2ef84f88e4a428615c4927704313137", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2a9e475cf45beb5df0760b93b4b99e3d488d38ddf4d661801a1ab2efe073a9f35e0acd5c3c896aa28d8b5b20e2e88436e": "0xaed98e15e3ed392e38654215c3d1fa8143de53460386b60139fbb45c036c1b430653462d3338", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2aa0fd96e6b35383106d6798df39b9ccfc05809bc85b574b586d8cb6cff329b5e5666a7f56963c06a4c95fcf681271e24": "0xbcb916e7a7ef77dd1f610ed27ec519b4ec226028eb8edade41f95b217f89f6201244656e616c6920436f6e74726f6c6c6572", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2aa10384d1e60926caec3f314cecb220ff954fd2279cdc545fb8b89133ef97c121308e4ca8e26dc2f7d3c3d9b2dc52dbc": "0x6ce8f0f322c021ca4991c83240d0feb94ad1678835b51d228999252bf9223e4907506963736f75", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2aa3554924e8f0605dbd0edded09a9ffe94082abb5e84b31a7cb7e0e69fd711f013ac426d62f1e157b762d284ee6efe2b": "0xd4e6d6256f56677bcdbc0543f1a2c40aa82497b33af1748fc10113b1e2a1b46011f09f8d80204b534d20303520f09f8d80", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2aa50a6c101407ebd9bede53a0c4277144e6717194ee8da5cb1669a5636c8821f764ecffa0bb0e43b610b8bb1fb1f197a": "0x16f24ecfa07199b88f010d94f47864ace2c0357aa4f37898f85cb39992e2036d033031", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2aa51254ca720f17a1f5a7027f48ba5f9c01b6763a287079871d569b4c1ef94255494347450d13fa06d2ecb298c426d3c": "0x54c473bf199d05b878ab34e9a37d17d0a8bf70498edb5c759672e984fa38b4320231", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2aac99d77f60d544097912c8355c33c854ee9592a2fd8d3954c85b71eb39e6eb323411ca48bfba174abbf1751d2d190ec": "0xc0b881e2db47fb95982cd5c364b87e6cdf5a5c8a336d980156623b53815c597b033033", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2aae461333986963974e8312595132a9412c0e71d5b27b11da4fee8ee2b71b1535daaccd5775846c26ba02d0821244667": "0x12c0e71d326f83f4e6089448e147fdab51b0b7398a7d0cc9a88b0571432e7310033536", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2ab394ee3cf4d50586384bb27c9b041034c27cde4c0ba44b80bd040462654c90c73e26b474895a2fd746fd5febf3ecc65": "0x8429c11f2ff4fc700087c7fdad402d6e97c6df5e73988c3a36c2b6fde7daee210d5a4b56616c696461746f7234", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2ab536a7613dde80e8e70d0da84e89d752ab862c753d2f6331a4403f28cdd60a942d5611882e934c079a55145f49f9659": "0x82299cce0c148ac684639df678476effcae36c4eb8cf15592c511512a857e74504494949", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2ab8a278565c6192692b3b187d9c43f84c05795cea6af4d0bb72417772d60d0e8ca43f5790448fc92f764088b0d4f4b1a": "0x16d5b643fdfb1b22d5dfd3a50157104df0580c910d2754987afc25fe0aaf582704746f70", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2abbffc8eba374975f0e6e558b2307c9230ed0348562c1ed74187bf91ab00d4f734ce2505a6d6f5d189ca1f8dc966e665": "0x2aa53f55efa82a9820f3c2569d4e52dc467475a1a11cfc9861ce5440316edb7a05506f6f6c", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2abd3d4eb29ca65a76575312e85d8f7d03650aa13fb0f5a4c3a5ae264eb820463be11b8fdbe5fd09cb34df93c19430a22": "0x66a4d150e1799ed9ffa721e7e95397c4484db801fb7f26fbc4f27e1d158ef8390232", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2abde7cd2c1b8f30e8b80c6dce5c67f6ca618dac7de8bd9fe8561c672d303c542f356e8f27be541bb6e54e80141d8187e": "0x08a23d4b915d29be5d2aa20f36649e004c6ee8df393064edad697934281bd51f08303250726f7879", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2acc6eb9833a7502d18771c4fe9ecf81850c63f86e505700906b9303be612c11427a137eee64475e048ca585562f79c50": "0x9c7c545141ea2dd84fe5ef7d567ea450f59967e7afa68e5f1ff7f7c46db19627033831", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2acc93bace0b7ce787d1d2104372dcab3a6644cb7298d69083173522d5e51c66dc5c88bb7e4358ab6d88b216d6574b010": "0x6a325e3630266fda0ef7f7725ef8199726e29d569d609f3cf068c4db7e82591a0234", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2aceb033b9addeb8aa7d5d99c6a8cf50414ededef8a62c8642099e5b094ef95519a5e2a1898ec9783c2bac2c71f71cd16": "0xf6b21d624832094b03aa672e016462a020e217cc67b1434785b99114a2b4fa5a04763035", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2ad065bddba06d39b4ba56da138a2d772f69f5924c239023e8555b80a7323494f03c76357fac283664c131a90d13bf971": "0x749ddc93a65dfec3af27cc7478212cb7d4b0c0357fef35a0163966ab5333b757084c69746869756d", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2ad24a02ed1d484da31090f95d6db1491b046bbfb0ab2a461c916bd646f879787adaed72992ff0182233cc798fc9a2c31": "0xc229d8ccc5e5650d17760ce2b7c42bdae5f6afc6e8bab249ec77f3f779ee5a6512313a206e6f64616d61746963732e636f6d", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2ad261372a499359b91b3a2e016b9aa80eb6a6d492311cb809fe02a7649fe2c815ac9a824be7761d7f5b28360d06b810c": "0xa215ba2d1b408fd5350b93f2566124331dabc06e94c16d7080d3cd5771d59958063445766572", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2ad3c87deaab49d4ef8674efce03c8935c49ea8deb91aae7843e2cdfba3a91fb9910efab535670b9da55bd5abdb7e542a": "0x04c73bb4b37fd89e159ea8dda26c4021a4af572826ad6397d8fa9942c18b3568064354524c32", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2ad540dafa3c010985e733c528734c9d2769bde86b6f4610d3b75a775d3cc411da01222b117e84073f9fb18e5a89de715": "0x4866f45ae7b07019c03464e3c8c1324e96d3f05a2c5205e889fe597b0af2a70c033031", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2ad7db5fb78662b93f04b6acc7c18d012041eda8a25068f57f573d5b152e2c8947c7ab80dead270769184cf63c77af554": "0xaed98e15e3ed392e38654215c3d1fa8143de53460386b60139fbb45c036c1b430653462d3236", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2adcecde88c84b8143f2c31ed585d2e44e62e1df098a40f24df7e2359de24775b28736ded030da69a7ec3c809b10b6e5c": "0x56d629a2c80762d412fad9c15d8cc973b463f600895170d43a10ca504b4f454e15205b335d20542e4d452f4b5553414d415f424f54", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2aea9940615a604916633e29b45b404fa07598edcb29987227d3fc1d585227937f701af167165fb0a99b6a21983fdba04": "0xf00168a3d082a8ccf93945b1f173fdaecc1ce76fc09bbde18423640194be7212083138f09f9a8020", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2aecb57ea6827c8a04c14050c344d78266ce201e876781c6466468f641ea7defd144b054fd1966e2292bab3c550f88711": "0xf00168a3d082a8ccf93945b1f173fdaecc1ce76fc09bbde18423640194be7212083137f09f9a8020", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2aef307bd73838b989f1a749238b6f04a98735853f4d1ce4c0e545e53dbbd8c65fe5f89385fecbb646a26fe00cad77959": "0xc229d8ccc5e5650d17760ce2b7c42bdae5f6afc6e8bab249ec77f3f779ee5a651331333a206e6f64616d61746963732e636f6d", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2af13827ef9659fb4dacd7cc4675e17ce2a30902e14ea5ffdb5135aed31d3940e0df7027a27d079c6a67d135981f47601": "0x04c73bb4b37fd89e159ea8dda26c4021a4af572826ad6397d8fa9942c18b356804554b33", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2af37c584ede4bc96a2beec1a74fb3f10e6fe75fdd65d00f6ea16c22ba1ce89e45441b80c597eca58690664288f1ca146": "0xd4e6d6256f56677bcdbc0543f1a2c40aa82497b33af1748fc10113b1e2a1b46011f09f8d80204b534d20303620f09f8d80", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2af5798e78cf8fcbc4626ea2f1f3e4a70c5fd9b06ea650783b1d4ad13841ed6caf054ff5cbe72ec4636fce640bf1ae53b": "0xf00168a3d082a8ccf93945b1f173fdaecc1ce76fc09bbde18423640194be7212083232f09f9a8020", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2af74e10d03469e3142b06730cf0bd7cbbc921beb233fc0c3ebb3f98676aad4aea89f81a08f57251e24e2c02f0dc0a901": "0xf6b21d624832094b03aa672e016462a020e217cc67b1434785b99114a2b4fa5a04763037", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2afa7012257eee9779458ee194e0b6a5144ab70adf9b1a6402cf14b3c61f98acf5bccabaf0030d537510166a21ee44d16": "0x9c7c545141ea2dd84fe5ef7d567ea450f59967e7afa68e5f1ff7f7c46db196270232", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2afd1838df35537febadf5e3617420f7b8af704356b5593f79cf9861e3c26748ac8ac6a4c2920582293228f56351d2667": "0xf00168a3d082a8ccf93945b1f173fdaecc1ce76fc09bbde18423640194be7212083238f09f9a8020", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2afd5dbb951d5f4a9f07651fe3541d5bee2cd31d823eeedeaf516f7fdcc4c7287e3d23014e76f804b332d7b52571c2a6b": "0x625a907225b8ed830c16996d75cda73ef03750b535a6d83ca2ba1246be2dd42417f09fa496206269742e6c792f766f74696e672d626f74", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2afdb125b38cd6e1b71477dbb7dc67946c8ceb3b9d38e7a25f5016eba5e885ade09042c214623524d78c73f6ce9bcf95f": "0x749ddc93a65dfec3af27cc7478212cb7d4b0c0357fef35a0163966ab5333b75706626f726f6e", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2afe65ec5f6703d19a70469bde3745d4fc1c0081353c756023d47df0da1d4c1b9eee95b9bb90058215e6b42ec5b00d525": "0xba98d1704adcb69b1d50aebfab39709c03713555e3d49e75690492b0a02f547c04303230", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2afe974c51069584f0b67963f8f53fa99b085746d68637b4db6d45d855e9e31ac9059ffc928c3330ad1e13ac6f170ad48": "0x0cf88657e8a5e5005c67c0ae58b0ea1137b817f32d30d80aba618a70b13bcc66033034", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2b0143ed97b93f210d26c121497e79683e8f0c9814b8cfe6b4a46e4ee7f2b9fd93aa98485c646f07e973e57293a107059": "0x6610a5024c2a5db3d02056d4344d120ec7be283100d71a6715f09275167e4f38033035", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2b04ce42c85bf3a1f40e03b434f56e20740e488d3a17720b2cc51ddc6cc6c4afb23ed4fcde97698aa2cf374fa7fadb37d": "0x9c7c545141ea2dd84fe5ef7d567ea450f59967e7afa68e5f1ff7f7c46db19627033538", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2b156ac766093c7ba112248de120f8777ed1d56154af1862efb63fc12298d73411b024a7b5312346ca95effe7011efec3": "0x2e6dde560aa0f00b08d0db5e3c2f199181be3ca53d2e7a0a742aa5692433060d0f405477697474657268616e646c65", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2b161fc09a5dd4437945738a2db74412778018b68f1983978069a54f1befb11b0702529b1cb9bb0163999d9bbeb85391f": "0xaed98e15e3ed392e38654215c3d1fa8143de53460386b60139fbb45c036c1b430653462d3031", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2b1671755a267e779d29b745afa7184bdd05bd77a93988e8d68d67733df1c5c149fcaf773e6a74e70428b2aaedb018ac9": "0x56923fcb0c362b333a2833175025883860f6b93996233319503a4ac478b7b1150b494e4449474f2054574f", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2b1845a811651232c98d46a6d2db1468678054da56ab2c696de80350f00924db18c896c3b9d66c26750628082750b332c": "0xce5c65fecd7bb733ee636a381fa9dd916f8cca91e2e403c8aea2f7ed32b31d680e424c41434b4d4952524f523630", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2b1bc87a77984491d27e1f0e6ba22efc2b20ba612ec45aa1ccb1ede3e2838ed2b4f5eadad5d80a873d74ead94b9689850": "0x904168b519b2745aa1480867fbc7db364c79e03fafd6e30ccc1691e7214ef8601631efb88fe283a331efb88fe283a336efb88fe283a3", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2b1cc4601528b3b27d22bffba3940a3cf60857d3958e4e8809b36403726468f6b336e952d7cdee4a16c32126719dac411": "0x868cd54faea1a0e45836635b2bf658733436ec69c5567d651be592392cbb69dc0232", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2b1d90018e8428ca502a306eab52ec898dde48b0a82d440116e0620963bfc19d1520435a7b64c4b36e5b258be8a9974e0": "0xac33b989d0b4dd35d2fb8af4cd04cc5a3831e59023cb884044f5cda0541f1064033037", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2b22683884f7fb7a780be6472f2eeabfd2889d414f8bb29201637b8ae394fd131642a3eb4764a82730e494d6e60a6c4bc": "0x1c6d8b40be9990c19e993d238e6e3613cfc6cbc51979d5fa61dd6ea2593856090231", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2b2a6983ef59563be11c6dd410ce0053c6aa3fa5a328b8a928c0aedc22aa88d14e807d2552c31bda8b23f3ac2cf01565e": "0x423e5d0451428d77e1f81f6f20c87427e355468da3ac8eea9eee7f041871a7330231", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2b2c14e2914e297220ba4ac2ecf4a2dd0c009ab06d6b49cd62f2801c4b0029a5343c51747f6716c788780bfeb2730af66": "0xc009ab06d6b49cd62f2801c4b0029a5343c51747f6716c788780bfeb2730af660e434841494e2053455256494345", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2b2d425c1822c8e8f9d00c0f561b3d58a06ffadfd1ff3fb474bcca0ee75b100d244da043ce2e0725e40b1e8c7d6f0251a": "0x0ce0bbe155c5f116187af43bae0bd493872f436a139e23d9b26289d0721a310e0c56616c696461746f722d30", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2b2f4429c50834c52a099157f11c40a473a6a0745688c52b4709f65fa2e4508dfa0940ccc0d282cd16be9bc043b2f4a04": "0x00f53cf59ee4bae1fc47b5df521d48a3cc2d02d5c15fd5d3bfa3d6a4a2e6a57611f09fa5aa53616e6477696368f09fa5aa", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2b335bd1aec2af648ea2cb3450de1bf5a759dc44004f91bfe44588e84d9c60517627929b322b7d00b8979035c3fc0be87": "0x8e28e91f200ae0e50fec4354a429a7e4e00f684f594a33437dff6e8c4ed180530230", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2b34954837d8d6e4690d665d2e8f6698746591c7794e2cb60b8a342f82bf14b2cfea945671453f92e330917366ed5f946": "0xf01c087c4a752cbf56ae4672f910acad4b234a830818356b8378afcd8e0423600c534158454d424552472036", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2b3a55f3b29992f1e339da4168c1a78c8007cf8c189e43ad7cc1eaabd0aeb82ae7d62e5ca915f6bb87c4a0d85bb8c3772": "0x9c7c545141ea2dd84fe5ef7d567ea450f59967e7afa68e5f1ff7f7c46db19627033533", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2b3be96d7b60e74bf343f4dd04e31babe081c3d2269ab0253aa2d2c40fd37ab6e7304b0daf0bd6068d0d689fb51f1c40f": "0x9c7c545141ea2dd84fe5ef7d567ea450f59967e7afa68e5f1ff7f7c46db19627033238", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2b3d6cf295dc61108cd8672c531252b07644f5b938a2bca8d0b0d5b0f08bfa3faa67acf54f9d45449777022fc23cdbc0f": "0x8c8305ff8478e6309325ebbfb81e8c1883d39e65d2ef84f88e4a428615c4927704313235", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2b44e7e0fad1601773b34fc84fbfffbd11ccd666d5c96fc362fd7fb1633ff09d05b3394ad29e7574e4231f5ab2e0f276c": "0x828618dad92559461b479508086bc781d88434e5372229cf66ffc887672e9b3404463143", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2b4738370a4177572a0e9eb1ba3a720d8a61a8e0ccd37645a2dd65916d9bcf3b77ecdf395ecc3beef72f3ad5565bb3353": "0xf01c087c4a752cbf56ae4672f910acad4b234a830818356b8378afcd8e0423600c534158454d424552472034", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2b487bb41f8f8bcf50bd84ad49b25667b662d04da99fa11b0ddd8bdfec9bbc2574ac71565e9346c8e13857934c18b3646": "0x2cba024614ea8ccd1ebf7a634f30b38d65c082be6aaa92551b9c3b4d1f15ae6e09486162616e65726f", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2b48c0b478f2d6dc553626f8464e3bec9936c411f5a41fcab2c26fd03ea779dfce7ce65c93203c5538051e77258315834": "0xfe88f2849c8b51127fefbb618de330c811b4092da0b9272edf2b8b7fddc05c1f032331", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2b49ee3607cefdaa13f3616289ca079f136dafe22546294dab15b18d1f15fed8856e6ace31582b0dca7f8d450cd963368": "0xabb9286b2b288f2af6eb392d95b12a64768174de723047b9ae0f86283dd5e34c06506f6f6c73", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2b4b7eb72a33fd8a878404ccb4c18d3b01239360b36af37935b370032d2306b6c99c2e06b0312c2de4ad61c263b82886c": "0x5a5f7eb7050fb96d8d7895d9afce428a064ce66e3b094805bcad9a8e68cb99340650524f5859", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2b4bb8572019f90dd482da55248e0f1b21ed7e0b663455310e4a8d084ce985ea6dde9cbd788f01cbc27f9a85264e97515": "0xd030ca0b2a60a30e7d1a0fec231f6f36c3b608036d25ff6b2b9ab9576d59c2520d5354414b452d515545454e32", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2b4efc7c6912288cdba7f101a722de6d9d8a8b294275746ad87f5fe0d3f5eb3fb81905036522357b616096f3e84bfced6": "0x4eed7cf3f4f6560d58db4eb78bd24b655bbd1d7a5c6b454e77c8dc5e2721a54d0a4156454e5441444f52", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2b4fe5af086dc362ec68a3fd6623154e7027b1e50e1acb6c1ff8777599be3350bbbd0236fd3866c367f420393d3adee41": "0x7ca460cc927a04fbc91f4ddda54149556d1a85196bc753d054aca1fb7621e3490474776f", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2b5129a9ad311055df8bc46e48cbcd31b4462badaa1c9c6bf3e368c5de7a206c0e8c1ec70ff0c8c5d2a51545e0514ae30": "0xd6030dd61ad78ca1900865d2b53dd163bbbb5b40c82f94d25cb6ecc750a93c250643544c3031", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2b5202c8793cc26142c2ed9c2300e87072ed9d00721b2fe294f0f2af432a1a2d98a45cf3d6db2939ae20f5bf25625ecf8": "0x1a8ab26aba64d6176b6aa462a2a7ef6252ca1063cf978dcb6f6c64fec81e7861074534592d3031", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2b56ad69ff410d39715cea2897e28035c4248d8caebe59dd27fb0606a3640daab22456c80bf8449bc0f9ca721ad2e2074": "0x8c8305ff8478e6309325ebbfb81e8c1883d39e65d2ef84f88e4a428615c4927704313030", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2b58bca7f1d5002592c9d5f4314d6155dc44a96f5d752d040b443a98592bb0d42719b2cf3ebe538fc10f76637bc054e7a": "0xd6030dd61ad78ca1900865d2b53dd163bbbb5b40c82f94d25cb6ecc750a93c25033032", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2b59699f193b136dca7642aeab5b7e63f1240c5bddabe0326741d3653bff06d6fcac311846cede93f8aa44a86a971924f": "0x56d629a2c80762d412fad9c15d8cc973b463f600895170d43a10ca504b4f454e15205b375d20542e4d452f4b5553414d415f424f54", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2b5b91b98aa6173a5eb85270b4ee572efc80e5adbafea30ecb72dec246ad8b5647f95092b535a702b4347d2ec210c6972": "0x321ec507203650141d2ec630b967b76ec45dd53d852b9cb25f220dd3a3fa2e51094e4f564f53494232", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2b5bbe7f3e23bed01c8dd47249447aa6c953288a0e80d88a64db2db07ca48da06678f683fb99301500223d663dca35b7a": "0x582e9acd4386d60a8d3de206a575ab9ab0c383f3b4ee88d2a2ed144afd3565040872657365727665", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2b5bef284b5039ba4a4ba3ba8eb004ed490e389b9296c049a2cf0cc3255f3d58346b0eb6e6b0826aeaf81aae144d5306c": "0xea6a0804e0024beaa87fc072eb250446162310017e52147d18fada54a8ddb57b0239", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2b5cf72ccc7c79555b6fa9d50f10f9754c2b0f22e091372190ee2f4f79357f9084e1a9d3bc9af30e41db16a3fb31fd3d1": "0x08a23d4b915d29be5d2aa20f36649e004c6ee8df393064edad697934281bd51f0832436865657365", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2b600787f7fa0dcf6bcd77df14eeca35a12c0e71d25be2e5d1c5893ed30710dc6c645e8f26b3e1c3ca43800fb99fcfa4a": "0x12c0e71d326f83f4e6089448e147fdab51b0b7398a7d0cc9a88b0571432e7310033135", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2b6dfaac45c58ac397aa14e90efb01d6976b2a1db526de647dd7aeeebd328bc037be6795e79e7235a23f74198387be12a": "0x7825b33ec8baf2d437c19856a6ce74f09bbf49c284602a18ecc0683874dd596e16736e66206b736d20e29e8b2076616c696461746f72", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2b738857ffdcbfc2a18c7c4e9a3bed4ef12c0e71cb2e754bb49f1758439d6729debf9a30cf5b9a797ec564f00592a2f5f": "0x12c0e71d326f83f4e6089448e147fdab51b0b7398a7d0cc9a88b0571432e7310033632", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2b75da1999ab35263ba79c536fd478fd338f0ee79e61dd2bd100c13719c468038ec4d722104b0a95fc38af7057c28fa50": "0x82299cce0c148ac684639df678476effcae36c4eb8cf15592c511512a857e745034949", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2b77d8d27f7500c1c4a94f6d63eb20ab612c0e71c512bfec8bb542308c909c7b50f401219848e9cd7ee84c2bf25196449": "0x12c0e71d326f83f4e6089448e147fdab51b0b7398a7d0cc9a88b0571432e7310033431", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2b77f5b4c626027fc176dcd30aa8167a9e68e209129894d176228151c41e67d96f9d8ed4da38338fab5c964f2cd2c6156": "0x4211b834beac4f35ff92e0dcbb0167f6ae7a0c43b186727d581d3f69f10fea3407484652203031", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2b786bbaf5f0f4985d65e2c96b517b5f42cb40effcc1bd1e91c49205a599b87e3a49dfae2ce9644f3a431e974c721c54f": "0x8c8305ff8478e6309325ebbfb81e8c1883d39e65d2ef84f88e4a428615c4927704313033", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2b79f96e3e2aca9cd3df81bb6611dbd0d62307128d13196dc291ac51e68173c5801fe6bace303a222d2659255d9debf27": "0x8429c11f2ff4fc700087c7fdad402d6e97c6df5e73988c3a36c2b6fde7daee210d5a4b56616c696461746f7231", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2b7b365c76d69bce8a04dfa122cb30ee3e62bfe4941f647a18c74850008608346ad2c9623378dc3b8856f4d9a17ccb176": "0xf6b21d624832094b03aa672e016462a020e217cc67b1434785b99114a2b4fa5a04763135", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2b7b7a632d73902d03c337522ac4f6b102c13d8c2c4b4445943ffce2d55a39cd4c982e5bd4181d30f712ccfd8347ca45d": "0x8c8305ff8478e6309325ebbfb81e8c1883d39e65d2ef84f88e4a428615c4927704313332", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2b7e3a8de83f5d9c72a220db7d533ecad8e2ca3235e29d530a16e44fdc3a6ce04c42aaff4ed9b7c275bb9ced877bde979": "0x8adc4e19e79b3d2c744f88fa5aca47ef05ccaae141f6435c2d50df824433ae48033131", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2b7ebe3f39428014d2cd531f2df6e16c48a989898ac32a8333eea5bebe65671f63fbae7c43756c21f8507be73a53941d1": "0x6c335d86444f3189027cd53244265047e52a96b4621fdaeeb9bc12857789867608e29aa1efb88f35", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2b7f510898ca9dc0d3cde9929856ade57ce0b753196d88630621ff926331ce4780474fdf5b100fbcf96dfd4e984d1c669": "0xfc5d04e7ff3965c8285a2c23aa573117deeed886bbe5e3be0974f1cf0a2ff216073036f09f9a80", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2b8077874958094585a4ed28a6037b037ac0c25ae153af1c54bd0eb9c02dbd01e3b462be18089e560a9cd19890dceac6e": "0xb0ef511fbed15d88d75933d12bb50b56d1bbed109380b2fe0c7ec72d441191520231", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2b8d9e0ce3698ce76df431f5bb8cbfd883c6d21b257bbfa6eaef65227c3ca8f934d4df946f53f65aee505dfa6b741c852": "0x5e1eb942e5f591bc1d902fc6a04dd7ecadf5f4916f2597df0505c6c521412c4b0233", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2b8f66ddba1b6cd906785cd2ab3f5d1995eb5606f625995f4a16ab77fab23443b28b5ae51964638b6c6d1020f5cdf5d04": "0xc2a82d0740d343bbcf853665019f2afe81ddeb884f76dbb5c74533610f72a73217747769747465722e636f6d2f706f6c6b616c75636b79", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2b914add7bf4db96d40bc2192c35c31e246378406055f64e506440a1b008f875abbbc8d3fd7c05f785a723fe1b5739fee": "0xc852bd64d95e1c2fc164ba7ee6c2cce6e87ff8cef81c60940d46f710ed712b7a0231", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2b99149ca92c21e9733fc719abb9e96bf9e7fb05bdd2dc88013e77f26a37dc19e1c1717fde8a27bfd1f2fa8231ddf8538": "0x3e89cc7fecc4ad46cd7ba606522a8d1679863da498718cf9acdafbde8cfe4b7804303039", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2b9bba004e878e6b65f88fb505f441de8b82ba825d0fa34373ebb741509f70042068219d805f221b75330b4513f62e674": "0xf0fd6298e6d06eefc52fb2f12dc1a6ff9e8958ac2a3efebc7f5673dc33808170033032", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2ba8007316dfb0887dfa7438eebe1aa06dea318de2228da64b91c671dd7f325df63959f9c51c86a36f28ec94126f32070": "0xf01c087c4a752cbf56ae4672f910acad4b234a830818356b8378afcd8e0423600b476f7665726e616e6365", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2ba8e2b3d2b14691b6e8f2b344633e311f6f9a8d8e0eb8f9113107b5f2bc4c3bf64a31c6ce51913433873e4357bd35524": "0x1c82102e4554587f23cbd4bfdb0f43c9d2879d18feb6102bbed977930f695f220231", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2ba98f853e954fceb922f0ff042f441575ff5a4655138350a17e2dbb4ed130642abbe12b52ed03867883f0af9a1ef0cc8": "0xbc955504a40c50ded178a8082516a78a68f503348c16b106fb2a1aa2c594743e065374617368", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2bad206323c089bccba048f80edd29a1248b36ca55541b8f8c030a3a844a247a85e731764d015bdede53205fb5b355a25": "0x7eb07fd02281d018a4c45bab914fc6e2a0f81620663b53ab62432ae62a07194d0232", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2bafa48c72defb21f2abfda59e80ad84d9181d99f43daa05e74f15ff308adb8a4ef121fe4976904813de2e16ac447c3ee": "0x625a907225b8ed830c16996d75cda73ef03750b535a6d83ca2ba1246be2dd4241e5b325d206269742e6c792f6265636f6d652d612d76616c696461746f72", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2bb0e7e0784f6df9f4d3896533f0ff3e380b036ace5df3680d4f61cccc6cef4d37bc396e6a6e63fdecf505ecbfe41149b": "0xc0b881e2db47fb95982cd5c364b87e6cdf5a5c8a336d980156623b53815c597b033031", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2bb44505de60060b7443bc2710270975712c0e71d06dd205beae5054c937e4170b53866e429f4be7a98318c261b3a0b2d": "0x12c0e71d326f83f4e6089448e147fdab51b0b7398a7d0cc9a88b0571432e7310033438", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2bb928d4de94710209fa18382a0eaa1a602f777f4b3001d83e7a2441ab8456d2db9ad30b77e5d3f2fa0c4150b769e9a39": "0x0cf88657e8a5e5005c67c0ae58b0ea1137b817f32d30d80aba618a70b13bcc66033033", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2bc06dd4cdc189d8a0eef9f070ce3c65b5f58951d682a66090492f70ce968af8b8d39a6308aebb3cabeafd44bb0213d91": "0xfaeffbbb88ab949b51abcacd45d7f9addf608a6e6ddc3d4b39147454e1a23a161356414c494441544f5252554e4e455250524f", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2bc1cc9ffed2bab794b7c8387367708533245a2e5ac185dedd4f63f9899990dc2d467a359dd573a7adf0817e06948451d": "0xf6b21d624832094b03aa672e016462a020e217cc67b1434785b99114a2b4fa5a04763134", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2bc29a465fa8d8290db0e093571568a99160e772b488c83753ee69cadc56cdfe71937dec6a69b4bee87e4cfeb4bf8d475": "0x2458c79f1b8d080257ba31830f364170c90b6b173be1832ebace48595d193b2b033031", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2bc4c1ee10a12aee9866c188315d2c8d1caa6c46edcc1d2a38bbfc4e200c3851762178268d7a3e565ab99728c18ae0376": "0xf6b21d624832094b03aa672e016462a020e217cc67b1434785b99114a2b4fa5a04763131", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2bc80891a015d9446458f46a10ae007da7eb15d7fc95b03fce6ab8cbc54c38ac898932407a3e9bd86d8c03bbfb5b8112a": "0x6041e8f550869197a24ed9e968eae648692cde7bbc04077114639c249cc0a0430474776f", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2bccad62ada0ce1d94de52aca44af59005247e73b8ad3c36bb4e01c93a9bd6a6048afce1e2a45863ea5fe99778b530b61": "0x5247e73b8ad3c36bb4e01c93a9bd6a6048afce1e2a45863ea5fe99778b530b61094e5244204c616273", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2bcdb959b5ddbd2d2d60f5ea4cc127e5464c23bf3c5f9b5c2b83e9bf6722b1a6c15671dd610c63009b0f67d4daa521b4d": "0x56d629a2c80762d412fad9c15d8cc973b463f600895170d43a10ca504b4f454e16205b32305d20542e4d452f4b5553414d415f424f54", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2bd24d016e6e576c1e340b9aea878a99d9d2acafdebef59f646598614d1e0f1ea7ebacf643f0ba096abd078d9a2e4ae96": "0x400a075c48b7985fad91dda0b168b2185958c9fee280f145d2dfe24958a12737033032", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2bd46d31c6545637d7db64114b9c8bbc0ea6f0d87d39b6b348f609c20246f065864972f409b809e94636fad2e6e779059": "0x48ca001326b583070e370be3bc6680d09cad47649584a5c992bd388c693b9a54033139", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2bd5adc4b7050e1990be742027d6b835ddc64ebe91ae1dd904651525eb5fd91eb0abf458cb0f5986158803e0075604153": "0xca437639da37528d8edc0bb6b31966fdc0263218f4bd60c6f2cc37e963090371066d61727332", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2be0a46a1f347a4442d32a7ad6c50a341f0825186ee2e14875b4da41144acdac7d5aeeda144951b84cb93c5b62388dd57": "0xaed98e15e3ed392e38654215c3d1fa8143de53460386b60139fbb45c036c1b430653462d3036", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2be2eb08addf037c74fe47d69298bafee7cc30da54f59bf041de60af0a1eeaea965edff0ba95e43be290b08ff15f91716": "0xbebf5aa73bf19935376f19460dacf00bf0dcd021ca37d6a2284cc6347dfbb13b033032", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2be4581484e33efc5a4f22c2fb7ea7935d3fb95a477ea8deb243947948b28d08677f5fbc3515d9365668056b12f028ce6": "0x400a075c48b7985fad91dda0b168b2185958c9fee280f145d2dfe24958a12737033031", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2be638c7d07ef5629ed517c7de9ac8e5d88d38df37c92f9cee029f6290428a9848f70dd8f10d519a6c8a861101863cd40": "0xaed98e15e3ed392e38654215c3d1fa8143de53460386b60139fbb45c036c1b430653462d3332", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2be7ffaf77a9ed2625b0a2444d7405c4a5624e7bedddddd49110e4c76ecfc6d2406dc3bbde447a71ef0e511560f588f63": "0xb2636043fc3b8dfa608167a9fb6fb9d065b9f2f5821dc4bfc9785a244b24a92a04563034", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2bf222eadfe6e79e6b98def037e616931eabaedff8f91f5afd170b1c8252522e76584565bda69f49ca2e223fdec4b5529": "0x7825b33ec8baf2d437c19856a6ce74f09bbf49c284602a18ecc0683874dd596e16736e66206b736d20e29e8c2076616c696461746f72", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2bf2ef73a6f67c9959ea062054f42e7d14beb8e393d37e827b64939797512b2988db9ea41f5b4d2f06a4f8c8fb955d89e": "0x5cadb1617794ea8d20a5b0bf1e3275a815229a34c834c9eb6383602ad47ecc550231", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2bf553593611c66c71467dc868745cd4fcca9c8d2749a01cf11872c61580b40f227d566afedd3b40cd29849276414c350": "0xaed98e15e3ed392e38654215c3d1fa8143de53460386b60139fbb45c036c1b430653462d3136", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2bf662d325aa8286f5766ccfbc05655e76920834078df5f13662750273260531e585b9e802eb1dea6a98e7fe2f7555570": "0x68f6e4f77f043dfcb9fe88519996ee25ccae674ccda259bc49efec6b6eeb9607033032", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2bf7716964fc735731e1526ba1768d4ec3012b3f9f22dfe0f9f29a97eb2fbcd227e5bd4f9c27df3a24816f9fd3a4b1713": "0x4e3711ff0fdcfc953c9ff93355ed42146e442c256b6010ddd5b5fe0ee8b8ac1c065374617368", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2bfb6aae7f8cb718d69cb0f57c5895a988805b2b3d962de88736fcbcccefb08f9915ad1ddab9d1e31782954ef1ea3e622": "0xaed98e15e3ed392e38654215c3d1fa8143de53460386b60139fbb45c036c1b430653462d3131", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2c0732c17118f0d7b682c4eef1536a9e29083308a14f56003ddeeadcf3e12c5f3685f05393380a47adc6be23c88d8b40a": "0x244a202cd6b29e2026b65a07c3fb32422138a122e581a627e35791da331bc9050a566172656a6b612032", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2c095df4ecf754f5d54cc181242ef3a6a68c1fc61924efb992b4e4c2c7a21d528dca21d3073fd304f536fd99a5cf1794a": "0xd6aadb9a7f66a45224f6f83011f854c0b5758c626b213f97cbffded94830507d05f09f909c", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2c0972e8de0c13e5b5abf5e9475c633d76d6f646c70792f6e6f706c730063000000000000000000000000000000000000": "0xd6aadb9a7f66a45224f6f83011f854c0b5758c626b213f97cbffded94830507d05f09f909c", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2c09f36644024793eef9e286856d2db4f8e74741b4eab0c60f4b1621f8d244da79dc84785622e52ac8e4e5d3da9f9e512": "0xee16a0a68c6bb00ee88ee56a12ad67e778bbee540f868ead35fb6851fc522c0e033032", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2c0ad33ef6d83ca521b3310eb6dde9706c419b5e959b021c52f9afc64d96ab1130da2a03f08f820789a20faa24a206163": "0x844152eccf08725bea8ce898d6fc5362ff2d0bc9dfc21ed15fd138438d1606220942657a65726b6572", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2c0bfa6e33b308d851c2483e1c82b32f44e3d6c92a32e9ec43fd78e7d7b967fa28ed347d96028d73f37113300cfa565e5": "0x34a3f0845fecdf74f7aeb569953da8cf8f8217a9a167a4e7d6b3438d8bb6d82817414e554249204449474954414c205354415348202332", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2c0c182d03f1e9ffa82b584e07c5c05fb12c0e71c9c7a0df0270f56ecec10f80525ff477398256a84db44f8362cc9cb7a": "0x12c0e71d326f83f4e6089448e147fdab51b0b7398a7d0cc9a88b0571432e7310033830", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2c0e1ad46d17fc0f4b698a7287ef8fe3efca784faea5287b50efffea3b8ec2995d80648fcf5292f38deeb5bcec2d15e2b": "0xd86dba437fa4388bc312e57328e808cb1d37cd49143b90c338714703867edd7a16f09f8d8041524953544f5048414e455332f09f8d80", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2c10ad8e048145565807efaf7c8b46d8d0fca29bfa87fda85b6d07265341c56bc44fe830e4bc1d7b8cd31f54cac6a32d6": "0xa6c197a5b757309578dfde7a02e19aa9922b8f81a60e81bb0c6b7295090b3456033032", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2c13831eb5df91c871b9b1c11fe81eed6bcf0343edbf88dbd0b2d302af4a027cf7a1b45be2fbed9e9b11b6bb6bcc426b6": "0x608aa0febae80d8c228709183cf997bc87b0aa219cda0928408df22ac7ffef3904303330", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2c1824b6d21a6d089a61ac4a92a8da63458599575b1d7994d5f588624fa628018dc6357f6a90f488a2d880525e582a914": "0x8c8305ff8478e6309325ebbfb81e8c1883d39e65d2ef84f88e4a428615c4927704313338", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2c1d348ce50c513331c744df4c80887f61233533732bfa8bcf7a95e0dfca71309e49a1fdd70d43fd5c405505a6826ef72": "0x9c7c545141ea2dd84fe5ef7d567ea450f59967e7afa68e5f1ff7f7c46db19627033633", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2c1e5370219ef8bf404a05386035753985c9752253a165c2eccaa4dd8644eb754e3c760f586e935efbdd7c3b629cc0642": "0xaed98e15e3ed392e38654215c3d1fa8143de53460386b60139fbb45c036c1b430653462d3238", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2c2c0df7bcb2ddc198b401ed3b93b3d6e766ebc87370f898dd73004e524f0019b36a511b071efcc5f685cd935cd6ac57a": "0xca42f0b5c7957571706f29d2828291b148b4b162100ddcac72c507fd8ab69b2e073032f09f90a6", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2c2cac9c49da2b4ffcb8edcbc915771ae12c0e71ca560b3ce013e7ea6f20692d95ceba300e0b354cafdb4095a94a27e68": "0x12c0e71d326f83f4e6089448e147fdab51b0b7398a7d0cc9a88b0571432e7310033339", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2c2d19768bb70536f5095fd03d90932a3a8ad44d6bd00b9ebeda2a48ccdad36d0ca29bd930ca2856cc8ce1c109f938625": "0x18cf1686419c41dc5d3e76d373e3176c32c6d23c755fe1fc357f9c755ffc00190236", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2c2d4765322365cb80a91583d75048ec0d693e6d764ce80662d891b0e1496fc7afdfd3470eeb4d703ce721460bb459d6b": "0xc63b6d81d7d307b9f4464304330a840f5159c78a804dd344c5fcbfb3da9aad11064b52594e4e", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2c2d88f1fd0fa5c57e30db65a2d54c3d8e573ce3c1ed2c09f46eef869e472f6fc1e1345949d22b585d2dab0198ed34727": "0xd3754204488186b41e90a93d0607992b9cb992932ff66c2faef8a984dfe4a234054563686f", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2c34421b30f87d463f8dae047c202eda6b43e9512a0b56f6e9080b36543163cd843c3816854a331c48cb107c63ee42f21": "0xce5c65fecd7bb733ee636a381fa9dd916f8cca91e2e403c8aea2f7ed32b31d680e424c41434b4d4952524f523530", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2c368e1042e4bd743cf6dd650094c8968ac66f315467fc0b8d0d5d5d8906dae845567f911e24012ab0ebc185ed2dc6a66": "0xfc5d04e7ff3965c8285a2c23aa573117deeed886bbe5e3be0974f1cf0a2ff216073037f09f9a80", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2c36b2c037f282fb5ba74450b56b8cdc60e2515bd2e4ff6a32fed6306b3fc37095cf875c65f987c19c2b2691d8545fe51": "0x9c7c545141ea2dd84fe5ef7d567ea450f59967e7afa68e5f1ff7f7c46db19627033535", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2c36cb8b90eea3eee5d839a707af372125c97524a02c01e505359a29988f9098c6b1034dcb3ed8af5873fac659a10763c": "0xaed98e15e3ed392e38654215c3d1fa8143de53460386b60139fbb45c036c1b430653462d3430", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2c372ecf6bda917e8c3993d822e9d2938cafd506351cbb8a3af1f69479dc08628bcdc05de50e86e2f94aaa21306727b2c": "0xbc0525c374a8198f3288a0733918321dfc26532e253d94da3a6a27a4c3e317600548415553", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2c39dc7c0b3db9a41dc9d0cb970ab04784445d3cb2872e596cdcab7e8ac9815a369a6d4277f831287523ad9da7e60a53e": "0x128b1857f835ab1569c06a71e4de49df3154a9d5a5fabfa2a4f1ab1c458bc1400ff09f8d9d20434152424f4e415241", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2c3f748efc07f699c0be80180e548a68c18b8c0db8e0d79d681abc2cde9bcdf73e8b84b9e893952d5528d849a465f9a25": "0x56d629a2c80762d412fad9c15d8cc973b463f600895170d43a10ca504b4f454e16205b31355d20542e4d452f4b5553414d415f424f54", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2c4282e7215ba56f6fbedbad9256127c9d3247cacd091a8f95e795c76e84bc34db75ba76e13a79c1c4671f12f433ee83d": "0xd3754204488186b41e90a93d0607992b9cb992932ff66c2faef8a984dfe4a23406427261766f", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2c433a21d7d9dd5728f4fc2b5002cbe7012c0e71c85b306f02dce509fbd905815ba90fd450199f70a6e00a56341340360": "0x12c0e71d326f83f4e6089448e147fdab51b0b7398a7d0cc9a88b0571432e7310033736", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2c43d84a1afca11e60189cdbe2d58a9702add23627ef63d51a47ec9d5f0fa0d06fc3dbfb0e84183b90a13f072cf735300": "0x4866f45ae7b07019c03464e3c8c1324e96d3f05a2c5205e889fe597b0af2a70c033032", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2c44d77cf66ec684924776cfa5a523fba5c975240a88ac1dc2d87fb2de37a5d8759307dd7cc9281114515ca26876f530b": "0xaed98e15e3ed392e38654215c3d1fa8143de53460386b60139fbb45c036c1b430653462d3232", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2c47a4b177cb9cb76f304a12fb2e5dbaa326e27145577ff5e9bcd3f75bba30fca9622705f65a07ecf04a5d692b284ce72": "0x9085297d964ea873a23b63151b4c82189c1314c31fda6f2d71f83133d0877c5c054b534d32", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2c48fac29dc8b043a08ca8a6866a3172d405637fb518f654b40c86cf257796c857ac3c28e5ce0ed978dcc4d69a5d67442": "0x628f36dddf8cdb0242104a2531e7d3efd4860a9a4633be69aaf30f63ccb25a5e08322d4461766f73", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2c4a73ca17582841b17aef5d92af7ad84764e2315d026e1e02073b27ae98b6866388a0208294c4ca8e4d70e25f4ddbf18": "0xe2fec50feac8a6c83a3e9f869ce04ab800420b2c80c4310f2de2e9f0adfa301d0232", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2c4b11bc3246014d0ba9828c2f1e5006eeee6c7b76518ff52ab727047c1214470a0fb4fce60ed6ae06185a1501e9a4ce6": "0xf00168a3d082a8ccf93945b1f173fdaecc1ce76fc09bbde18423640194be7212083039f09f9a8020", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2c4cbbc94ab26be6a5bdb9daee5cd70725ecc1d4e60a92262c1bec62d034c979f42cbd3fb1c28570d5baed6e5ed20d533": "0x5ecc1b0043fe1fc18950cef3726fa74151bc41f77438ce924c11a9b43823ff43035631", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2c511c6d5a2c38335a61c6672dc3acd6602a6ed2142a394d0f42a51281478530276f88d15657aa277b62c54bd1576f322": "0xce5c65fecd7bb733ee636a381fa9dd916f8cca91e2e403c8aea2f7ed32b31d680e424c41434b4d4952524f523232", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2c516cdf13321f494db81413474fc683812c0e71c49ca78c235b4cc7c02b0dd42d2ba68cae14091330453206d11f34a56": "0x12c0e71d326f83f4e6089448e147fdab51b0b7398a7d0cc9a88b0571432e7310033234", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2c52166ebfd1d6b8020d3943d7cedec91941acddb878c9380546d8e08a2c94431dd6943d8c238428364d4eaf95218075e": "0x983c5a0d1f1e697c1a0f9798bc25543603751b41102d41c3b0e23cbc6e3fdc0b11566978656c6c6f5f4374726c725f4949", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2c57d41ec62587c3fb8186cb0e3dfd8644396d758a45239e3ad43d8ffa0d171a6785aec18c571107c6675d53d082f09c7": "0x92e02ce87428939cfbb7fbeeb1ee758b749a5854a1bd3ae9ce36b3bcb753010c04303337", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2c5e7f71fd200b6fe4eb9835f4d1b25ff6cf4b9ce8d60ca73a35f036cd58afbc52ecea4d691484586967ae1ed45a1c423": "0x9c7c545141ea2dd84fe5ef7d567ea450f59967e7afa68e5f1ff7f7c46db196270235", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2c655baa60c6a1fbebb249e33cb0b9add2bfbb8610a814c9052c287849831e4e28789a020afae5a23c9a19d3f37864a49": "0x0a71c6a0fbf9b63ac089c5395bdea4917a84aabb3475d4454147c4d24ce1013a033031", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2c663bef8269796b13f10c0461aac5d7a460fbb15abc6a11bacac5accdd7a64ac63bf649e22c4efb879ff0cb0446b7e8f": "0xac2709eb9569c861e63940eefaec1f51ccb76eaa84544e56331adfcdec85991104303033", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2c69574091b5b55b20ca1398ba24ed8127e91f2c936482460b397eea5923867efeb2635679ca776cdfdc62bcea000250d": "0x9c7c545141ea2dd84fe5ef7d567ea450f59967e7afa68e5f1ff7f7c46db19627033333", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2c6a263da35f84d08100669e601eece0f7c731b26739bf75d9607468391f9d743d3ee7f65f8e668d770174f74dcab7f43": "0x7a54e6a55c0453407909789a06c3ee6719f8735ac370d6f17dc342717fd76819033034", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2c6c3052eab8465f19e95119c634901719e7b589d0d5c36284021ae227a2e2be43e1dd1b67c0df432648e5026dfac6f43": "0xc46ff658221e07564fde2764017590264f9dfced3538e283856c43e0ee456e51054d4f4d4f", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2c6d5d6ccd4c98d250adb9db370fbd83c240246fc1579b9f65b2c83cfa020ea61e54330741399b8acbc8b7215b8dbcf42": "0xce5c65fecd7bb733ee636a381fa9dd916f8cca91e2e403c8aea2f7ed32b31d680e424c41434b4d4952524f523338", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2c6f5823bae5e0af2ed8e01c4052ef851473d3b1ef58c6170dd0d8e4f61cdd1d594cd17280988b52a7333b3a98fed4269": "0xdcb38c186bf97625f108b4832981d966ebed50d939349d4437a6f538d40d56760c56616c696461746f722031", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2c78f02cbe754419892002443c7030fb284e7a9749fd2b23ce7f7b775dd0f3808d6cdab42ba064fb242afdf0283e60a20": "0xe04ca25cf1cbc516ed1c138492a7f2e606f60c5a9ac96cb405eaa3914fd129730231", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2c7e0feeab14ba681f29b85c5ad4274fe9dfee84695666c414061c119c231b91511e18267044792868388c73f59306474": "0x08745476e8a2fb16504c77a75b2dd20b6f56cfb71c87125f1707a702753af24e0d4272656164204c6564676572", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2c7e4e58a6554f3b70576f68ad2adec1112c0e71c471767a1c8d1f0fbdc97763c8730745526c890b3d603d90337caca44": "0x12c0e71d326f83f4e6089448e147fdab51b0b7398a7d0cc9a88b0571432e7310033735", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2c7e7b67dbfb457a80e1167ce2823f278867c63888fb81ef44bb0d5b761d8b536abaaaf5dae3b5d23891554e924049a4a": "0x54fda5a0e241e5497283afebd81b53f6a0235abf62a9bd39594be3f42d291e7f0232", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2c80d069f113fdb657473619a7965822308c74cb0df1d73c69a078a6dd56d80ea94e08a2f72cba07ce6c5b471fcca8976": "0x9c7c545141ea2dd84fe5ef7d567ea450f59967e7afa68e5f1ff7f7c46db19627033639", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2c862a10b89cbe9a3dfa65a39f18b3993ee75ab2836d2ddd324049b86b224542d6cf8a12b601045ec14c454fea4e9cd47": "0x9c7c545141ea2dd84fe5ef7d567ea450f59967e7afa68e5f1ff7f7c46db19627033534", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2c87238565a7c87c42dc1d0af6e850914bec1f258092973881a9591a5f751a5ca2b305c6bac9f4500c0e56ba02dd8581d": "0x9c7c545141ea2dd84fe5ef7d567ea450f59967e7afa68e5f1ff7f7c46db19627033930", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2c87c742f32bd7ed02b901c06bc6d6b877fc552b8c6596a09ef8008c83d1dc8ee77dc175036bbd2ca89a55b855a0f01cb": "0xc0b881e2db47fb95982cd5c364b87e6cdf5a5c8a336d980156623b53815c597b04423034", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2c88ef78987683612d50c0be34436b628b64bfb076e6685695cbb09316f448529f41964fbbc9520059a0aeed64d63761b": "0xc4516751df2e5803bac3bf9cf7b6d55cf4acbd76f861ad0a2a2b71b7a5ed805406f09f988835", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2c8b8e9bfd20adf75bb72e680248543b6241816355a91d53c772aebd5c1ff1114bb35fd22995e8b0d84fe770304b80352": "0xa0ad3e520332a754892d7a16de9de871b9f20e982d62a498b5d9c7e5f93d433e0232", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2c8bad951e3d5c6352288db6618ba66b03b839ff2a9cba91f5d0a511651c76f3ae7e0eb8bc76d7862338f987e506ba6de": "0x58bb56063a47ee6e4a4d0bfe444682394a1e4657fa39f4622f2a0285689c1b3c04303037", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2c8c2ebe9ba5122aa7c5b611104f6d2133c667aac50304fdae4ba9932ebe5628ff1e133986bb2e1ce686f28c6a5d4ac27": "0x0a409ce1eed912358015a8139383b02292284b392bf23ef9eb89c7f31ed7e10b0c47414c4158594e4f444532", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2c8ef88b4ff9043b10d3482e3d690190188d38deed3dd10c90cab2c1a5b59040baa3c1742b2439d6c4ac83df7da5d894e": "0xaed98e15e3ed392e38654215c3d1fa8143de53460386b60139fbb45c036c1b430653462d3231", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2c8f27ce4c04af2dbee5b29cf6738cc4e64dd9ec1480c8ae7a38a6566f4634c7f1b5253a0fcd426b3c712d8e2779ff71c": "0xf429460ae52548e754c712a7cfc75f1bf7c9295da165293ca52ccc686db5c02d033033", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2c8f65b71c2d877b722553f31af6ccfa9c61e997a53022149bda8907ce19e1780b9ae75e23fdd6b44fd5a6adb4ff91801": "0x14cd612ff7f390b9e90584767a00a4e9b740b61c0f2134698bbac79c6649764d067374617368", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2c8fe8b016f9239cbd637951585c50f2512c0e71c4dd67a196937bcfc45ed0384d81a3b7e8a5b9746ac82081c4bf30964": "0x12c0e71d326f83f4e6089448e147fdab51b0b7398a7d0cc9a88b0571432e7310033634", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2c9112bddeb1c092662778b846189608264563004d7fde7f69c99e461d43e799f2b8bc69c9c6941a265f5fe1e7e50c464": "0xbc486ed2f394da6e6b58b130687b48d3d19f756ba6d0655d37bf58ff0f59f974104520504c55524942555320554e554d", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2c92041aceb812cdc1cfef27b6e230ef0eea34392724db7a397808df783a7fe52ae6436bd9c2d86af32abe8dd81f43c33": "0x80dea82a6a4704d208bd43d1ea1d5a0bd97a9d20c5237beb348be8c82f37d93c0644656e6e61", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2c9237312715124e8572d812441a946b9980e50eb048a8102b537fad10ac389068a37e29e93ed6cdb700ee571eb988116": "0x8adc4e19e79b3d2c744f88fa5aca47ef05ccaae141f6435c2d50df824433ae480234", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2c93e26ac998c0f325e7513c26a2d488436ea3b4376625f8f5ac0cf7b48b7a186f96bc215f34976f9eb692eadb46ce29a": "0xac59122f8bc8c527a8efde87156403558ea66ca0ef049cf3fa4f671f98517d6104303131", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2c975a2d94f7f370b9deebb70fcb33468888593ed4e02aa8a39aed15ec8aa2f0ba2eae732b9e2bf7f6d72b6d012fd925e": "0xb8897a746ceaa53376946a3da353c1c987df8c0caa4395ac0eaf0e6c748740540656414c2031", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2c97ab4211b2be80337ce8db6424a4b82d2d790f992e31eec84ed33b3ddf3e92ecaeaed911f0026c2ca09087f3eb1d3eb": "0x00f52ade889dac25285059b639359071c2aad88e3f1f60593f86cc460ce2021304303236", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2c99c694356696e0d88c2b9f0978eaa40d6574db78e7c0315546032b1775930c40d4cca7562e9210cbde93344aad7aa54": "0xe04ca25cf1cbc516ed1c138492a7f2e606f60c5a9ac96cb405eaa3914fd129730232", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2c9a3fca2fd6455d970ee5a18021cc07f12c0e71cdddce276170fdafc609d13aa23bc51e46a52772dcf1e378130b6b014": "0x12c0e71d326f83f4e6089448e147fdab51b0b7398a7d0cc9a88b0571432e7310033331", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2c9de13c0f1f94250695cf5357c033fed5767532cfd7c17f35bb22551c3364d9737749661b25f431f04df8364c9db3954": "0xac33b989d0b4dd35d2fb8af4cd04cc5a3831e59023cb884044f5cda0541f1064033036", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2c9fe0fb7c71abc4543f69c72b7a12f10f29100ef06c7724dc32404caf185c03adcfe64e92a3a4885e08cdafab2594d2d": "0x9c7c545141ea2dd84fe5ef7d567ea450f59967e7afa68e5f1ff7f7c46db19627033431", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2ca0a74073e20c91c21ead30bd7c080ac7bdfd0ce52699e0b3f913ebc544b48b0cb02fcb8cb394625f88945200318f592": "0x0093c7603ddb81760e5c90ba6c0fde51812e18e6cc14121c081f5a573a86814204303237", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2ca264436f692517aac39a0019195e8e55a3116fd94d5f079378c4b1f2066ff567078ae68d97100fa408185a98ee92fb2": "0x9ee1fa0d8d4e022ed5680b5925d19718a7ecc9f8f2ff77de54f0822978d2775508576869746e6579", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2ca4a896e116624b2861f94798a238d6a29cba2b60e937fa112f8e61fdde36e4043d0c40b1eb73f12b5534b52d01b5e16": "0xc0b881e2db47fb95982cd5c364b87e6cdf5a5c8a336d980156623b53815c597b033035", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2ca60b7ae0e6a88784f6dbde953128897deb536d9d2138242abbfb7d0f1b7b2905d8316566edd28c2d029996a89e51e09": "0x008d8404893c7b4b80f397605cc96e61fec3c89676c8c2794a2a7d281d678b1a0e4d455a5a414e494e452043544c", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2ca68f8e1e13fc625a7186db589a2d5efeaec5e47daff641a4a15c87ad7e12649e07f6ebbb54630b984952184c657e441": "0x88e89854ec5f225c9a3b8889d4b1afc0cf6cf473d4265a96463c08cccf38905b033033", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2ca791bd928f52765c183f6f1589e1951c2b69f99b0ddfb88c8fa9df62c4865ca4e69515a21c16bde93c726b1e678a156": "0x8c2f8f1570391214b89f82df1e2e0c12f9e2e814cc8e38b3d8baf3692724a311032f32", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2cac3a1bd3e914af301f241775717b98284993faa382230fb6bae24747cb90b01087b26817950513c4b313168b517950a": "0x4e516d9d6527c3bdcc45105195b8e23480bc0f257308b1f4fef03e06efbb1c5b00", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2cb02f7923bef31f1ce1312dc332cf80f603d8b10a42a8be5f7e755820b0c4241732614384e039536c8e43d3b41443056": "0x9c7c545141ea2dd84fe5ef7d567ea450f59967e7afa68e5f1ff7f7c46db19627033331", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2cb0b84d68fc7b2a7866ad3cb80b672c24c6a12b41192cb3355642a4de4fa55ae61387c23673f0e8c8637dd864eb0c443": "0x9c7c545141ea2dd84fe5ef7d567ea450f59967e7afa68e5f1ff7f7c46db19627033736", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2cb15507f9629d869c55b268697b25ac0d6d65677fb307c3ac6c6c0405a1ecd9a47d0ade13ebd9fd340038fc78d9d8836": "0x8c8305ff8478e6309325ebbfb81e8c1883d39e65d2ef84f88e4a428615c4927704313039", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2cb2339fa49f11b9c1fd38f5f968d07102c01bce1cfd949c169cf6d216d5c446a8c947147b5b7f128b6a46dfe92f90f00": "0xeaacc14e67deba7935dc28c86bb8b6bdb64239065b718fed6b8691ce141633500953494c49434f4e53", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2cb40f49264114da393e7182b3be70e075e25f73392aeea8ecd64fd33e2dd4728e355e314d8fca42e2a382f95a941d6ca": "0x5ecc1b0043fe1fc18950cef3726fa74151bc41f77438ce924c11a9b43823ff43035634", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2cb5a9851dff4fdf52cfdb2a41da2aac53ac5201c3a4b0b032e701e34988ca6a06831b69aadaf9a388dbd33d85ac85f6d": "0x14ce4e09b999c54351c75b74d0bafdd17d86d98b6aab5176b9068e1be13e096f0244", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2cb65691609bf934f487f8039e13f8182305b1689cfee594c19a642a2fcd554074c93d62181c0d4117ebe196bd7c62b79": "0xaed98e15e3ed392e38654215c3d1fa8143de53460386b60139fbb45c036c1b430653462d3237", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2cb689f2fd08e34f3e90238d841086e91d8151ecb8e8d11e6c6bd81ae49216b9ef92d2b83b3ae39702a397922f1477768": "0x7a895955042cb3fe863f3564e7b30e9130e37b6d905be11c0cf91064de1cd83a064672617a7a", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2cb7fec13b4b0d346f813adbf6e0f4714d2de3abc2fce0e6fb421d7a29d736a9ddcfdf51244022ffc483a291c4e4da958": "0x5e97f331813198763da88ad2b1f5deb3f42373a93e8895c43de399aa6255da47054b413034", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2cbc95794f214bac79234d84db933b4666a1241c7ef9541ddaad26287d92df0abacf7ac4a7fc4df046e4b866c05db4aab": "0x1c6d8b40be9990c19e993d238e6e3613cfc6cbc51979d5fa61dd6ea2593856090235", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2cbd2e8e70dc5faf3239fa2b71325c085426c1e2855920b16c78a37f7b6f480163f2a876a889f78b1ef2d11ebc9fd1459": "0x48ca001326b583070e370be3bc6680d09cad47649584a5c992bd388c693b9a54033233", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2cc0032b7847c0117ed1762e6f5618b9ce25940a2f472c60c242463e18c20ab6555074a0644ac2b9583140abc15e27124": "0xabb9286b2b288f2af6eb392d95b12a64768174de723047b9ae0f86283dd5e34c055368657a", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2cc32df75fbbde634234f8396ad7d4c25280daf6efb2a16974f928da1abda06f2997f18a8db3cc73dab3cdc97d13fa520": "0xd4e6d6256f56677bcdbc0543f1a2c40aa82497b33af1748fc10113b1e2a1b46011f09f8d80204b534d20303420f09f8d80", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2cc5cd9eb850ca3895f1947c8669274c754572de1db5ea15bc7731401c4fb92ba2ab3f7c387acdbbc2590a673bef4e248": "0xf6b21d624832094b03aa672e016462a020e217cc67b1434785b99114a2b4fa5a04763337", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2cc60d0fcf17e5894976fdecfb422e9975e5085f483896c9bfc341a80912faf167a1ef9229fe8b2989de7b6bad03c63cb": "0xf04c95a6ac10a0db5af28ac44776f95949dd543f494f8b8787925c41fccf7e0f033031", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2cc69ce5a07e89174505f3dc6f32b0130c6125fdd59c2b545e1032e0223a7ae0e3aa3c4ebbafe72576dec399441068e3c": "0xf00168a3d082a8ccf93945b1f173fdaecc1ce76fc09bbde18423640194be7212083237f09f9a8020", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2cc7658cd138d09c0993a1fbfc7d4dee1540a38c94322e193c52afe4d438b6d6b1c50a9cafa87e47f1fc41221594d5f39": "0x7c88cb63517049b0569ba773b2cd7be3dea4c7c88340ba5f31c7bfa2e847f65f04574d32", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2ccaf6e6baf961c91815720cb19b07a1dee67b25f8646b574d06dda6da0b74ececa842c48cdc5bd8fabb48276f28a6043": "0x52e73898bf4601f9c9a7fa052de0cc313b159dd368d458f4cb0341eedcd6d818076c6b736d3033", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2ccf2a14c5e31903431298a626cb6338886505f7c520a5d79d531e99903d5a18615f4510652500f511c8052d8e6a42721": "0x0a71c6a0fbf9b63ac089c5395bdea4917a84aabb3475d4454147c4d24ce1013a033032", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2ccf79fc0aca9b50e29400ea26e3766a3f40945c32b5bb894f311b2a680d927a1d26080b3b4b1c8b5bcabb196918d0e2d": "0xd4e6d6256f56677bcdbc0543f1a2c40aa82497b33af1748fc10113b1e2a1b46011f09f8d80204b534d20303720f09f8d80", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2cd4c0c53d5dad472fcf92c48f39dd8b04e9a1114da2f930a02193c823ab3393fd2f4867b0ba68ab5ec267e50ecd35420": "0x5271937d9336b12c2801a62938d27878729a7987c705770d5f19c0e42ffcc64c0c455645525354414b452032", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2cd5844c23cffe5eeab0272580b3c099e5c97523e781c4c65e7df12bcab25d2f3ad96a2e73c9252da3b889bcf77aecc5a": "0xaed98e15e3ed392e38654215c3d1fa8143de53460386b60139fbb45c036c1b430653462d3138", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2cd76e777b154c1f906b39ca7917edeac0cb5554f54c346c7996d2f6ad6c5bedcdc094b6ce0bb9a4afc7db6ae865cd378": "0xf6b21d624832094b03aa672e016462a020e217cc67b1434785b99114a2b4fa5a04763036", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2cda725c218beb9ad3ed6c3f612069deb9257672efbce6327e97783808a8feb2ef8dfa71bdff401f06700337dae17a253": "0x84bda1949a2b78bfc3b12dcc8f2c8e8822912efe0c693a23effaf7f3b54e9a5c0232", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2cdae06255e18caf09f75addd45e7945c60bcf3dbbcdcb2254472d74e7522e08b6e35bfab991d39e17c8e35ab634e3c28": "0x34f589d251903b0ac5a22b1d13d54696fba34b77f5d21f5244de9071711447630232", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2ce65ba8dc6d139df7b9d100a5355959d9c9d52f08adf4aa10b316922daa16d396cfb66bf6d3b87454d7a468e19060f68": "0xaed98e15e3ed392e38654215c3d1fa8143de53460386b60139fbb45c036c1b430653462d3139", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2ce7325022b2841cbd87e51dc0fe475e72f9daa984f4b569c43ddfa8b12c3f75e2e02f8c0ce9980e00daec2cb391c74a4": "0xf00168a3d082a8ccf93945b1f173fdaecc1ce76fc09bbde18423640194be7212083235f09f9a8020", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2ce84651c82027649daa82f74929a1a68ac5912fc44a3f886271bf2e8f0dd2d5f102f7bc313f1009b771526114fdc2d70": "0x56d629a2c80762d412fad9c15d8cc973b463f600895170d43a10ca504b4f454e16205b31385d20542e4d452f4b5553414d415f424f54", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2ce8550d1d22ea15df455e6d9bafe27d0befe117ae4a987baebd13ac5c3b611ded994a75dc9ef2dfcab5071688ec9e2fb": "0x702a6dc9592ec94ce9e1f07e2a0559d7f43f932101bace2400d0e92419218732033031", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2cebc66c2defb142ef92b6aaf4fd35cd226090dc5275e53b65763f135108a9111289aa1ca6331a8ddb3440059cd33d75f": "0x26090dc5275e53b65763f135108a9111289aa1ca6331a8ddb3440059cd33d75f076b7573616d61", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2cf19e88c68ecd0fe6ff5531f8a20c3d056a88434d91c219575e30f91afe0ef870901772375a33f006fa82b7c743b4917": "0x9c7c545141ea2dd84fe5ef7d567ea450f59967e7afa68e5f1ff7f7c46db19627033936", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2cf2a472468ebd4c5207391a823f9eaf954cbb80bdac7fd85808d631bc4007c2b928e88ef08e8773d7b26e0acce33dd39": "0x7ec07e354ed4f92abdd5a1570470994410ad04181deb63229bd98ff39b73170a0f4b454241422d5354414b494e4732", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2cf3df5e48db7f78958ad9e0c84b7a87d787f2dc3f07598f255932ee1fd3cdfea934389c61a31473a87d270655f70811d": "0x287e6f010e50f642775dab59f39ee4de313fe6325181ca603824399cf4d42c080232", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2cf54cae9e2c000cc351b755c233471197618f7a742a744daaea9f6761f81fc54933a584cc5b4870a47e9525f42cb1760": "0x82299cce0c148ac684639df678476effcae36c4eb8cf15592c511512a857e7450256", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2cf59286ba700190de3e238a509f05654e2dfbb25f8e8e6047e14474e054090c283b6c8d34fbcc7370fff8292592f934e": "0xd4e6d6256f56677bcdbc0543f1a2c40aa82497b33af1748fc10113b1e2a1b46011f09f8d80204b534d20303120f09f8d80", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2cf5a7a71268d5aef05bb902061376d137294d22dea735215a7ac4a2aee260eb25d1beaad4b02bd8dacf87bd611a96c3f": "0x7294d22dea735215a7ac4a2aee260eb25d1beaad4b02bd8dacf87bd611a96c3f0e416c656e61204c656f6e6f7661", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2cf84a8a77725503ae8de745901e90a5c0aed675c9de132c2b598f6fe8d256c8057b2d2cd28b2ae3fe6fad5475b407324": "0x7a895955042cb3fe863f3564e7b30e9130e37b6d905be11c0cf91064de1cd83a033032", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2cfc822ea97fc4ccab14633d946df8d1370a8fd1a49157402789a0c495dc9c9d12e87a64805374661b32f1d715ca22f5a": "0xd896f718b4ad053ba53468ba0347060b4a80f03fa72e9c14da5e2e7ea80e3f2c046f6e65", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2cfe0705b1ec0b13dcfca8982fe2be0685e0a33a0fede6d4995303cad923ea9cb39de708069630184e76f3c276b76c772": "0xce5c65fecd7bb733ee636a381fa9dd916f8cca91e2e403c8aea2f7ed32b31d680e424c41434b4d4952524f523339", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2cfe616516a4c40b9240377a15fdd83ec3f9bd8000dedbde0a47dbd7bf089dee1fa558ac28796942a5883af07ea59fce1": "0xcca2a0719fad006090aad6536ca8b7d8c527589be01b0012564dbdd36d9a492305f09f8c9d", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2d027c850edbdd122c1ca049f4f84bcbe6cdfaeaa8c9eba3e4d30f66d1b53a97f830612cdcdb1ee1d203a797ef4973125": "0x4e908afcf0fb6b394bd1a043bc8b226fac33b4742731b9cde5d324f450eb3006054b563032", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2d05351a690517c7ff30db70d638702339a7f00455c8ddda3532450ad2eae9a5405522b11b320e52851ac6fd870b12d12": "0x78baec43fd49badfce811cbba08b3f0ccf758b5e22f0c4d745452f5dad6eee070f5265776172647320436f6e666967", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2d0c0098f070694c79f4ac845ed9ddfa312c0e71d489fee1707d4857f5f4cca6e9ccc10a81fb25b9cdf5c2d872d0f3a5c": "0x12c0e71d326f83f4e6089448e147fdab51b0b7398a7d0cc9a88b0571432e7310033033", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2d0e999d1814db997088ab8eb16c8e4ce2c61f078a240b295eb8d19db50e5b27b39225ede1cf718c0872c441cb7ac8d54": "0x9c7c545141ea2dd84fe5ef7d567ea450f59967e7afa68e5f1ff7f7c46db196270237", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2d1225dcab17d4833c75587142b80cdc916cec430366d2ba6b46f6b084f62ec4f76967ec6fc65101e6de60c92d2751977": "0x664b2886e95f12e168b420f06b90c11d8cdfa7ee747bc12e235a6d5efbae6e12033032", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2d14e8491c6088ebd501c2798aa90a7983e8086aa5e41114ace08f4330aa4d5adca61f5dab191bba7ab6b2596f1c40c18": "0x844f55022b2b8667129c167068a9c2a6bc292f2d312336bd98339d686b575a1b0e414c4c34484f444c45522d5631", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2d194b05dbfa05a400c9c5eedbd8b124c3a43a4e20e15a0c9e0009fa11135246e1de9cf4507c1945bc86cb0a088c1c465": "0xc0b881e2db47fb95982cd5c364b87e6cdf5a5c8a336d980156623b53815c597b033135", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2d19b2b7f6f4027c79a0abc64de1ed2c7a570c6ce21a0b2f432dfd11756cca948259a8b281196ccec975c681372a06280": "0x3a731ac0ae7375a2cce5b504484d91f1c49923b3425072e36e12b0afd5f2a8570530303031", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2d1b6d842ffc033eb576b4e2268de1a3f6cfe88656d6a99bbf56d216614a02ef9f0182f63dfc21d7dfedacb4ff517f135": "0xf40cd7a2181289e32776625b9f3a193f749e33ce1bdeb76cfaabece606c7324c1968656c697873747265657420666f756e646174696f6e2f32", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2d1d8e0232be19b72146d75ffbef993757282bd520ed3b58e948d1e3ec6d993c607c87f153a9b90954fa973cdf3adfc54": "0xa845ea35913a0fbdec49687ebc5b1579bb632c080ce61b02919ba40bcf8892760234", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2d1f92b7f176d02ad63f25f36c9c66c1912cc166f2df9f0fe89f79e2b568a6e92d61ca5f5f53050ef8744edf74aced0fb": "0x1c6d8b40be9990c19e993d238e6e3613cfc6cbc51979d5fa61dd6ea2593856090237", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2d26582886f6371b327d9d490054d68b8681559f05e3544030950899e305d923d8e11e244943c1520c35e801253d28008": "0x8e32641448f9a5ec78ad04a33b7874a2942ca7ad4c7e8ee2e45409cee1883e060231", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2d26ccbf305e9a72d94dce38f185b6f613a4d56fc0f3aed44e21a24d0a3c17a4d6c1360123ce0a4d9a22aaac577031c2e": "0xc0b881e2db47fb95982cd5c364b87e6cdf5a5c8a336d980156623b53815c597b033136", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2d272d57e3f1f50afcf83e2781a1a3bffa6f39c26ca691bd958706b03619b5579a313404e93089bafe5760b2a9db4b551": "0x6c335d86444f3189027cd53244265047e52a96b4621fdaeeb9bc12857789867608e29aa1efb88f34", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2d29b1f2499b255d6726de0fd9a8f33d4b842b822ff26324247b6ac5a4f3eaa2bb97ab63a9ca95c2ff07775a1858f0173": "0x78283798169eabf7cd6924745cb60df616354b36e53549fd8dd71e815386f525033031", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2d2eeee9a44ebb023b302f71ce92956c9807a095defd81e409429e0f0036df659f3472f90e3b9376e669b71adb898702c": "0x184d701295be7bb38b2c0c58a35bf8edc592671c53d149d206e037dc7c9beb7b0234", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2d332c90c9ea90c0bc0897fbf38b83925589d797b259ba12d5f74d118a2f63fdd5b519b69003821b9da81614225776a2a": "0x56d629a2c80762d412fad9c15d8cc973b463f600895170d43a10ca504b4f454e16205b31325d20542e4d452f4b5553414d415f424f54", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2d339f0d287fd7b01b925311f978fa71fbc154c7a8b77c508d364f2ad31111f48c1eebcd3367da39f5fd907b510e5e170": "0x68f8bfef657c69a5c34721cbaa618ae9eb2108566f9a2606cf5055578e0c251100", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2d3804a2d371ac6b1b45ff1c4db978cefa61366bf4c8e9f8fa63bdf70263753a1d34a66a616dca43b48c9f99d2c641c7e": "0xce5c65fecd7bb733ee636a381fa9dd916f8cca91e2e403c8aea2f7ed32b31d680e424c41434b4d4952524f523331", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2d39abee85bb62414141a5baf3a7022bc2dc4deb5830a5e765042800fdbf03927e72ad3d40644360b07cf9ac241638701": "0xb45b073f1e692d18c2dcebae861b2f166a4dbfd95d9780ffef603c9e61d0093509416d616e65636572", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2d3f2c11ab0f9dcc8fdcbe4b7d2419a2ea6cf293e01355a99ab2429bc7d9f56bd24beb526079ac3eb0a00c3c70e4f6465": "0xd4e6d6256f56677bcdbc0543f1a2c40aa82497b33af1748fc10113b1e2a1b46011f09f8d80204b534d20303820f09f8d80", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2d3f889daf4e1933ed169fde2153f634448ff655461db0e896365cea6351beafb80b40f19a3c453fc27e6609f872e4238": "0x9c7c545141ea2dd84fe5ef7d567ea450f59967e7afa68e5f1ff7f7c46db19627033637", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2d3fbbbc50dd153421623bd762a2151e4c6150d4b20644caff90e355c0740cf211f04ec624a65acac57608e7390488f0a": "0x8c8305ff8478e6309325ebbfb81e8c1883d39e65d2ef84f88e4a428615c4927704313032", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2d3fc34f7bfb87eb2c0895361a192e82a94ee7175041f3293479d3abab6dd9fd5e5d463f539bf6eb18a2bfc85e6c5bc54": "0x16eaf9666bd95a04bc6ed619c30a4809a43fd7265e414284c11b27b8c666fd23084b686173746f72", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2d41bc04620b2161b34eb34e6a47af25a3a337becdfacffca71fe67fec208733754f035958d349d36b30225fd47798f6a": "0xf857311106c8d7b0daf6e096db9a0d759b52403e439ab23fd6559780a8b1c803066269736f6e", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2d435c2aa12bf8a0adfbadf18fac462d02602783d96c4e25d8f6894e457ceb968bf1c9694295aee52514d4919056cdb12": "0x26842927c98a50ab1d439ab45f21c5beb6970556e1fd7b52df44977e4344b148033032", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2d4a320b2374d4601da0b577a391500a08a51fcf7cd53d24e15d85b8180f31d5f9b295af7841f9448f80b7264f3818752": "0xc229d8ccc5e5650d17760ce2b7c42bdae5f6afc6e8bab249ec77f3f779ee5a6512383a206e6f64616d61746963732e636f6d", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2d4c814a5e0c2b6022849e302087912d44f00d8607ea768fa23a0befe7cead74f5f99102a70f53aae2cf68922f526523e": "0x046ff960b0d51db710b8ca414171afd47c9612311b69fa9416622dfb42a33124033031", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2d51de4a39ebe413b925af948980a9318ce00415c4b594b4c5085fc803c7eb7872847b7b50fbb0ad93cf0fb95c7a0bf68": "0x7a54e6a55c0453407909789a06c3ee6719f8735ac370d6f17dc342717fd7681903434c", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2d52334bf3f7bd78a7fece8f120b980605f5013d41624228728182b71bbe799dce7dc5df6963fc02730c6b4b3e84273e1": "0xf00168a3d082a8ccf93945b1f173fdaecc1ce76fc09bbde18423640194be7212073132f09f9a80", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2d53c55f298492f938e93d235aa93defd6c98dfc795cd34290966dfa3a4f690a2c703dfaa31792854885295a61cfdd670": "0x8a320af9e031a3396f15acdcc65c43008124068226505ee7e12bbb0a12012e600c546563686e6963616c2032", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2d561cdf3d173b0e7dfe0ebd50b63f0a9260707c021782450fc2707ad65e0ffebf1f9e4025b69b8e192378e4835b05f74": "0x8c8305ff8478e6309325ebbfb81e8c1883d39e65d2ef84f88e4a428615c4927704313239", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2d5741a0a36a4d5ff8186e070a2e5f417d4cc99150b203e2ded46d1bdfa43c2f64f89cb4a9102e8e6d5b37784ab97b117": "0x9642d0db9f3b301b44df74b63b0b930011e3f52154c5ca24b4dc67b3c7322f150573756231", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2d57f307487465f7a00d54cad65ec792a34a2536cdfc1e92e55a4f4c1310aa2cb76257a87b0e66cea1f2d392c7080be22": "0xc8566f6d3669729e877cd5e453d59f6be01ae6f31b7a9c9925160e70072f7242094d555348494b4132", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2d5912e8857d3fd846b9b7afb3d401568d091cf86d04141b1c17c70826c08d074cae1b00d6f82de1b8a5406ea10ce723b": "0x5270ec35ba01254d8bff046a1a58f16d3ae615c235efd6e99a35f233b2d9df2c095452454153555259", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2d5a47d7294408d90d3f758a183db159d49820d872869c2370f72f871556e9584aeefb7b7de62e6559c69f1503cbdb545": "0x1c6d8b40be9990c19e993d238e6e3613cfc6cbc51979d5fa61dd6ea2593856090238", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2d5a98fa4765f4842f41161a64bdef2980cfd5ba5a03ebfcf979f3bb7d68fd694bfc64d37bf04ca7b2e87d4e38827f94c": "0xce5c65fecd7bb733ee636a381fa9dd916f8cca91e2e403c8aea2f7ed32b31d680e424c41434b4d4952524f523531", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2d5b7042dc452982b56910a0b527fe10c9cbecddcf7044de2e7f8aff6dddd8660e28ef5214c59623dd37a62d950da795f": "0xf6b21d624832094b03aa672e016462a020e217cc67b1434785b99114a2b4fa5a04763332", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2d5fa0362c54826076a67ea94dbd89fc41884855fe5ccb84c814252cb959d599ee9f90de9d3b7c65058b75c39f21b2802": "0x225f2459239641fc50300041f8980fa044cb07705db61fefb340804172b1c25d033032", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2d6422f105e1d8cb4f11ba2d711d212f922dd0bd944bf21712d577daa894b5d2def3b907ed1ce8cb334dff3c8216e1a59": "0x50df6ec6f3dbb1134df6fd1d572d4dfdbe1058fca0e7197ef8d0f3d05a720f5e0232", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2d644185f1c9275c27934b091f00ce5aca56bd842d168e9b1eae2ef3d1f6d323b9bd4b8db997ffd2ff52369e5c0ba5512": "0x9c2b14c09923911fe0ff6918b7c7702a91762aede2c2cdd0f1f0bdcf7b9f2a5a04303235", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2d647c6fd4fc90d8ae0a3118849fd10e144a8bb3fcbbd5b54617b782667c7f8c5a89ca53c1f878cdc9dc1766f447ea30f": "0x269fa27098d88ecb1640185c91860fb62d92ae9a6ab7713c79485bae49862b39033031", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2d6551bb9732ee95a0588e7c3edff87bcef8d3f3e96613631bf0c63444db7abcc063f40cfcd2f4b477615443fb8e84d5f": "0x4ef63a0f97791221290fd19207cbb23ec5783221b5016afa55161b01dbb0125d04303139", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2d6916cf16eb26f9d1c7af3577f43b00c367c5a125977696926fd9820f8282c73f7a2cc8fa0dff0f0153cd7519d6ff316": "0x20112dff656489548b0a7815a06d3a59f93880ea46ee2662a6439bb431bab04607736972697573", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2d6a9f2d02150c4f45638b84b15be87b812c0e71c4aba6d53775e0a27ff00a6090b2d9bb4171096109a5aa2a59328df61": "0x12c0e71d326f83f4e6089448e147fdab51b0b7398a7d0cc9a88b0571432e7310033633", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2d7c3b31efac1b9eedcf9c85fe247c820dc89c6865c029c1088fb27b41c1a715b0bb611b94e1d625fa0bb8a1294187454": "0x9c7c545141ea2dd84fe5ef7d567ea450f59967e7afa68e5f1ff7f7c46db19627033335", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2d7c748420ef9a4ddbad4b898d4a03a5df86ca83eaea9aace8ba08ee406a2ca470fb8d274a9fb496cac6e8797721c5977": "0x3ef88f51188ea054ff03b902d8706c6d9b1ea56c119b34e0b88e915b5d02da5d035f31", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2d7d29505a6326c67cf801741f043061f4cee1a8fd3bca977c086368843e54330002df861543497ac55e3818e4111cc26": "0xcea3dabe52b2a665b1e19bf8c6913a5d54e06d6413ca3ddbec8f9a22415ec47712416c7068612043656e7461757269204362", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2d7eae4b41a09c76f6187adc728d7c74b3ab6cfff71e91eea05d195a10fc0a03a78667a6ee5a915fcfbb25e90bc258f08": "0x2c5bca9fd4c92b051e35c47617175d8f28aba000ccf921cb24bdf555662f2d41033032", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2d8058cd6e8e400b8b686a6dded37ac508c65e884140b3bfc129cf21cb7423ea9f6a72246c273c3ca4c77a00910f58136": "0x5e97f331813198763da88ad2b1f5deb3f42373a93e8895c43de399aa6255da47054b413035", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2d83f38b37d340f3c33fabe76bdeeac52b0eb1b93d4fb82e4fe4e55b4dd8375b8a09c97596db6bc7e080401f2b88a07e9": "0x88e89854ec5f225c9a3b8889d4b1afc0cf6cf473d4265a96463c08cccf38905b033032", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2d930cac322a8e3609661590a21692ba3ae47a2ee72d479b5ae8c2237b156a6c584d82884c37be50958ea32c1aaef7832": "0x7a895955042cb3fe863f3564e7b30e9130e37b6d905be11c0cf91064de1cd83a0530312d43", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2d9393dc793396a1735689e9acf9fb238fc53b8a54a21149380351cadce380bcd0028cec8145c34fbb67db6176dbcd31c": "0x52e73898bf4601f9c9a7fa052de0cc313b159dd368d458f4cb0341eedcd6d81804763035", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2d9dd9d53e72d0e4a66b17379e58131ce6c736a063c16e476c5d534aedf7e9c95a40f13c95aceb085ef74155d4b37800b": "0x2e62b548856a9ff975d160a0df8219bd36a7807620ac1ae2eeeb34498ba3e4701264656967656e76656b746f722e696f2f32", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2d9f6e3572a83d81ad6cadaa3c87a2d5272f67d9caa91e4c5777b9edbb0f7297d7f294627685c9af7eab3563ef66ffc20": "0xf6b21d624832094b03aa672e016462a020e217cc67b1434785b99114a2b4fa5a04763430", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2da14c430f61b548473feed1d3e41218222caae65e7ded01a955d36299f613aa1636767c9944621bf5eb149290339b97b": "0xc229d8ccc5e5650d17760ce2b7c42bdae5f6afc6e8bab249ec77f3f779ee5a6512393a206e6f64616d61746963732e636f6d", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2da71dd7ef8ca0345c33322399ee10dc612c0e71d2a6032287a5bdb910afd1522f52f26c1d619395f3c8d1d18ed23c12b": "0x12c0e71d326f83f4e6089448e147fdab51b0b7398a7d0cc9a88b0571432e7310033034", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2daca255e05a7d5ca9895f01d07cc29fa7fd69aae09c52bef16685e25b29e22f3d1b43f6469f035a9081033b9a7025c94": "0xc0b881e2db47fb95982cd5c364b87e6cdf5a5c8a336d980156623b53815c597b04423132", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2db06bc4c90988ca9c276efca888bef2f720436c87f73ebfaadd5ff7748bac986ab74277d57e5b946066d922884a5d80d": "0xce5c65fecd7bb733ee636a381fa9dd916f8cca91e2e403c8aea2f7ed32b31d680d424c41434b4d4952524f5231", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2db0bacaee235efe7f0fe598298761c3912c0e71cb40d9d91814a130bf4ee7008a6e83563520ad677eb2034209fa20e55": "0x12c0e71d326f83f4e6089448e147fdab51b0b7398a7d0cc9a88b0571432e7310033236", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2db2588a557075ca073621e5d0b07a30d2c21eb7992f79d2d844f3006382236000c2b1eeb4c8985c6ed6db26734ec2e70": "0xc4516751df2e5803bac3bf9cf7b6d55cf4acbd76f861ad0a2a2b71b7a5ed80540c6b6172757261706f6f6c30", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2db6986be783dc3e2bb83f85d79155aedbb4e1d9efbe50d88f02dc608509ba4ef589646abb8dde69c9398738becc8cd48": "0x008d8404893c7b4b80f397605cc96e61fec3c89676c8c2794a2a7d281d678b1a074d454c4f4459", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2db6d64cfec14a985d9c3e13fd71cf74f29c22701c5675f9a1d0c99c86c5bd43a5c781b5029d080077926cd3d3d17a81f": "0x8c4c81f382ae2c201eed4b0b519f352aa9c0c8593122418b30ac9760844de2fa0234", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2db8cc90b6fcf6061805fc0b2f6d2e0b68a650412c92229bf1a2eb1c0cab9c133d54c5b82cc723b202ee634e925effa6a": "0x5e1eb942e5f591bc1d902fc6a04dd7ecadf5f4916f2597df0505c6c521412c4b0232", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2dbcd9f73ac37913ba3bcf7ff82f93706882b91920f9e4483d2910d72403ecc9522283079ff6770b58be852648e008d44": "0xb4410d33f13c053dca87be657a0ae3cc87655baf43f7efdd454ff74e3a9d8a2f15f09f90b15374616b65204b697474656ef09f90b1", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2dbf093212b4012e7da96293ddc06a4a09b1e47be56602b6fd57d873573f8e1cf67e97ee448fabff165be2cd9b7b6a777": "0xd2cfdfb80cb90a4a5826c98846a367489fd25d3a2561838fa372f39f3f7fb138033032", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2dbf5ab9f73be1b226d58325b74e902f22e91e1aef05cb877f9c862b416d157a840115d43c307290dfba6ac4c4db5dad7": "0xc0b881e2db47fb95982cd5c364b87e6cdf5a5c8a336d980156623b53815c597b033032", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2dc04960fa04dbf91bd6f0f6026404e62faca0437ebd16050e22dffe85c091c5a8e24feb20d488444e9b9e7e7cbc78013": "0x5e1eb942e5f591bc1d902fc6a04dd7ecadf5f4916f2597df0505c6c521412c4b0235", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2dc27428bd38cd5acd3165a17711fa3ba1a765697eb319802107fc3eb312b686bc335cf4456be1c46d6482bba3e1eb038": "0x9c7c545141ea2dd84fe5ef7d567ea450f59967e7afa68e5f1ff7f7c46db19627033631", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2dc2a961efcab146f4743645e32a5c866d06a4dfc33d452ca4fbf37fd660a153b0d87011761701591ed79e5bb87596044": "0xcea3dabe52b2a665b1e19bf8c6913a5d54e06d6413ca3ddbec8f9a22415ec47712416c7068612043656e7461757269204263", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2dc4913f0c56caae531361483b1d0c8ff8c21fb36ae0d9d838e3e635f7d867a4eb44fcedbfc8f3d03f22f342f2a64b38a": "0xa6659e4c3f22c2aa97d54a36e31ab57a617af62bd43ec62ed57077149206927000", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2dc5dfdba2a0510c456ef89f489bbc1a9b04789c005102f21fd271c09568a78047f581710323b5f91b7c2d5743011e128": "0x8c8305ff8478e6309325ebbfb81e8c1883d39e65d2ef84f88e4a428615c4927704313231", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2dc60939087599aebe53acd8e5d4079d33e94cee09a8718b5957b697f388b7300815ae76c15d0ca5c0b0cefc84d5a7d4b": "0x8adc4e19e79b3d2c744f88fa5aca47ef05ccaae141f6435c2d50df824433ae480233", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2dc91ac82f44cabc9de8a2c79d28d6f435e11390e1f7b87f6e2a59603d7979e4e26259c41f011eba0e6f3ed6996e7151d": "0x7a8b217ad8d80016336be124846210559ebf720aecd25ea0d0d11c10f1839e7105f09f9299", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2dcb3dc43edbfd078f6047d712dfef49614b04bcc309f1abd5fae50084923f7d14fc5b9eaf257c0e2c5dafcd83e3cb363": "0x94339db8b404ea216d60433f00ed67b0cdcd9e29d21355615d967161db0cb04c033031", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2dcbb8a73f2966312f90b7a816f27dbddda5484b32d12a09f6c28114f2d9ef1a6cb2088cdd2c5d9be152737bbd165733f": "0x1e6ea78e3190ac2cfde9c0041ea7a0e1f7b89d52f4a58f01f69258150b782466033031", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2dccf206125ed7e98f38e60fa95831a952860f5267cc37b8ac5cce7fc5e1e00aeff5c951ca71a7075e75e5be1136e8e3c": "0x4211b834beac4f35ff92e0dcbb0167f6ae7a0c43b186727d581d3f69f10fea3407484652203032", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2dcfd76fc380cb9ef8907144f5c27f7f5acabeb358e532ad64c9e4e9f5b3a2bef0358e8535cb4e1b8a7727cc24b7be643": "0xfc5d04e7ff3965c8285a2c23aa573117deeed886bbe5e3be0974f1cf0a2ff216073034f09f9a80", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2dcff612df642a86df4851fe810a4e808594e4ff12db88b9c74fecc23b4a9bb35e999a5c9a6424ec47f3e0f5529fb655e": "0x1c6d8b40be9990c19e993d238e6e3613cfc6cbc51979d5fa61dd6ea2593856090239", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2dd00eb692e2e60a5edb02bda27491782c573b977a12a27f38f686571c67e01b848e24b49fb2ce07b8b0f12caf651b6ee": "0xf00168a3d082a8ccf93945b1f173fdaecc1ce76fc09bbde18423640194be7212073031f09f9a80", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2dd3906cb7799120e9220dca4276cc62a6268664daaa26e11b1691bbada389dcefe14898f05214f50027c797d8004f777": "0xbc486ed2f394da6e6b58b130687b48d3d19f756ba6d0655d37bf58ff0f59f97411474f5645524e414e43452050524f5859", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2dd3b705c6ff3a2e644c15c6158e2a27500e31d15b9166c5238cbdfbcab39ccc2fe0173c9419b060f28fbf3f0ea0cf25b": "0x1097c82198eca584e8d9bedca6a5ffc1f1eac3c1fb91d0ef4ef313b842b04c3f0232", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2dd41ba720188814261874148a590262616a025114b9898b0e78a9472f31364689261cfcb35daf692c62f36012706db19": "0x1eb38b0d5178bc680c10a204f81164946a25078c6d3b5f6813cef61c3aef4843117374616b652d636f6e74726f6c6c6572", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2dd66630c8a9f37422bf4f2e1de7853f55627b276d86cb8de65eb9b261907a0134f1eeca33e423eb357ed4cc339e68d1d": "0x9c7c545141ea2dd84fe5ef7d567ea450f59967e7afa68e5f1ff7f7c46db196270236", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2dd7049f241e097e2e14377b9f0d1471fec46a834c9d9bad9de24c9d4c6c85d4f942e2c52134f408e7fef2381bcdf2dc2": "0x983c5a0d1f1e697c1a0f9798bc25543603751b41102d41c3b0e23cbc6e3fdc0b0f566978656c6c6f5f4b534d5f4949", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2dd7649b3c6fd3940e5c3f07a003847b220d879dee526c91e9a590785b4982690fc4a04d41fb7e49c83389e6848132b0d": "0x6883b9f834076b9c1368e7692ec0a01ae97a52c5cdca957b5d31103423cfbe45044b5631", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2dd8a2891c55851c6d5b09185a589a015c40595c253aabacb254a3a476c0ed1b1fdc9368157d2e6d85dc38f5eddddf13f": "0x945e90a1afc83f0c74a3ffe96b40c4ebb5397af04126bc2db23036c043be4a630232", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2dda664af553b017672bf40043090e510bcf4933936ffd18b5b65409bdc003b5f5ad8f9b8e36ae97b1f7b5f0af2803bd8": "0xc0b881e2db47fb95982cd5c364b87e6cdf5a5c8a336d980156623b53815c597b033132", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2de19609c2b633823780967a99f09eece10a89404fc6e546945ce58e433c4e88a17167caf4e763793cd3b048e4b0b5940": "0x78baec43fd49badfce811cbba08b3f0ccf758b5e22f0c4d745452f5dad6eee07105041594f555420424f5420f09fa496", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2de251e40f881f9217c2e38706e3af7ac12c0e71cae4be30aa91dc1e77bf2bde98af86c4d385e9c0868d8af4a50258803": "0x12c0e71d326f83f4e6089448e147fdab51b0b7398a7d0cc9a88b0571432e7310033939", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2de981500a43f4da9e8719948e3d7565e5092144ba4cf9a4997c6dcae1ec2f9b8cd1065ff5d1f97812c5700132036a504": "0x6849627c337067117e864eff154c6125539fa6e4eaa980712e7594cf78447874033031", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2ded01e74365e3760e06036ae1c43d2317c7c8105064a32c52de4d09d9b9dc358756f37ccae41c1ae71178ce302ff5374": "0x749ddc93a65dfec3af27cc7478212cb7d4b0c0357fef35a0163966ab5333b75709487964726f67656e", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2ded4e227d37f3edb020a97a214ae2e0a46105c0b02b08c1a4e094e2bbc42fab06c13cdd155bff92dd844d3bd727f2612": "0xa61514d5cabf81b3f62650806870ad83b2e5059538b846b6dd9963e010566a170c7765623334657665722d32", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2df4f39598dce850aaaf9166114fb0bfaa6359df267482f0eb4004f12f3189cc44d1e70441ecfcbc1a2d5c6c32066003b": "0x8c8305ff8478e6309325ebbfb81e8c1883d39e65d2ef84f88e4a428615c4927704313036", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2df546ef0648729181d0afdc326b51a3c1e25c43583448b07d9e3ff3a2c67c1674ebc968258e42ac4ac000204f6298774": "0x9c7c545141ea2dd84fe5ef7d567ea450f59967e7afa68e5f1ff7f7c46db19627033138", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2dfec92e6b1ceb2162f6b90e6c1e58c1d6c4d3e81cd1909e980648a1d2b7820cc93eafdf0151002f481c0b874502db473": "0xce5c65fecd7bb733ee636a381fa9dd916f8cca91e2e403c8aea2f7ed32b31d680e424c41434b4d4952524f523334", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2e00c261c706fa106c6b2fe14b24e0f857e581640cd7c61c76dc4b85b771ce496d10e52429113f8e7629425ad9787c81c": "0xe659339aaaf44f9871d9a42595bece9cc446cc4dc321dcb30c798332a57808460554555a32", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2e08e603289d76e449e3961b2c9ab6ba4b2fde580d330e81fd2b163a77bf1797f3fd19e98099fec1bbe33217c7f18b77d": "0x366c1d734b33c714b0e0e9f164426e66e3bfa97b917b23e5d3674f4a2074f86f0220", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2e0b3f181c5a9a05fa98a63930a7207a1009ea4dab5c62d5da4b72e17b5ee5932a3098fa728b996bc7ed07f112702d32f": "0x5a7aaed28c23b0b10d2fc6a0a914c93ce965749d67d7f657facb010255e4852e0231", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2e0dc322e86d29e3b50cfb38e35ea5a7f90549dacdddd5bba278515f623f95197c97a6a7793e1e350c7492a9436e4a90d": "0x9c7c545141ea2dd84fe5ef7d567ea450f59967e7afa68e5f1ff7f7c46db19627033737", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2e0e6ac01103ed2c064932499ba7b8198623ad4601b91806226421ebcc2af8a4e60b4292b52e9fa8bc1c57131da504800": "0x9c7c545141ea2dd84fe5ef7d567ea450f59967e7afa68e5f1ff7f7c46db19627033336", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2e0e84d0ccf8d91b0701dc235514ccf4f40ffc76cc196faba27d81c0c8925911628bea264b949bff7a26edc041bfce66a": "0xfef5977196fe3fe5c456a767e6b06013ca62762b282de97040add4ad2c53db61033033", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2e0ed24a7b6ecc44c7eb0d7c0d32ecde38cc54beb3db37569467a12154f037da2f6d859d11b72db7cc8f615c7456bc923": "0xbee287e579da5137412f2c3bd4d5ae4c6a11c4c420e04261157e04842a2ea641085a676162696361", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2e0f6b4abe0f57172867aaec554a3a4177a1b5cf762b0c34865a94bbfb0382ecf0cb030a97e582c4f219c51441ec0b805": "0x6e8a3622a7355ab70892bc48236c461076d5163f55309b7e5d0a459d17c6272a0232", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2e155932771905a9da18ab702614d5a4a46911250513cf4880a89dd8ee3e32cd8363d0f3a064767a4fd19635f2605475e": "0x74c76b2bb6e2e4b16fec1849aefadeae913aed26e72e2101a4dc34abb3e40776036b32", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2e164b11dafd4eb203991a45bdece3cc26cd8d0f1e2161523b73cdde28b857e8d4c281ee0825d88c3658675561a2bda1d": "0xce5c65fecd7bb733ee636a381fa9dd916f8cca91e2e403c8aea2f7ed32b31d680e424c41434b4d4952524f523133", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2e1cbf7f00da6e53c3249ca49ea77889d62832dca982c4883b26bc9eb5f5af530535e7d216400578738ef04ef0871de73": "0x8c8305ff8478e6309325ebbfb81e8c1883d39e65d2ef84f88e4a428615c4927704313530", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2e279f183c3fa7038c796be0ca5053141c0c6960f5ed4ae55f47327fec246d858b57f0d4baafbb54920e0bd47e1dd721e": "0x8adc4e19e79b3d2c744f88fa5aca47ef05ccaae141f6435c2d50df824433ae480236", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2e2e0559b320cef9a9e04c60fd88d7ba088bc16ce9ffb289186e900a2c7bafd486c3ac4c2c612497a5bf14f8aa2dcdb09": "0xa0d32bc7ae5d421990bdb847fc38cade9b388ce8138ab4e4ae957fc7ca59bd2c05e29e9556", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2e2ea2c505786b366b22eda70f336ba33ce52792eba24d1a81f5979865ac647e16fa810d48fa38b2840de291115171e06": "0x76f45a1045fe47a639befe802be7eeea599080222e2f45fba46492039609cc0706426c61636b", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2e2eebedecb077f136805ee88eeef2b7eccba4ab664396955d9309b5ddad39f02b7cbbf76743a9e8969949c3e8a2f5ea4": "0xc85cebb3f21b5e97737a7bbc14d8376a79dbba9c2849a28edae77c776d1e4a080232", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2e3340acd351f61644d02973d5b0808a7c234c72214c38e8cb025a2b0995370d26b4113bec935efcedeca89dd30d21275": "0x56d629a2c80762d412fad9c15d8cc973b463f600895170d43a10ca504b4f454e16205b31365d20542e4d452f4b5553414d415f424f54", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2e35c3408f4c500c4263624ed16c2c6f5545513938fda2f111c89660c78998fe45547148b9c2c0891f28ccadc27313a45": "0x9c7c545141ea2dd84fe5ef7d567ea450f59967e7afa68e5f1ff7f7c46db19627033531", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2e36f6a57fe303b9ac571b4f4e279cdb5600456bf4a3edc3d8ce8fc483ea6b102c620264661f24c3f33b4b41ca8e54450": "0x8e06bfc989509d6d625c085209adb405867bdbe4f167ded7e61ec126c683165d10416c7a796d6f6c6f676973742d3031", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2e38aa8146872f9e132f103cbded76a490ed01c71965026d33ac38506cc0590b2ceceaf2a3cd648e16e0a1d4c10542671": "0x8c8305ff8478e6309325ebbfb81e8c1883d39e65d2ef84f88e4a428615c4927704313437", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2e3f641554b5597f917be4084dae6e274d44824ac8d1edecca67639ca74d208bd2044a10e67c9677e288080191e3fec13": "0x68170716ab7c6735dd0a1012045d9ea33891b5f6596cf97eb217d0962d86a51809706f6c6b61646f74", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2e456d7ddc7cc8e5a24e70581b204c85b2ad8cd53e45f24d5e7c2cacb60dfc3a4dc6260682150104828e62d3a0142c008": "0xf6b21d624832094b03aa672e016462a020e217cc67b1434785b99114a2b4fa5a04763234", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2e4941e79c2fc14646d53947055a43a6a5ef2424315d83ff1d4199b1151f91ad9c0e89306512b02f846f7acf17f00da67": "0x9c7c545141ea2dd84fe5ef7d567ea450f59967e7afa68e5f1ff7f7c46db19627033237", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2e4a9e83f16a2f3f9536fa0267e9daf3212c0e71d210ce61c449fc8f5f3f521209d2906e445239a938303741301d0ef7c": "0x12c0e71d326f83f4e6089448e147fdab51b0b7398a7d0cc9a88b0571432e7310033132", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2e4ba00cd633b8e3fa3f5623f69e02de848636a9fc435413c12d7c7524f6c12110ff15938dff2da4dd92cbc87696c721a": "0x9c7c545141ea2dd84fe5ef7d567ea450f59967e7afa68e5f1ff7f7c46db19627033337", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2e4e966dbda21853ec16ee4d348d8d3fa62be3477b75e8497245a053f1f51f752421fb039f6bfe04a397e85be7e193440": "0xface99d3401cb9b45ee1bc0ec52f4cb35914dc5ad27806230534230eedb8413d0546756e31", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2e4eb707c294c16066f750a1ba2d16fb34a1123e20cbc903262ef39136378a2528eb7382d3b598cd240af1a965f402662": "0x8a65f2773ad69cccedc0a58ef7ebd2d446b882231b4b97044105b2035a8d95460232", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2e50d77c8ee8e0ca85e7832a42a57c8cb989aa1bd13df5939cb65518a399c66800e3b23e792592f94ba7af30597d7fd71": "0xe4269547e0e9a8c162de9215bd45921be44dfb58ec95d2f627990d51890014400231", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2e51ce0489d80aacb5ac38f204dead12c740cfb483a7e7c4d04abc9fc3651beeaea5633eed75f65c0380d424312412357": "0xd8783497b4c06f05dfa6ca91a0502e77ea7ffbc5c33c7142a5d9d1f0322d783b0853504152544132", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2e53ec219e68dec0b35fe17cf965f90a7a6148a5ba31e548196ff678386e2c8792fb3bea265b6c2475e62eab64254946e": "0x18cf1686419c41dc5d3e76d373e3176c32c6d23c755fe1fc357f9c755ffc00190238", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2e54e0729b8b63fc4fa13f0e6fc628f08808652b2296e43e858df65b69d5a3942ba76744dd8d0cf390ecdefc89b3a553b": "0xe4a66ee66171e3238670377bc9ffbd7cb4bda47baf25e6ed80c2070942ee3f721170617468726f636b6e6574776f726b32", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2e5a91996fdb6ad1366a1d9c10f5cbe533cdf73c789cb02811fadd2fc2fad69647e6a22e18ff3b20c03cb9ed07ca0e69e": "0x2c5bca9fd4c92b051e35c47617175d8f28aba000ccf921cb24bdf555662f2d4104303163", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2e5af5fbc22b8e32f770ff1429ca33d395e26900b9067da461527acdd9856b0934eef5f0c099a2acdce01b51f02be2351": "0xce5c65fecd7bb733ee636a381fa9dd916f8cca91e2e403c8aea2f7ed32b31d680e424c41434b4d4952524f523336", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2e5b3c8937ab058e906ccfc60b0908667dc226375dedb131cbc73b5c90ea8d374d5d4b5e75dae7eb6a9a4c215d8e9b0ad": "0x98edcae85e6eef98ba192a51fa0efd89aac0541fa264d46adc9d8f29d3e2104704303138", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2e5b64404ab43ee7cbcbe85ff6f5d5b65ec496735eca64ceabe80e911ddbad8c072ac5b69d3d88ed8dada02a9cf5c66c8": "0x4c042cc1451781f79ff3bc34cacd5329b21591b2b2d82ad57426a5079ad1c45508f09f8eafefb88f", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2e5e92887f1972bd9979c363bd2d8653ad21bad21a85a2c91d823216610c964d9fef7dddff9f1864b2a7b4a8e667c1f53": "0x3284bc8ce3083b62e671d1c5bd61db5b3fea95a77967341ca8834a69cffcfd5f0231", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2e623a56518f78c9028775cc55f65c190ec194255613dc072122c8330dc7c18e15b12e5eb3093a442224e91e50cba7d3d": "0xc4516751df2e5803bac3bf9cf7b6d55cf4acbd76f861ad0a2a2b71b7a5ed805406f09f988839", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2e63b7a685f63670a81a262fcfbd9fbd2eaa00abd5e6449dd46d8882c6024f26cb5247d26becbfbb4f57314d342b96a65": "0x9c7c545141ea2dd84fe5ef7d567ea450f59967e7afa68e5f1ff7f7c46db19627033734", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2e658ef02e990b8c30f8da6914cbd955f0119766bce9e7ccb7adf4b74870a29b352995478848ad500f46166c797f1c326": "0x083f39607241c8ebb62919ab2ed816cb6b20c7d0abad78a92570030d2f96c63c033031", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2e65b73e2c0faf462b8528f4a507cc9f8148abf367d1fcc88ac026490727eccbeb507e35714b327c4a3dbe404622184b2": "0x1a8ab26aba64d6176b6aa462a2a7ef6252ca1063cf978dcb6f6c64fec81e7861074534592d3032", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2e65b7dbc9946c336efe1a3714adc5c139068a88ce95e5c34122578c16d46855386229be241a7e0656ef469a03db4ee19": "0x12d49078cd721faa2f041d0cf96e0d8194561fdcb4ced457270e52f209e76c0f0b37363666373436353732", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2e6641af3b6641795527ce31eeed557dd12c0e71d46088235059834f57282e18f93197b164a04be4082b6dfd88d86f531": "0x12c0e71d326f83f4e6089448e147fdab51b0b7398a7d0cc9a88b0571432e7310033031", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2e748d98bf8b780c7f223b13fb6222c5612c0e71cbe21aa863d666ff694ca4aa3a1f0e89a9e75ffcdb6c629fa1d006460": "0x12c0e71d326f83f4e6089448e147fdab51b0b7398a7d0cc9a88b0571432e7310033937", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2e7555fb4759ac62feda8f76622333aa7922988e0c062661a2af3df12782ee38f6df030390d1874d113bb8a53c165f147": "0x269fa27098d88ecb1640185c91860fb62d92ae9a6ab7713c79485bae49862b39033032", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2e7589bc127b541c9356d09774bf0653a2c34b3c3d2a9e4c126b3e6152b8ceeeb75c43d7530aa56ca6f41de5a5e76a270": "0xce5c65fecd7bb733ee636a381fa9dd916f8cca91e2e403c8aea2f7ed32b31d680e424c41434b4d4952524f523438", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2e76b9a352f58af1eff362b8764392433187f07072543de8fe520037e115acbdb9b9ab6a321be237e39e67ca4ee979749": "0x12bf9efdc9e4e25b4dd72c560029152b6546ba2fb62eca400d7edee7e5f36b5a0231", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2e78077f817c4c582219bdfe28f1e7d7e2e8036bee650826ea445368d4643b0ad2341924bb357c8ee1596fd1235ecf326": "0xf6b21d624832094b03aa672e016462a020e217cc67b1434785b99114a2b4fa5a04763235", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2e789267e130c5ec1992e7b2300146bdbccc10f47daf388814d58209cad72e4c07dd9131ffb7b2b909d39746577a97178": "0x8c8305ff8478e6309325ebbfb81e8c1883d39e65d2ef84f88e4a428615c4927704313233", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2e79245080d82d693b3d098f207b3efafd5febe9f9f424e1a509cadb2ccd2f502fa1e9b577c03bfcdf74f7e6abe6f692c": "0x02b47d21483aa953be67636583cb184f55d575e0f71ec75f45383a786324a64b055a524831", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2e794c096ddccbd0c284049c16597e94a88c83f9b6b21778914870c7fd18ce9b3b44831ca8706611d6b2fec736a5ecc4e": "0x5cce1eed57740222d643b9c92a594bec58f9b9968bfd4d63d495a7fe5237ab1e094849524953482032", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2e83fd59e7b41f06d890f542016d8d5f75ad5faadcc4848cc8acadadf39c4a9893e13e8993e270364eba8ce53b8374c6f": "0xd4e6d6256f56677bcdbc0543f1a2c40aa82497b33af1748fc10113b1e2a1b46011f09f8d80204b534d20303920f09f8d80", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2e84ddd98e3af983e752fcd3aee367351fe3aa3a8b8e0e17a72626db79dd999dd5e9cecb8e0f265391e5daae3ec229d3c": "0x4eed7cf3f4f6560d58db4eb78bd24b655bbd1d7a5c6b454e77c8dc5e2721a54d154156454e5441444f5220434f4e54524f4c4c4552", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2e855f21c0bc68c9fd5e477dadbd5b2eab22f3abb5bafd42556aaae871a79acac48e9b874703cedb7f8f5ce219860ae08": "0x8c8305ff8478e6309325ebbfb81e8c1883d39e65d2ef84f88e4a428615c4927704313034", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2e8745646068bdb0edac7096adc4803d597a214d9d7e4d9756f50d6b43a18a8ee671cb1512b46f2c2c8c1309694dc75bf": "0x548dcb6c3aabe041e7f7ee65af37818dc7ff1ff1a4300008100322c39e9c610b06415341524f", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2e8ac56067099b665e2ce074b028d38a586d6e47051058a73623a0abe221e2cdf86a362a3da910618be17cbe3629eaf31": "0xfc5d04e7ff3965c8285a2c23aa573117deeed886bbe5e3be0974f1cf0a2ff216064561736f6e", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2e8f202e282deaeb09e361328a01c8e1cbd65fafff9dc200e3945e786ca92ba36a9aa333b09bb500b632e8827f8f7ab38": "0xa49deb88afa394b7eb478483a65a8c8f060b7de319dc6f65776a84d9e8f40e7e094b534d2056414c32", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2e8f875b461cf418f5973a82da0aac2212f9c09c8a70b63d73be60dfe13947a17839970667250b900c8560ed4d042841d": "0xac33b989d0b4dd35d2fb8af4cd04cc5a3831e59023cb884044f5cda0541f1064033032", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2e958ff3b911d721acbddcf612e892996b89b1a8c5532845c171dcfc78c4bd5c42c634e7d6548d6646c83fdc25bd4737b": "0xce5c65fecd7bb733ee636a381fa9dd916f8cca91e2e403c8aea2f7ed32b31d680e424c41434b4d4952524f523538", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2e96d7ea11d81f95d0428a125ac69d5d6225ad9907fd7a3f7f3633f2251c3b390b338385358f1753ce35bd27328c7fdd1": "0x68f6e4f77f043dfcb9fe88519996ee25ccae674ccda259bc49efec6b6eeb9607033031", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2e96ecd9a7d9777c34414149982f444e3801df817f435be03321e6a77b0fab3183b9716117accc0f3db95c9f6f9434954": "0x9a2cb674ea2f4866664769a1663fd6aa321d9cfb89b67c402c881891700c0f57104d757272617920526f746862617264", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2e9b53625b2ec22da0d66ee96aed6c8a9fc036538dd0a7335685f0b7f62f6745658ff16bc2d61a8830e70dad3e1749355": "0x9c7c545141ea2dd84fe5ef7d567ea450f59967e7afa68e5f1ff7f7c46db19627033837", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2e9c29fa4d8f011d919e8b0aa24ca376f687a846146ca3cae0d51993c0e186d6026b2134ca05e213562c0141a85b4ef5c": "0x9c7c545141ea2dd84fe5ef7d567ea450f59967e7afa68e5f1ff7f7c46db19627033430", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2e9dba064d1e0741d4b5e37a05f52e1c046a4204de252ad6bb8587604684eb6b0d8d7c5f9f8e7ca0132bcdc6d53131e47": "0x04c73bb4b37fd89e159ea8dda26c4021a4af572826ad6397d8fa9942c18b3568064354524c31", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2e9f3f3edd998aec1842b1673a32cb65d16c4a4dfdd6c04572aa9c3fbbce888451c65cb1a1c96f611aa638e609cb6f609": "0x9c7c545141ea2dd84fe5ef7d567ea450f59967e7afa68e5f1ff7f7c46db19627033532", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2ea29bc2f13063ab1c9c07534875dbc8d40619a9305b0571ee5a5666073612190b2035be70b6846a2f16c94e29908d389": "0xf00168a3d082a8ccf93945b1f173fdaecc1ce76fc09bbde18423640194be7212083230f09f9a8020", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2ea3cedd2f091ff1f1d5ddefad7fe2d8fac11ec66576b8d0a1c924596e74f3b45c61c7408e1680e16b4e365ddb4b93f56": "0x729f8acbb64cb60b5edb62beadc9ac05430ede0086e29800ee32d106befc78250231", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2eaa90e48b9a7dd48967a015150804612d85561d4ee89c473f4220a4a5ca0c8eaeb01fe8d0740aed291ad796d4b2da175": "0xb08b555a5a3b2725e01ba15eb40aa32dc5b781532854b797808ed45e752b047c0231", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2eaab2b4e0025425dd7049c8429770856c63d0c9d2b2f1b51dee3c65bb2714871c2913cf646efe3c775d5cfefd4e1bd89": "0x16eaf9666bd95a04bc6ed619c30a4809a43fd7265e414284c11b27b8c666fd23034b33", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2eab688ffc102f64125630a3c861323e9048bc4da5e4289eeb52244056c70c535f165d37ad921c08b9d00466a1fbfe442": "0x56d629a2c80762d412fad9c15d8cc973b463f600895170d43a10ca504b4f454e16205b31315d20542e4d452f4b5553414d415f424f54", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2eacc1ece31019fbf6408ccea0dfa084d12c0e71d25d4ac0ea242b6e44fc9625e1a4dcfe17e6cf9dfdc0bb233ec589556": "0x12c0e71d326f83f4e6089448e147fdab51b0b7398a7d0cc9a88b0571432e7310033136", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2eaf55c9b1b5c07116f73c13edcaa29869eb6835f83b4313045b2a156d5af104e172dc687b2bd07554ff3699748c41050": "0x48ca001326b583070e370be3bc6680d09cad47649584a5c992bd388c693b9a54033133", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2eafc1348fe1623ea22d24055452df792d2c2f040d9b3546eee26f30efecb97e72fdaddea5d4999845b37742841e95f57": "0x240cc50e90684f175ebef583b904fbc0b9aef4b38aaafd53e6436ad3e70ba3660b496e2074686520736b79", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2eb3072732122ad64b038c799d470f71c4409776e3d248cea53e8d6fce41bc1795b83793fe794119a63b82a7e837e9f59": "0xe683743954d0cb555a54ab21cfb8161f74e689a051d1ac1dbbb94df70be3d81e04474f56", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2eb5b956e59f0279c2a89a00f1a78eea9bad66ea053eac162ae6fa88c672a16dc18d932399e7159d0e2ef25c62189e637": "0x3d6d2d20735ec00c7753d3e6071ad1e2280288a98d7d89c2a2b7fe08bf6d05bd0641726a616e", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2ec26a61f6e5d8383858d0a1eafaf930a9e745f85a1a8ed92e237063f3ba463c198d7744b7698e0e0a9a12c5966d798c8": "0x88e89854ec5f225c9a3b8889d4b1afc0cf6cf473d4265a96463c08cccf38905b033031", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2ec4fe475d73cbb6bd5e7e5afecb01039c0266f91841edb77e30346c6da3975b5c3ffce4a2b1ddeb696527bcc0279f3ce": "0xcca2a0719fad006090aad6536ca8b7d8c527589be01b0012564dbdd36d9a492305f09f8c9a", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2eca8cbe6e1a53559e1f36828c7644781f87441058c9c1d89f27cd68a74ced729f5393936f7c041de6732df7217d17cfc": "0x548dcb6c3aabe041e7f7ee65af37818dc7ff1ff1a4300008100322c39e9c610b074e504f4f4c53", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2eca8e087b9c31caf6b65683abd4243337cca5de8c58ec8fd1a269c3e51acf6ad45a8b9b32e4a65a4d4c481c5c449d826": "0x2a807fc9b3748a0d6b964bff11360e00040fb5fc569a9595532f935286a45f47037632", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2ecb59c824a063fa221530b13ea4793e99a9868ff02ab61c9603e98eaf9560a864870596f58a7144203636bef6d04e269": "0x8c8305ff8478e6309325ebbfb81e8c1883d39e65d2ef84f88e4a428615c4927704313131", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2ed7626002652026efc7173f5149ce3a5aec16460ec51be05e01406f39af4e8adc9d400e511cac7aebc10c31d42540f46": "0x9c7c545141ea2dd84fe5ef7d567ea450f59967e7afa68e5f1ff7f7c46db196270238", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2ed845b33e774e62f877fb9bec62ac9085b485a5d58748bfe83392a1ade902a02c95084c00df2070dc8f32f13ad499e1f": "0x0c841e6aea307d8704d5b7b7b71afad58548ce47dce090e25d01b84925e5c48d0f43686f636f6c6174652043616b65", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2edbd4867a11999b712c3889ac4cf711276ad7b338e915c739fa6055381d937bd4541d12ca755533161da8611aceca14f": "0xd8876695e0680719107b9ccb595ad5d8bfdc4ccc8e8e4656091fcfe652c0f1550a564c4144494d495232", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2edfa6613fca1f3a39cb95daf9098547038cd946bf9de9d576d29db5fc442e5078a03f73b67ba76d8717634b7be4c5a23": "0x8c33b686a457b74f9b1a61b4446404e522d122064d6713ffacee88bfa9a158610f466f726b6c6573734e6174696f6e", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2ee06f0566e3a2fcac576e9bf84a239110a750504f5da1835d98bf849ebc018742d544c86edbcab2525a8acc2178fed59": "0x4e908afcf0fb6b394bd1a043bc8b226fac33b4742731b9cde5d324f450eb3006054b563031", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2ee1bd3f0eb1dc3033e9f4c7f4c9b3e29cadcba686c8bd7b8579cacb9e1233fee5eba81db5e7c25328b724198bc499b2b": "0x0277ce02b2ac78ceeb9ae4fa0a595005489bf3f5f77898415e32a3e9504a53141e546578617320426c6f636b636861696e20436f6e74726f6c6c65722032", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2ee51c0467906f0399b711fe5128cb7ee12c0e71ccf0639294d8ecb643d6dad93d9660836463f91d1b66292fd9b1ab05f": "0x12c0e71d326f83f4e6089448e147fdab51b0b7398a7d0cc9a88b0571432e7310033836", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2ee5aa3cff49e0a798d42c3a4edc2b45bf826721deb8c5d5f99d57fab56da2e28286fb7ad92f148b05d1aa353fea2b26a": "0x86b7409a11700afb027924cb40fa43889d98709ea35319d48fea85dd35004e6405f09f94a5", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2eecadf8dfe8dba8d2e7c5557ebdeea0b96043b3a00f3e936328165ca3f780b594dc2ff0d9e72659a9e13ad74c3bdad4b": "0x4ac4eaed36e5c54f045b46cb54f533b2d3949c0ca7137e89ef03ee3f56f8155f033031", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2ef2e11f785c26f6ded26c3139eac5be7506014a02fa72b89b1b4ce899d40e369b2ab4d06fc1ead4663c856bae3d9db60": "0x56923fcb0c362b333a2833175025883860f6b93996233319503a4ac478b7b1150b494e4449474f204f4e45", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2ef60985c2bf366da5782cb9287150873964d882bb6127e75f8c02efdefbf052be0c010256c41d832e8c81fae632dec75": "0x76e282d7a7eef593fe7a9a8c5d08a21f134e8858e1b1753bf347057c4db9b23404303336", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2ef72750a5dbb1f175ecf94f7254cf8da53b9577bbf862a61bfd4c7302c3a43bd26a9b50370e3cb6586c8e267c1b87180": "0x58f26dd10efac24a7fd1813d6aa72a8e60bee976f7da28e492ad033fc18223150230", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2eff63fd37d1b282f7824ce8d27c457b5ea4565b84bbc645ba42d3ce16887c42062314fe6aca7ab36a1fd942d7f31c76d": "0xc088a8a35f9a31008c7ac0d4103078bb14b3d50213e4b92bf03ea98c081f173c04303036", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2f008e8cb26020bde50d4f0b553b1a67093bd14a518853f72f3deb5357ee12fdd6e77151580b082bd468bca1358250d2e": "0x96f7daa1a00790f8b168d3db7f0175e5f8dfd3430dc7edb4c5b807bce2b9d93a076b75732d3031", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2f0094ef8d1df177a8d33417bd36a38e93e4f57a212fd4403b083d956909c66b8e492e24c48095c3681a5a28208803744": "0x5270ec35ba01254d8bff046a1a58f16d3ae615c235efd6e99a35f233b2d9df2c0bf09f908b205748414c45", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2f02caa348f4c67075fec728c3413c5677afc36665eb89509814350a32bc136f095dc1c9224dac890c0112b5f4b53ac6c": "0xf6b21d624832094b03aa672e016462a020e217cc67b1434785b99114a2b4fa5a04763334", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2f0550d244d630c7356199c24d2f56fe812c0e71d10a91f1a202191134bc06e790e98829eb7d76881e3c8b42dbe8a6d41": "0x12c0e71d326f83f4e6089448e147fdab51b0b7398a7d0cc9a88b0571432e7310033131", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2f09d6c2a2016877c4728ec370a211b47feb86644e89b8c9daf871b44f7111264cc15bfd8efa38a255124412b9bcc5869": "0xce5c65fecd7bb733ee636a381fa9dd916f8cca91e2e403c8aea2f7ed32b31d680d424c41434b4d4952524f5238", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2f0bf2c785c3e07b3e53a9fce2530b727deb6ff39e56549c7a265ac798934d66b541c41c2e2212c34bd76b29635b4cd23": "0xfef5977196fe3fe5c456a767e6b06013ca62762b282de97040add4ad2c53db610554697073", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2f10c646f0d99a97e06f60f9e098d413d831b9437615fae78c29e32df5b9ca228b4e9b4b31eccc8c090834cf6a85c8e29": "0x32068fb3b800c5df40df16619761b3418e40d9455784b6a293d2425e35ef2c27065354415348", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2f11a108af7a78573dd904944eb3de78c3e586d68dad3baa2426853204a502f7476c280a7cc3bcc4f25bc4bfa3e121601": "0xa43b2797bd4dd454d7fb0870a2a4edd62b39eea0801f6baaf09b05c8634b5a250233", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2f13d95baae246a1e8d55a2507dfe207e88624098732487bb9f92045e3d405bd1b7f9432dbd705c3ba58c5e86d1353c69": "0x8c20d46f86242eea89c400d5c478207e05c76bbab29a748af8aac90d627e1a010243", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2f1c9ce061a86af07f6a818c8734f14fed8c68f5ee90ef5d4f3a2b0d3e827b6b52d6d42c66f0789546e7672128891df61": "0x8c8305ff8478e6309325ebbfb81e8c1883d39e65d2ef84f88e4a428615c4927704313236", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2f1fb7eb39a9d8c38c4afdc44ae906bb73481012d5c43235dd891fea6f46c4745b4c6f9ae37e756f7da67f6af35831a23": "0x3ecdb909643a31da23e3dec041ef8920632ec16fc5157297084eda7515badf68033031", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2f237d4da327376ccc05b307e2369972b26053f965308328e14c097fbfc2b09b6b97256bd6a14ca1459ff9c1e8dec3556": "0xce5c65fecd7bb733ee636a381fa9dd916f8cca91e2e403c8aea2f7ed32b31d680e424c41434b4d4952524f523239", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2f23ced154c515cc7381ba21c5a71a2ff54416d87ef2183c6d1c383b29dd10f002272468fc70cdbddd42b5093425e5422": "0xc0b881e2db47fb95982cd5c364b87e6cdf5a5c8a336d980156623b53815c597b033230", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2f23f3b7febcdb548f3145cde9c1a0e9112c0e71d364ec914b6b740ad7c055dbd9a15aa2cdf4f6b3349970e15b6b73e01": "0x12c0e71d326f83f4e6089448e147fdab51b0b7398a7d0cc9a88b0571432e7310033137", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2f292f07891bc9729fb879d675866f7f98e4ac154f73a0576603db7786e98d6a1db1e72e3a2b32d2540828395dbd3f7d7": "0x2ca8e96b721f074e95a3f7d994c370dab688fc85134de7e2e7d4589d0a306c51033031", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2f29930ae86e28dadad8b3f03c93d00962d14410d4bb33f09014a028cdbb9d2c2f00e7d5021748ac859c5dc11cc277a6f": "0x02b47d21483aa953be67636583cb184f55d575e0f71ec75f45383a786324a64b0548454c31", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2f2b50261383f32267afd11d1441702149a3bd9c292ba18b98cdfeddc8e45fc0a4eb962baa86c5d839ff3e433de19944a": "0x8adc4e19e79b3d2c744f88fa5aca47ef05ccaae141f6435c2d50df824433ae480239", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2f2cc70fbe35d96dcb882f5452b71816412c0e71c712fc750ea7987ebc3adbf181c53f54133d3378fa5d7268bace38a05": "0x12c0e71d326f83f4e6089448e147fdab51b0b7398a7d0cc9a88b0571432e7310033336", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2f2ccf65413283ccc5fe7be230377dff776497a6036a1ef7d02ede96d44f39094a5fd50e69d524990946cf5e6e6f1da2c": "0x22a58635dd1a211d33750333282985df00d84e87b160293d6b39e89ea4bc7d670b414e4f5645524e4f4445", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2f2cfff95d1e91cb6647ce16c34f693f8e4f351785e2ba01d8ae8c408b0112af93577eaf7487d1ad4cfb54285c88dbf1b": "0x9642d0db9f3b301b44df74b63b0b930011e3f52154c5ca24b4dc67b3c7322f150573756233", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2f39cf3feea5583006ba1636f26099b471adfba8c2b21414451ce19bd06d2e9ab7541214eb3285ae73da678a755432237": "0xdcf2917d37c64e3d60416e47b5185b4d6c3965ca531ecbe29e1d2cf759f5f871033031", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2f3c2ea1f45b4f32b0ef74fc35e1e741a847074f1fb351eaa06337823c68f2a9fb28c98db976bc5cc16867e4b84bc1060": "0x9e826b5434525d00c118f3f6b0a29b7f432be7bbd18659d472c5f07298e769490a7068696c6f74696d6f", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2f3c8018203bea6b4195eddc135d90047164f70bb86b671d46c1748f38329f50db8fc5461a4ba4dbbfaca7a47bd063962": "0xfe6c31fcff28694469c3d4c1681270bdacf6edf7ec39bda6c68cf25738268b79033032", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2f3db22b473c2869c1572520aa5e1e3f4dab0125fdf270b1af39164693d9bb3251d63b78742a99693632359e0dc6c4882": "0x36b5dcb29928d8a462f493e0250e895158fc4fc54eb5d00a2a6701fe36a4283d0d5069636f6e62656c6c6f2032", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2f3e73875249d17f518bc605addbf0c8212c0e71cd7c05aaf2bd4ceaaeddad56e206f8b7be033b915ca7e8391aaa56a0e": "0x12c0e71d326f83f4e6089448e147fdab51b0b7398a7d0cc9a88b0571432e7310033330", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2f3ef16462d5d6cf08146deeaad6c6a1558b16e3eabd2cb50029bde70c7a7ec0123d1e710bbf45322f50be3f21ebf8747": "0xe295650fdd71d7046633b1fafd0881a3207719c573f17725fccddf854a8b562805776f726b", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2f3f6ab2f877ec353024b0d4a581ec9b69e66677d3f5f4ac376d14bf73bc819845156f1f25ce9e6930fd096741276ed67": "0x1a95c3968b83520b8e43f82edb0f050b1ce7281873a93bf9c0798efd50f5c41a0654616e6973", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2f45a148fa03b9a5ce97e26b45105f0e79801bdf93fc1d4b0186e1295d517b03a5749b90c94a5468d74331a6ff529a953": "0xd60cf655685824e9966b0a10c01dc8b17b37e24944fdd760e4dd73ff1dd4ac1404626973", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2f471887a1bcebb9ed9456d6694672c5412c0e71c92f12577507a7ceef4da940099fd984e976858d6d4c6826ff76e2544": "0x12c0e71d326f83f4e6089448e147fdab51b0b7398a7d0cc9a88b0571432e7310033333", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2f4b2b50539776257271de63e3d55aeeee8b27a414bbf2ca10db6202c922e1d33359b65c8d4967fc76f926d93f54dd916": "0x5e1eb942e5f591bc1d902fc6a04dd7ecadf5f4916f2597df0505c6c521412c4b0237", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2f4d460a7cf7347eecf1ea2331620d3561024e48276b150fbff7c44baddfce92ba5d90057d518d3b29bcfaa421c13ab7b": "0xe4e00e63c3647fc8c0a3d1b163ac988b6f0a7c3d05a01e209d4adef8e285037b0942696b6572346231", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2f50b6a6dd76109679dbe380f073a1fba09f7f25aee06632399bd9de5e4a311cfbd1846ecc34f8abc3bb8118a45c98a2e": "0x0a439f839504ef07c5cf8daf62beb17546e808ed1026c8a683be8207245f300f0b5374616b696e672d3031", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2f50cca20f59770811debd1119a649b719ca08cd9b7fdd71d23d3a07906fac5a51b77c703f290adb2b5099b4334407913": "0x4a003aeae28534daddcc861d7d3e91b576683544217044cefcf4803ced1fbc690232", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2f54df87c5f1f17edf050018f5d0f6e3d72ae12a9ae7729206f6988826c71f0f3076971462d1ac94efff198392464a657": "0x48ca001326b583070e370be3bc6680d09cad47649584a5c992bd388c693b9a54033032", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2f563f9de25dcf55912a6f06a528d5fa774fb773cd20d9adffcfc49a58d0ed20bf5baf645cd37aaaf65408f56ffe22116": "0x4eed7cf3f4f6560d58db4eb78bd24b655bbd1d7a5c6b454e77c8dc5e2721a54d164d55524349454c41474f20434f4e54524f4c4c4552", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2f58d058c15c34128c960f33402556779649bd677aa43958fdeedca2f9159ce5de8d5a278c08e73c4ab9a713a24d0d47f": "0x56d629a2c80762d412fad9c15d8cc973b463f600895170d43a10ca504b4f454e15205b365d20542e4d452f4b5553414d415f424f54", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2f5d4af8d3aac1dc12cb3b4e57ea6d654280774e8e4e6118ffded6250a1b6b1a50285b5a61cf184e19a2bc8e8de880858": "0x8c8305ff8478e6309325ebbfb81e8c1883d39e65d2ef84f88e4a428615c4927704313138", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2f5ee7dd57b2155ec96f49d1c5d1dde5842091485cb911996df13bf18b2ced631569a74c5e43790f285fa4ec64142d503": "0x08a23d4b915d29be5d2aa20f36649e004c6ee8df393064edad697934281bd51f0531426f74", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2f61a062242c9ec1639214545821d86e18c6d54d22c18c9072a83594d805c1a6c4a06940528eac4c3cd44359dcf9aee4a": "0xd82318297ca7af51ac2546ea6bd24acca272e1627db952e2ca35df527a3cf2570232", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2f69833f1ae9dbbb00dae666f139773905009e192ec169788c9c1f0202fe7c2bc79405ff8b6e1d1ac78fd6152006e606d": "0x5270ec35ba01254d8bff046a1a58f16d3ae615c235efd6e99a35f233b2d9df2c08e29b93434f5245", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2f69e7ce6dbcee801e749a85956c602a240e877da5560adb4bb476e067659f4446675875a5e49cac2d3a4ad207adf450a": "0x8adc4e19e79b3d2c744f88fa5aca47ef05ccaae141f6435c2d50df824433ae480230", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2f6dec04f83b8e2ffe18956dcfe64f2db1a232a8dc0c50a8faa639ed22d11410c00f5b812bd14ffa6f3f554d8edad4172": "0x7c7d2fe83c4af79c49136f0f8c5f1a00cd8d0aa91c94fe74d0145cb96d688f66032334", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2f6f510eadad5c8c77ed6d38c1698e558568538b172c522826347235dd841d08c6512bbddf1fcf91a10c9bb9542b75ca3": "0xc2a82d0740d343bbcf853665019f2afe81ddeb884f76dbb5c74533610f72a7321b32202d20747769747465722e636f6d2f706f6c6b616c75636b79", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2f70d1ff9a047126addaba5bc180f653e0cb8ca7ceac36a246a8295a56068d2b532fa2c61affbb34bc5a80777d91f1805": "0x9c7c545141ea2dd84fe5ef7d567ea450f59967e7afa68e5f1ff7f7c46db19627033635", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2f72913cfcdc0d34c9abb281c5ac246c3ea08268d10b6dd05b9db75c7b7abc2b95e9b24d47f7b2a6147a56dcc745a0b4f": "0x48ca001326b583070e370be3bc6680d09cad47649584a5c992bd388c693b9a54033034", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2f7802b4b06fccbf0ccd56f8111fff98a24177bf6f8ef353988a83494a9fd6a8ed1f89ce97daba4d8448c48035b646960": "0x78baec43fd49badfce811cbba08b3f0ccf758b5e22f0c4d745452f5dad6eee07033033", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2f789f222c0c713b56e093e473a22562d12c0e71d466c86c2834663f4edc4bf268a2746f02da7a7334344582db793062b": "0x12c0e71d326f83f4e6089448e147fdab51b0b7398a7d0cc9a88b0571432e7310033032", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2f7a6e9656603ab873c94abe3d3da7ffc68851551f073cdbb09116a1e5b1500042b1376b440f967b0ff961df638fae867": "0x9c7c545141ea2dd84fe5ef7d567ea450f59967e7afa68e5f1ff7f7c46db19627033236", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2f7ce288025bd4a563fa7c6828507dff3d8ccc709448e61b19bc01bbe3be7d7e74c2303883ac6d06c19393f9c1140840f": "0x78baec43fd49badfce811cbba08b3f0ccf758b5e22f0c4d745452f5dad6eee0705504f4f4c", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2f7cf5ede6a33615ed553efc37660a1969e98a7c353052e4ff27d50ee1dea0f7379ccdbdaad823c457b755413243e967f": "0xce5c65fecd7bb733ee636a381fa9dd916f8cca91e2e403c8aea2f7ed32b31d680d424c41434b4d4952524f5239", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2f7d6185d74423b52fb1014da109a710f93ec952a9328c2f39b697aa00f57f01c289423ac2068f506ce2165be10f1ec45": "0xec7afe6fbfc9947fd177ed118016e403dbc14803a0432bfaf0337e3bbc3c820b04303031", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2f7e69d9b9b0db08ad3941a583e280b29b00533dede137ae3424e18ed36871d41e440bdf62952275f43c899e1837e3161": "0x8c8305ff8478e6309325ebbfb81e8c1883d39e65d2ef84f88e4a428615c4927704313434", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2f881b72e5735e0005018dd4da333c3d8eef86cb3454d5d2d17aceed4598209af5d3ec6a09cacc00bc88d86bba7f34645": "0x243612f0fc6c935d9ee0cbe21c453a83f58a9427054ccdc74966890ca57ca7190232", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2f8eacb151d14f713c6edc17cd546d26a12c0e71c648c0ea092b2481ad9657956548a531fa3a89a140d3d8f9359fce54b": "0x12c0e71d326f83f4e6089448e147fdab51b0b7398a7d0cc9a88b0571432e7310033936", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2f92cf23fd7dffa81b32c1b18edcb1307de89b93418a2be5e997eebd4b815754518fc3b7db32b2c31bf97c8297f8ff752": "0xf6b21d624832094b03aa672e016462a020e217cc67b1434785b99114a2b4fa5a04763038", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2f9361e34a3820d9663762bf72d872f77c0ffc934cf4bfe0fd0cbb0153cc1f8c1f784ae59bc53da0e1833056c63b157a2": "0x4284fa7c290fb6052b9437610cfb2e19b3b37081fc72140e444d5b57ca01924d033032", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2f963679a580318063a9fcdd9ffcfeb131cc49a4b3adb82193695b2dc7507d28e72567060373e1e82206a0430005b694a": "0x56d629a2c80762d412fad9c15d8cc973b463f600895170d43a10ca504b4f454e16205b31305d20542e4d452f4b5553414d415f424f54", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2f97972cd70c90172b59ac8f8bcc1956f12c0e71c6c063c135438f8997461cbe25e61d7569fe4c3f9f07db032f75a581c": "0x12c0e71d326f83f4e6089448e147fdab51b0b7398a7d0cc9a88b0571432e7310033434", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2f9895a23189b4bd5c7dc15f4354c2cb55c7c97a0165263b9287982692ec2845cdf8ea293108d3cf51f598b6e98da1f7d": "0xce5c65fecd7bb733ee636a381fa9dd916f8cca91e2e403c8aea2f7ed32b31d680e424c41434b4d4952524f523535", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2fa174cfa8ec743e7fa1821b8f1c83320837cd9bff26ac28b84a814643ab00556d90e873a921633bab990cc75b5a06dea": "0xf00168a3d082a8ccf93945b1f173fdaecc1ce76fc09bbde18423640194be7212083135f09f9a8020", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2fa18806f4b64c61f196b040fb75212ad2ec6d11607a14dd26f32576e47831719d548c856ce4c188091790cd93ba82606": "0xdc86d7e1dba377a90f087a942c0c2777851b447a16af68cfac09c2e58ecf7e1d0242", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2fa43c77ec1513d34e343507763368d2c5a6e6d7f1f5af2300c1b721cde7f08238ffef321bcb45cce819b00557fdedb00": "0x5a6e6d7f1f5af2300c1b721cde7f08238ffef321bcb45cce819b00557fdedb00033031", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2fb5e4582a7d7f848ef547ef35b4002c612c0e71cc202669b8b8f008fd88fc91048ddec2434e536b37adc066ae2d1653e": "0x12c0e71d326f83f4e6089448e147fdab51b0b7398a7d0cc9a88b0571432e7310033238", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2fb6259e402d8e96835c54de5060ee57a6e5bea81107431deda89d3b05e7e1656354c48d0a5cb767851726ed359371f7d": "0xce5c65fecd7bb733ee636a381fa9dd916f8cca91e2e403c8aea2f7ed32b31d680e424c41434b4d4952524f523131", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2fb80f286c0d81ae630a5066a97174c07cd5f012106aaea7652374847b9658c8c300f0f0b26e484e99f7c1e3d32d83a10": "0x3a731ac0ae7375a2cce5b504484d91f1c49923b3425072e36e12b0afd5f2a8570530303130", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2fb840883000e9e9bb33e817326b3704af4642a032339376577e3ff7f6d55a53fb6519c5a20633e30bea2bd4d2eac3a05": "0x9c7c545141ea2dd84fe5ef7d567ea450f59967e7afa68e5f1ff7f7c46db19627033434", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2fb8fda93c177343af72612720c0a4d885a3b1634ed187e0ff740fa52e33f2748d0e88a19cec4e5c185cb00408a89b605": "0xce5c65fecd7bb733ee636a381fa9dd916f8cca91e2e403c8aea2f7ed32b31d680e424c41434b4d4952524f523539", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2fbb99ba0c4a86dc67ca38c3071429e8406beb838b0ba3114b2d1342cf7011c397879da3fb4b4ffd4df534e6948d4913e": "0xac33b989d0b4dd35d2fb8af4cd04cc5a3831e59023cb884044f5cda0541f10640554525359", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2fbe3ec6b6f209986f7c790b6f07f5b847493915ecb44badd479418bd0ef0f753952690f6ceeb421a0fe567edf2fdb228": "0xe26969331bf77ce04768009026a5362d51e5bccc12f788b8cda2a43ef218bd04094175677362757267", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2fbef333f49a8a69f97789d70bafe9bc34c69cc407f4deaec89a4090075f36639e151c616b8ed573e7e384ef7672d100b": "0xfc5d04e7ff3965c8285a2c23aa573117deeed886bbe5e3be0974f1cf0a2ff216073131f09f9a80", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2fc1b05f18f15932e1feafb89e827fe010879c078b9026ffc8f5b7ca4f1af1ff0f51c592958f24b43ea5433a34f0cac02": "0x4e4ac8070fea95496b63cdcb6987de88f63dc75a295eace6ce5079149169300c033032", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2fc365be94c882e564b1276951858b44ebee52eddafc82ea6226864dcf0583e034f6510d2b390ed60129b6855fc020c06": "0x8c8305ff8478e6309325ebbfb81e8c1883d39e65d2ef84f88e4a428615c4927704313133", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2fc3963aac45292fd533f75fd86b2776712c0e71c6d383ed080fca5ac67242f4365fce824e3b989af1388d5a94f38b934": "0x12c0e71d326f83f4e6089448e147fdab51b0b7398a7d0cc9a88b0571432e7310033237", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2fc7ba4593d07409b3f412f1bd282cdfc15ece2a3d6a57419d76a4a66bfb72185e128e3abdd1e13345052f43f21548a9c": "0x8c4c81f382ae2c201eed4b0b519f352aa9c0c8593122418b30ac9760844de2fa0235", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2fc85519bd52e95bf35dca96c087df9833159dccdbf4c37ba277b4becdae7ef002bd7ab17d62fc7419dd68967e41a358b": "0x6610a5024c2a5db3d02056d4344d120ec7be283100d71a6715f09275167e4f38033033", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2fd040f54cbd52461abd73a171fea85debd05066b950d256e451a29012b1fdd38e661516eeeb487d816bb2a65975baf01": "0x68f6e4f77f043dfcb9fe88519996ee25ccae674ccda259bc49efec6b6eeb96070530312043", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2fd2d5105a0e18eace0917beab6a3c06106b430745802c7c8d5cb3537dde6dda1c74dd2251837c781be4e0aebfde8d673": "0xe8b2603f6baee5bc32a9b9e4eee9168499fa553d35edb56aef0035ff7e1f165e0c506f6f6c203220f09f9a80", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2fd53da24044e2cbb272f820421dcce934e6776c8d171ebb2e352ecd10eb75ae1403f00a4d76089ef92d9d598264ac841": "0xc8c0c1fb9bb3902b9e4790461bec2c33afa31c9a3b72a4e4ab6c050b4a284507033032", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2fd6768c7769684ca925e95e347e739f6f2382813004a234ea40eacc434ee04b04e52977a2907023a2d2cc44d46412057": "0xe6247d2909686256b09006b07e758ecc128364a926f1223ef04b38628a5a3a5e0231", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2fd7743d42f937d08697eed3dc9a08054de670277a4ec31a0664f1d47eb01a7fc351952d63980ac1246ae1e6751f61504": "0xc229d8ccc5e5650d17760ce2b7c42bdae5f6afc6e8bab249ec77f3f779ee5a6512333a206e6f64616d61746963732e636f6d", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2fd8cbf55b87480eb57c660a1ee51397d742e6def792a15d4b2518cd2a957f9bb7f75525308355f9217a2df17a701128a": "0x4c4769cc1bf4774f19c7433e31a5b8cb686944cdd758e193d264410d4918b1200231", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2fdf2c89d5d9107f1c6f7abf3c00afad2c2b18a21865fc3da2283153ebd44a5da61f33753f6f20eee1d8e41fcbaa0dc67": "0x9c7c545141ea2dd84fe5ef7d567ea450f59967e7afa68e5f1ff7f7c46db19627033133", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2fe336c580c0aac48f9675f6119359f3c74378a77c102cab0cc86d7fa5bd19668bd88c48b2abecf283d81eaf19b4ef464": "0x0a54e1448806b2c0cbdfd5da73198f12554bc972045fc9dd3f2e22b6c5a97c1d0f466f726b6c6573734e6174696f6e", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2fe53b5e22298bed52eb973676ce36961a872a2b4f736ef9a7242e0a0d8e64d616ed4c2da9a103707e9ac7807a764292f": "0x8adc4e19e79b3d2c744f88fa5aca47ef05ccaae141f6435c2d50df824433ae48033136", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2fe781d2115a0c6d6e092f21df11130e6041edab68d8fa56e9c4845bb931beb45b2e457162753e65c440d11f83cc82871": "0xaed98e15e3ed392e38654215c3d1fa8143de53460386b60139fbb45c036c1b430653462d3333", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2fe7e3f3f42b17a585445b3960246fa578a1e84fa7220a6f820ca42a6dbe689b545ba1def88a7f1bd98d7aa46a9ab742e": "0x48ca001326b583070e370be3bc6680d09cad47649584a5c992bd388c693b9a54033135", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2fe8e5e0ff57af24f2fe84e128c33379f329a36786940b598924622428c95d5c41812d55b9ea2f091ad99b2fbc944331d": "0xaed98e15e3ed392e38654215c3d1fa8143de53460386b60139fbb45c036c1b430653462d3035", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2fef4b17e8881773f3a7026ed8252925b4e8b6fcf0dee98dcb0d710fab325fdc6b158964c7011e9a43be877bae760717f": "0x52e73898bf4601f9c9a7fa052de0cc313b159dd368d458f4cb0341eedcd6d818076c6b736d3035", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2fef90f8cfd2ad5246969d5211208d9bae6ba74e93df6c3e3cd1615c99708e867e1f3160e324fdcce53be8e3b733e663a": "0xd6030dd61ad78ca1900865d2b53dd163bbbb5b40c82f94d25cb6ecc750a93c25033031", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2ff1bac2f77ddd9afa2671c7f8997439f983a3e49a6aef7637adde845d561274ddf1d66ce267c81b3b0bac979ff79106f": "0x9c7c545141ea2dd84fe5ef7d567ea450f59967e7afa68e5f1ff7f7c46db19627033833", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2ff8ef22db0199c20624fd641ce685a3d988740c0cb624d6228e22704f9dddd8a526775c81506cb9eab96d3be870d4a04": "0xdab8ba7a028d62fe9a5088e46acdbd2039f01abd8baa7c695d9377661c3d406d0232", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2ff935b8d9b8b9bae1cec0a900aa2d3c812c0e71c83c45d50d2f831c6574ab25eabed7842fc69f51bba122c617531d725": "0x12c0e71d326f83f4e6089448e147fdab51b0b7398a7d0cc9a88b0571432e7310033435", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2ffe13fd1e48e4594d33864de440f71acbe6ac75cc8c52d2d3b88dd29c0352b579f4891c52f76508269f2328fece4d07d": "0xa49deb88afa394b7eb478483a65a8c8f060b7de319dc6f65776a84d9e8f40e7e0e4b534d2056414c312043544c52", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2ffe84d61bd1090467d85b0393f73254340d1c7929a103e88681731f954862765bb66d96c36e22f82a35fe75cf7a72c20": "0x9ee1fa0d8d4e022ed5680b5925d19718a7ecc9f8f2ff77de54f0822978d2775513576869746e657920436f6e74726f6c6c6572", + "0x2aeddc77fe58c98d50bd37f1b90840f943a953ac082e08b6527ce262dbd4abf2ffe9d9c0d6db5ab5e0051a7533be77e012c0e71c65c6d73c4787dc93561ade71071ffc5d78756ba4f606fe91a6e34521": "0x12c0e71d326f83f4e6089448e147fdab51b0b7398a7d0cc9a88b0571432e7310033433", + "0x2aeddc77fe58c98d50bd37f1b90840f96ee5a0b09e7e9a96219dd66f0f74c37e00216b615048534c12bf9efdc9e4e25b4dd72c560029152b6546ba2fb62eca400d7edee7e5f36b5a": "0x0000000000000000000000000000000004187f07072543de8fe520037e115acbdb9b9ab6a321be237e39e67ca4ee979749", + "0x2aeddc77fe58c98d50bd37f1b90840f96ee5a0b09e7e9a96219dd66f0f74c37e00ba2794d92fc826e4269547e0e9a8c162de9215bd45921be44dfb58ec95d2f627990d5189001440": "0x0000000000000000000000000000000004989aa1bd13df5939cb65518a399c66800e3b23e792592f94ba7af30597d7fd71", + "0x2aeddc77fe58c98d50bd37f1b90840f96ee5a0b09e7e9a96219dd66f0f74c37e01dba54cb1c92c2856aa4370ee3d21b98ec19f0cbf2106a036215937a15bbe517b24ae5fef4d3870": "0x00000000000000000000000000000000040a88006a747b712bbac65dc015105c9cb6d29ba60dde6762a881975c6b1b1a02", + "0x2aeddc77fe58c98d50bd37f1b90840f96ee5a0b09e7e9a96219dd66f0f74c37e0214f0b5b1672e56729f8acbb64cb60b5edb62beadc9ac05430ede0086e29800ee32d106befc7825": "0x0000000000000000000000000000000004ac11ec66576b8d0a1c924596e74f3b45c61c7408e1680e16b4e365ddb4b93f56", + "0x2aeddc77fe58c98d50bd37f1b90840f96ee5a0b09e7e9a96219dd66f0f74c37e0223d09f1c0c1ef00ce0bbe155c5f116187af43bae0bd493872f436a139e23d9b26289d0721a310e": "0x000000000000000000000000000000001006ffadfd1ff3fb474bcca0ee75b100d244da043ce2e0725e40b1e8c7d6f0251a2c61317ffa5f84e38eaaa44e333ca7be9924b445ee9e6e275421200ecc58a9b09454a3dfb574a6756a307688f156f4ebcfd72b63515bcdfccb50cf7f7bf92c12b6a0389596b472840969a9088eb5852fa03a5b5dd7a3c2fc7275d7c05563a900", + "0x2aeddc77fe58c98d50bd37f1b90840f96ee5a0b09e7e9a96219dd66f0f74c37e0318c1db47739db4d030ca0b2a60a30e7d1a0fec231f6f36c3b608036d25ff6b2b9ab9576d59c252": "0x00000000000000000000000000000000041ed7e0b663455310e4a8d084ce985ea6dde9cbd788f01cbc27f9a85264e97515", + "0x2aeddc77fe58c98d50bd37f1b90840f96ee5a0b09e7e9a96219dd66f0f74c37e037dbcdc8f46729a2cba024614ea8ccd1ebf7a634f30b38d65c082be6aaa92551b9c3b4d1f15ae6e": "0x000000000000000000000000000000000c98cafd75bd233ed0674c7493c67d589c4d7e78b69cdb409ca66c0f3a7391ec06662d04da99fa11b0ddd8bdfec9bbc2574ac71565e9346c8e13857934c18b3646223b081a343ef66eeb872caa2ceac54d75566c279627592362d2cd162bd21831", + "0x2aeddc77fe58c98d50bd37f1b90840f96ee5a0b09e7e9a96219dd66f0f74c37e03bfd6fd4ef57fa5a0ad3e520332a754892d7a16de9de871b9f20e982d62a498b5d9c7e5f93d433e": "0x0000000000000000000000000000000004241816355a91d53c772aebd5c1ff1114bb35fd22995e8b0d84fe770304b80352", + "0x2aeddc77fe58c98d50bd37f1b90840f96ee5a0b09e7e9a96219dd66f0f74c37e03e65d4ca28086078c2625b0e10c7bf65f283c576878cf00f67478d3dbb6bf39ee62b3ca19ce893d": "0x000000000000000000000000000000000448edca59aaf9ec40d9967f298ab5a5a2bb7265eef18569d5c065f318da512358", + "0x2aeddc77fe58c98d50bd37f1b90840f96ee5a0b09e7e9a96219dd66f0f74c37e03fc9979d20d8f4376e282d7a7eef593fe7a9a8c5d08a21f134e8858e1b1753bf347057c4db9b234": "0x0000000000000000000000000000000004964d882bb6127e75f8c02efdefbf052be0c010256c41d832e8c81fae632dec75", + "0x2aeddc77fe58c98d50bd37f1b90840f96ee5a0b09e7e9a96219dd66f0f74c37e046409e5f145bc2af4f95e82d3eeecfde0058a399005262a9709101ddf3f2a564ab34040678ece15": "0x0000000000000000000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f96ee5a0b09e7e9a96219dd66f0f74c37e0556a86b11fa77913c7f40746d04d77628d886dfd469c9bf606232dedaa248f5c219d32da93f4054": "0x0000000000000000000000000000000004f2ee0d3d7e3d57e18249e42d570e163d7f34ac68e81c973b41bfa521f2e99e0e", + "0x2aeddc77fe58c98d50bd37f1b90840f96ee5a0b09e7e9a96219dd66f0f74c37e055ca836acf0447774422321a842adfae9419ecd3983c4fa2da6e879ccc1db031e54c742bbb9bc03": "0x0000000000000000000000000000000008f67795750255b9f9c19a23a72960b240276a404d3c5fcb4fde2cf5759e88f7045ff23e481785ec5fddb6178f6860b44bdaa0150ef473a91de3f1ff794b2b6fcb", + "0x2aeddc77fe58c98d50bd37f1b90840f96ee5a0b09e7e9a96219dd66f0f74c37e05d31d1ec885004a5a6e6d7f1f5af2300c1b721cde7f08238ffef321bcb45cce819b00557fdedb00": "0x000000000000000000000000000000000c1415a9d9719c249bdeecbb9b746639f743e2f238ef5a2b227ce206eb93724a6f6a4aa384952d2245b6c439c833edb350c0ba7e31ca423f081ee6a0d79596c6585a6e6d7f1f5af2300c1b721cde7f08238ffef321bcb45cce819b00557fdedb00", + "0x2aeddc77fe58c98d50bd37f1b90840f96ee5a0b09e7e9a96219dd66f0f74c37e05e3f970c23ff63cb85d101c656fa86dc284f34f7583b5f178d9e9b619df6031fe2c04b4c5f07e26": "0x00000000000000000000000000000000049a992b67797a09bfa4fc79558b14bff0e2ae2b20207ceadef50ecef31d120a15", + "0x2aeddc77fe58c98d50bd37f1b90840f96ee5a0b09e7e9a96219dd66f0f74c37e06464a684f7b7a0d1c6681030fd4860fcfc1dfad9ae55fc0181229b007b6365dc4c8f5fbe162554c": "0x000000000000000000000000000000000cffd31bf694e0d28434da06abd3fe4febe23b25054b5de48ed94246339c51b2e6eaf1654d9143d99dc782d03b496b3801e06a4c6405ae954f40b7e7475f9ddcb466a4ddefa00f74de69a30bb8f6f87c50cbd2804768c367f3fbad5663a98fe48b", + "0x2aeddc77fe58c98d50bd37f1b90840f96ee5a0b09e7e9a96219dd66f0f74c37e0655181280220c8b6280b912d54001e1ac0bbc1023ba9a16974a6c23d22e817e97d418ea94d29642": "0x000000000000000000000000000000000414a0db74267a9c3994944cb470c48a9f4c8a01df05766b96eb29789e9f049748", + "0x2aeddc77fe58c98d50bd37f1b90840f96ee5a0b09e7e9a96219dd66f0f74c37e0823dc59ec2f7a204eed7cf3f4f6560d58db4eb78bd24b655bbd1d7a5c6b454e77c8dc5e2721a54d": "0x0000000000000000000000000000000018b4f8dd9a19e72f2ae65f989872a96ee2e239a9e135a868bddcb4dd278ef0f97a8d9511843f9df390385c97ef304025decc2d42cd7082db58f5b5e0523c58183e7a3a98a1dcff1349491c4de950bac2427069580f45cabcf5b57e645d0df2882b74fb773cd20d9adffcfc49a58d0ed20bf5baf645cd37aaaf65408f56ffe22116d8a8b294275746ad87f5fe0d3f5eb3fb81905036522357b616096f3e84bfced6fe3aa3a8b8e0e17a72626db79dd999dd5e9cecb8e0f265391e5daae3ec229d3c", + "0x2aeddc77fe58c98d50bd37f1b90840f96ee5a0b09e7e9a96219dd66f0f74c37e0832e37ad433bf330093c7603ddb81760e5c90ba6c0fde51812e18e6cc14121c081f5a573a868142": "0x00000000000000000000000000000000047bdfd0ce52699e0b3f913ebc544b48b0cb02fcb8cb394625f88945200318f592", + "0x2aeddc77fe58c98d50bd37f1b90840f96ee5a0b09e7e9a96219dd66f0f74c37e0867cd2096d96b96ea6a0804e0024beaa87fc072eb250446162310017e52147d18fada54a8ddb57b": "0x00000000000000000000000000000000200cad33c225bbc550c7e1b89ff2feb2dcc8993f2e3a8dea40898fa8f54f754b002ecadcb36865c859f998d5538bc2629b4f4aea6e03dc4cc110bcf0eea4e063307ebadb760b7f8ca8280f493f1604fa76e90df43f3ce4b084ea6383315b94653f8aa121a03ca81740284a3d24ea4bf49f22578caa58441527a76e8464a319a015a27a87e5999ee8830465b09da09f16adfaa168d3aec122953b44796a9db5157dc6df02cd907ad64313666799a84023c8e8025e7f9f5483a05823a732de3dbd3e90e389b9296c049a2cf0cc3255f3d58346b0eb6e6b0826aeaf81aae144d5306ca8e2730b18be41205e5d9192603da3fc19d7d4b951519509cb32458ad622ae33", + "0x2aeddc77fe58c98d50bd37f1b90840f96ee5a0b09e7e9a96219dd66f0f74c37e08cc79e8d56c8beb7c88cb63517049b0569ba773b2cd7be3dea4c7c88340ba5f31c7bfa2e847f65f": "0x0000000000000000000000000000000004540a38c94322e193c52afe4d438b6d6b1c50a9cafa87e47f1fc41221594d5f39", + "0x2aeddc77fe58c98d50bd37f1b90840f96ee5a0b09e7e9a96219dd66f0f74c37e093c88d361b492968e76c9299f5a2046beaa5266ac0ef8b7b310c929704f15d8e6657b371302202d": "0x0000000000000000000000000000000004b0bf0c9e4095ac5ab829224395315bc4e298b21b180d6e9a86e698f974d2fa25", + "0x2aeddc77fe58c98d50bd37f1b90840f96ee5a0b09e7e9a96219dd66f0f74c37e096c13bcbcb0791226104ba050f385c19450c62d2adb3e9deabed8783eee0059d582ff8918c03b10": "0x000000000000000000000000000000000426104ba050f385c19450c62d2adb3e9deabed8783eee0059d582ff8918c03b10", + "0x2aeddc77fe58c98d50bd37f1b90840f96ee5a0b09e7e9a96219dd66f0f74c37e09c71da7f0f4f7aa98edcae85e6eef98ba192a51fa0efd89aac0541fa264d46adc9d8f29d3e21047": "0x0000000000000000000000000000000004dc226375dedb131cbc73b5c90ea8d374d5d4b5e75dae7eb6a9a4c215d8e9b0ad", + "0x2aeddc77fe58c98d50bd37f1b90840f96ee5a0b09e7e9a96219dd66f0f74c37e09d05f5fb1d062ad503551a752e49ebef1b6988ee561cbbfe0f442a56fe624a58ae80ff3b3b9cd7d": "0x00000000000000000000000000000000085034b9af07130a1799cbdbfc0c2ff2fbafaf47fc4cf70d82dadd9e606f23085f5034c3e43599377576fb1fb81c8410fca61070ddcff4484cae5e57de2d084f6f", + "0x2aeddc77fe58c98d50bd37f1b90840f96ee5a0b09e7e9a96219dd66f0f74c37e0a7a36431e6bf788600e047c97181ac8d0b9d5a6372f6018f556d68b2b4cdb529d87da365f718d40": "0x0000000000000000000000000000000008ad17c83beb46308e21cb6fb45b9587a826addb8c001e01bc2280847982af1b77769e87de4b843adb49b3de1ff29ce837047c48023aaaf9c6d3abc6e66b4ec34a", + "0x2aeddc77fe58c98d50bd37f1b90840f96ee5a0b09e7e9a96219dd66f0f74c37e0c100cc5eae89342e659339aaaf44f9871d9a42595bece9cc446cc4dc321dcb30c798332a5780846": "0x00000000000000000000000000000000047e581640cd7c61c76dc4b85b771ce496d10e52429113f8e7629425ad9787c81c", + "0x2aeddc77fe58c98d50bd37f1b90840f96ee5a0b09e7e9a96219dd66f0f74c37e0cff0134bde4ac18abb9286b2b288f2af6eb392d95b12a64768174de723047b9ae0f86283dd5e34c": "0x0000000000000000000000000000000008e25940a2f472c60c242463e18c20ab6555074a0644ac2b9583140abc15e2712436dafe22546294dab15b18d1f15fed8856e6ace31582b0dca7f8d450cd963368", + "0x2aeddc77fe58c98d50bd37f1b90840f96ee5a0b09e7e9a96219dd66f0f74c37e0d39c09be41728d25271937d9336b12c2801a62938d27878729a7987c705770d5f19c0e42ffcc64c": "0x00000000000000000000000000000000044e9a1114da2f930a02193c823ab3393fd2f4867b0ba68ab5ec267e50ecd35420", + "0x2aeddc77fe58c98d50bd37f1b90840f96ee5a0b09e7e9a96219dd66f0f74c37e0d533a9fec9db13002b47d21483aa953be67636583cb184f55d575e0f71ec75f45383a786324a64b": "0x0000000000000000000000000000000008d5febe9f9f424e1a509cadb2ccd2f502fa1e9b577c03bfcdf74f7e6abe6f692c2d14410d4bb33f09014a028cdbb9d2c2f00e7d5021748ac859c5dc11cc277a6f", + "0x2aeddc77fe58c98d50bd37f1b90840f96ee5a0b09e7e9a96219dd66f0f74c37e0e77a555b20dfd069642d0db9f3b301b44df74b63b0b930011e3f52154c5ca24b4dc67b3c7322f15": "0x000000000000000000000000000000000cd4cc99150b203e2ded46d1bdfa43c2f64f89cb4a9102e8e6d5b37784ab97b117daf0804d1bf147f716661acb2ce7c796d0d655e2781c22cd138c4e6d6edb9b0ce4f351785e2ba01d8ae8c408b0112af93577eaf7487d1ad4cfb54285c88dbf1b", + "0x2aeddc77fe58c98d50bd37f1b90840f96ee5a0b09e7e9a96219dd66f0f74c37e0f177f5acba9e6e070661c356f24a2cddc859fbae974cdff149661f165f5e622df3060bcb8e7b373": "0x00000000000000000000000000000000047ab0ef4391500cf4634c08dcc0bafc65b9c787a651ca8679b8ef33a6b557fe5e", + "0x2aeddc77fe58c98d50bd37f1b90840f96ee5a0b09e7e9a96219dd66f0f74c37e0f7722ef9e3f0c3bb0d8ce5256f0b5a51a38ccaadc6d21fe930d8ff3da1dca198ebe1807802da753": "0x00000000000000000000000000000000042fa216946d71756ea4bc43259d6866958233f796bbdcbca326d684a840ef72f0", + "0x2aeddc77fe58c98d50bd37f1b90840f96ee5a0b09e7e9a96219dd66f0f74c37e0f7f00ad7cb619c008769738ff8d53c17d6e0f0344e52c50a5ef6b61a33389f4dc4adbb7aa2f384d": "0x00000000000000000000000000000000048a0e42d190d3ecaebf11d3834f4b992e0fab469e6bf17056d402cb172b827a22", + "0x2aeddc77fe58c98d50bd37f1b90840f96ee5a0b09e7e9a96219dd66f0f74c37e103e847acd44a834c8c0c1fb9bb3902b9e4790461bec2c33afa31c9a3b72a4e4ab6c050b4a284507": "0x00000000000000000000000000000000044e6776c8d171ebb2e352ecd10eb75ae1403f00a4d76089ef92d9d598264ac841", + "0x2aeddc77fe58c98d50bd37f1b90840f96ee5a0b09e7e9a96219dd66f0f74c37e10af15fa81ea76ada81e54507ca4f6fa30932b96d35e8f073556c99f4e3119e5f679893450192109": "0x0000000000000000000000000000000004fcdc5fe2f7a0789f42175567fe656b9121815763a037c761ef846f0d97420239", + "0x2aeddc77fe58c98d50bd37f1b90840f96ee5a0b09e7e9a96219dd66f0f74c37e11e755e0b2a267d8a8a2e5461f346cf0c23d1ca613437432a160525b6487dbb718afa51439d48d04": "0x00000000000000000000000000000000088a74d6464340d1e60feb30c35ef63b8e48737f225e6343b1875e352756d0160f3515e1b78389f5ef86a9b5e739a0912d6cc4e9f4775698ac23458e8fe8764f89", + "0x2aeddc77fe58c98d50bd37f1b90840f96ee5a0b09e7e9a96219dd66f0f74c37e11edb4162e9b96b85ecc1b0043fe1fc18950cef3726fa74151bc41f77438ce924c11a9b43823ff43": "0x00000000000000000000000000000000145ecc1d4e60a92262c1bec62d034c979f42cbd3fb1c28570d5baed6e5ed20d533c83b0bba37f25f365e26efbe6c9ecfa7905dbdc0b0e3ae60b29980b42c509c6fb47150da85f064599455634eee628e2f775d06bad83bb3631130854914e96d015e25f73392aeea8ecd64fd33e2dd4728e355e314d8fca42e2a382f95a941d6caa471c7aa909cc665212bb36003c52c5d3eeec39f96556a8242e861c5dd7dde41", + "0x2aeddc77fe58c98d50bd37f1b90840f96ee5a0b09e7e9a96219dd66f0f74c37e11fbcd54abb1de419ce84f6cd845ac3fb2a009aae8e99b1a2fb64aa3e7ce1c7867f3ab2db0c9bc00": "0x000000000000000000000000000000000432ef9a68234eec37684bf683d6e07e2deaf52a336ad7dd7e124041baeee37368", + "0x2aeddc77fe58c98d50bd37f1b90840f96ee5a0b09e7e9a96219dd66f0f74c37e136bb08c596dddb97ce2421f6b3c80a00c8fa9476eddad55f7bb9cc2f54ad916b4969c103b5fd438": "0x0000000000000000000000000000000004aacf425049b018fb55d17640939a6f651697b153bbc59a060a7f2ce4b4c5610e", + "0x2aeddc77fe58c98d50bd37f1b90840f96ee5a0b09e7e9a96219dd66f0f74c37e1404625c59d62180187c76f60b8e91032091aacb1ec79764af51e796a0c962bd2f2e766e9e5ade45": "0x0000000000000000000000000000000004e212871311a823c9537b3f70adf0a9697c7286c84fdefe5603bb2fc49b0a7b67", + "0x2aeddc77fe58c98d50bd37f1b90840f96ee5a0b09e7e9a96219dd66f0f74c37e149ddb66d3286a35ec7afe6fbfc9947fd177ed118016e403dbc14803a0432bfaf0337e3bbc3c820b": "0x000000000000000000000000000000000493ec952a9328c2f39b697aa00f57f01c289423ac2068f506ce2165be10f1ec45", + "0x2aeddc77fe58c98d50bd37f1b90840f96ee5a0b09e7e9a96219dd66f0f74c37e14f43fb7c9ca8d300cf88657e8a5e5005c67c0ae58b0ea1137b817f32d30d80aba618a70b13bcc66": "0x0000000000000000000000000000000018b085746d68637b4db6d45d855e9e31ac9059ffc928c3330ad1e13ac6f170ad48bc1e141bf6afbb7224e41e050c296f264e8c4c3cabb0d91a5594f0585be0571402f777f4b3001d83e7a2441ab8456d2db9ad30b77e5d3f2fa0c4150b769e9a394680cdf69422609ddbb2cd596ee4366b84a50a3f17c0a88b9fcab7263852cf6d982b1616f2b4b963fe2a8aaec915c4d3f90aada694bba3fa5924127e67a2456ce2af982fd853bcdb276d9be46e6bad4cc8e1af153d82638d2bc829e6ec3e2a6c", + "0x2aeddc77fe58c98d50bd37f1b90840f96ee5a0b09e7e9a96219dd66f0f74c37e152f5e61256c5cb31a95c3968b83520b8e43f82edb0f050b1ce7281873a93bf9c0798efd50f5c41a": "0x00000000000000000000000000000000049e66677d3f5f4ac376d14bf73bc819845156f1f25ce9e6930fd096741276ed67", + "0x2aeddc77fe58c98d50bd37f1b90840f96ee5a0b09e7e9a96219dd66f0f74c37e15cb248f0f9af445fe56be5933800b45a21ee8e9817eae9f49099fdf4a20076718497092ed43c62b": "0x0000000000000000000000000000000004a8070648f6e43b7d8a8f10418b696130d2046c10645f10085de80e6098b85f09", + "0x2aeddc77fe58c98d50bd37f1b90840f96ee5a0b09e7e9a96219dd66f0f74c37e15dcd927177e5b7aaee65bf22cdf1f98c91b6c176854d8072f1328e027d2e84d23607b517b1b9429": "0x0000000000000000000000000000000004aee65bf22cdf1f98c91b6c176854d8072f1328e027d2e84d23607b517b1b9429", + "0x2aeddc77fe58c98d50bd37f1b90840f96ee5a0b09e7e9a96219dd66f0f74c37e16530c8e1e5dda93b43ec7322956d133d41e28758fc64d2da34d2888d93af64eb41f7afa26967961": "0x0000000000000000000000000000000004b43ec7322956d133d41e28758fc64d2da34d2888d93af64eb41f7afa26967961", + "0x2aeddc77fe58c98d50bd37f1b90840f96ee5a0b09e7e9a96219dd66f0f74c37e171ca88a3597ca4a1097c82198eca584e8d9bedca6a5ffc1f1eac3c1fb91d0ef4ef313b842b04c3f": "0x000000000000000000000000000000000400e31d15b9166c5238cbdfbcab39ccc2fe0173c9419b060f28fbf3f0ea0cf25b", + "0x2aeddc77fe58c98d50bd37f1b90840f96ee5a0b09e7e9a96219dd66f0f74c37e172f5474abcf5643a8b5707defe6889dc178861ea7b68861fd0ab5427b54119950e6788afe1cad2f": "0x00000000000000000000000000000000041ca9c1ffaaa251b220fbca62f28d6936272e11d052c4e995ace722bb6c2e8d26", + "0x2aeddc77fe58c98d50bd37f1b90840f96ee5a0b09e7e9a96219dd66f0f74c37e173c712e406fc7a20a54e1448806b2c0cbdfd5da73198f12554bc972045fc9dd3f2e22b6c5a97c1d": "0x000000000000000000000000000000000474378a77c102cab0cc86d7fa5bd19668bd88c48b2abecf283d81eaf19b4ef464", + "0x2aeddc77fe58c98d50bd37f1b90840f96ee5a0b09e7e9a96219dd66f0f74c37e177d87d70120c0c15a9e357de87525b67cf9ed1d0f06a15a6363665ca1c9f43ff527c87c0945597c": "0x000000000000000000000000000000000c5da7c5df13916304befdcf8c879f5a35c7d65539711eb5cac00a9d5176b36b580ee022b7052ed281ad71f8cf98ddc2efd5b5fa45d741e4861c225a2bcf22731bd5f8960e7af211c990e0d092ba6038772482a74e9dc91e5696c84fd079992ffe", + "0x2aeddc77fe58c98d50bd37f1b90840f96ee5a0b09e7e9a96219dd66f0f74c37e18871df8131a10a56041e8f550869197a24ed9e968eae648692cde7bbc04077114639c249cc0a043": "0x00000000000000000000000000000000047eb15d7fc95b03fce6ab8cbc54c38ac898932407a3e9bd86d8c03bbfb5b8112a", + "0x2aeddc77fe58c98d50bd37f1b90840f96ee5a0b09e7e9a96219dd66f0f74c37e18b47e3024d66dfe628f36dddf8cdb0242104a2531e7d3efd4860a9a4633be69aaf30f63ccb25a5e": "0x0000000000000000000000000000000004405637fb518f654b40c86cf257796c857ac3c28e5ce0ed978dcc4d69a5d67442", + "0x2aeddc77fe58c98d50bd37f1b90840f96ee5a0b09e7e9a96219dd66f0f74c37e199f24e2487e567b321ec507203650141d2ec630b967b76ec45dd53d852b9cb25f220dd3a3fa2e51": "0x0000000000000000000000000000000004c80e5adbafea30ecb72dec246ad8b5647f95092b535a702b4347d2ec210c6972", + "0x2aeddc77fe58c98d50bd37f1b90840f96ee5a0b09e7e9a96219dd66f0f74c37e19caab1fd4cdabfaf287534dd5ead6c0247a1b0d3ada5588e578602c2ed64caa6f6fc2a5efee6f23": "0x00000000000000000000000000000000049eed509e1b9e0f45b24942e75abb7aa6fa306d0e52c74fa8811857d54d0bd03e", + "0x2aeddc77fe58c98d50bd37f1b90840f96ee5a0b09e7e9a96219dd66f0f74c37e1b2d52234edc009738f45bd8f6341dac4486eedaf00f2357cd19b8d4b8f0271c7340d56fe02bca72": "0x00000000000000000000000000000000045cb36ec4414da2e8f8e6be74901ceaeb189e4bae84245b00640f96ea36814501", + "0x2aeddc77fe58c98d50bd37f1b90840f96ee5a0b09e7e9a96219dd66f0f74c37e1bcae011029977921b0fa0b1a8e6d3ca06224ada945bd41785e55822a36102e48d584ddbb03e9573": "0x000000000000000000000000000000000438bd292140ddbadfe9cfdceda3090c9818d53ae79a862d77e782bf9c9e94fa40", + "0x2aeddc77fe58c98d50bd37f1b90840f96ee5a0b09e7e9a96219dd66f0f74c37e1bd7316875d7fcf8a0340d617b2e5fecf5813d12bf441eb025f610edf738af8f79a98a9e168f690d": "0x00000000000000000000000000000000041020aecf6332d324cc8681199d469780ab81d8e87dc408aa96ca573c590ce344", + "0x2aeddc77fe58c98d50bd37f1b90840f96ee5a0b09e7e9a96219dd66f0f74c37e1be2a3fab16ae5e58429c11f2ff4fc700087c7fdad402d6e97c6df5e73988c3a36c2b6fde7daee21": "0x000000000000000000000000000000001462307128d13196dc291ac51e68173c5801fe6bace303a222d2659255d9debf273c0bb72774583cae164f6f184ea05f95f90c8fa34203b9b2c5a2c1b6beb90a5f389af7a171ff4ef270fc5c602f1570ae7b818fbcd797ae42b5ac9f14454c5b4e4c27cde4c0ba44b80bd040462654c90c73e26b474895a2fd746fd5febf3ecc654c70ba4d71065dc3bd0d11c1fff6bfca26d89b5c3f406eef2e5de8ac7334866c", + "0x2aeddc77fe58c98d50bd37f1b90840f96ee5a0b09e7e9a96219dd66f0f74c37e1d7259e4eafa026b88e89854ec5f225c9a3b8889d4b1afc0cf6cf473d4265a96463c08cccf38905b": "0x0000000000000000000000000000000014c0d792a19684453c51324b0f2a420544d8c3378c515c85c6aad72b7059ed4cd19e745f85a1a8ed92e237063f3ba463c198d7744b7698e0e0a9a12c5966d798c8402b7e0857f31fc28e9c6a0f0970cc810b66ad393edbe120b4d97f5ce99261c9b0eb1b93d4fb82e4fe4e55b4dd8375b8a09c97596db6bc7e080401f2b88a07e9eaec5e47daff641a4a15c87ad7e12649e07f6ebbb54630b984952184c657e441", + "0x2aeddc77fe58c98d50bd37f1b90840f96ee5a0b09e7e9a96219dd66f0f74c37e1d77b5b5e1a11bfd62a79f3b924342c4f634d8ebdf77f50ac051d41387a72d22f2f38155762c125f": "0x0000000000000000000000000000000004304e4137516cc6a906f03158933c2430744e602d6549dfcbf5a0d767358ae419", + "0x2aeddc77fe58c98d50bd37f1b90840f96ee5a0b09e7e9a96219dd66f0f74c37e1e495b9d3175bbcf109e87a012b2754d0b23501fe1fa775db374927f09c228f07948f81ad84bf617": "0x0000000000000000000000000000000004109e87a012b2754d0b23501fe1fa775db374927f09c228f07948f81ad84bf617", + "0x2aeddc77fe58c98d50bd37f1b90840f96ee5a0b09e7e9a96219dd66f0f74c37e1f4321336da7ceadf4d95d4c5c0131969148d3a16b3d95ab3d051771d971a1955d7e745b0a3a4f16": "0x0000000000000000000000000000000004ccc49a4cbcaec6b03737d84c907628a2cc104cc75ad817ad38292e5bb76c527e", + "0x2aeddc77fe58c98d50bd37f1b90840f96ee5a0b09e7e9a96219dd66f0f74c37e208d340a192a7ce08433eae795936e63871cbcf0410517d1dad4755f2da4a6d88c1cc1c589b8e86f": "0x00000000000000000000000000000000042a4f829cfd9c12a01da70549643e5bade2829684c101fe7c1362176c884a3719", + "0x2aeddc77fe58c98d50bd37f1b90840f96ee5a0b09e7e9a96219dd66f0f74c37e2137b4e662fa80a05a37c441df3f0fed7ddef5581ff70437b00fb071e0b09537caca8adc4354913e": "0x00000000000000000000000000000000045a37c441df3f0fed7ddef5581ff70437b00fb071e0b09537caca8adc4354913e", + "0x2aeddc77fe58c98d50bd37f1b90840f96ee5a0b09e7e9a96219dd66f0f74c37e214a284ee9e9b01cd61813f456c8f11087d572921c67afff25605aa712899d6a6b04cc42c3d2d417": "0x00000000000000000000000000000000089bee35b6118399b673cf802455159ae282fa4a1e68368fb67cf85b00e47461194f83a66e4c8f4afa5949586c22ba0e7d73e7e4dbd6c1efeb9ccd689080834600", + "0x2aeddc77fe58c98d50bd37f1b90840f96ee5a0b09e7e9a96219dd66f0f74c37e21667555f2586f1cc852bd64d95e1c2fc164ba7ee6c2cce6e87ff8cef81c60940d46f710ed712b7a": "0x000000000000000000000000000000000446378406055f64e506440a1b008f875abbbc8d3fd7c05f785a723fe1b5739fee", + "0x2aeddc77fe58c98d50bd37f1b90840f96ee5a0b09e7e9a96219dd66f0f74c37e21aad0a24a729734c0b881e2db47fb95982cd5c364b87e6cdf5a5c8a336d980156623b53815c597b": "0x000000000000000000000000000000008080b036ace5df3680d4f61cccc6cef4d37bc396e6a6e63fdecf505ecbfe41149b2e91e1aef05cb877f9c862b416d157a840115d43c307290dfba6ac4c4db5dad74ee9592a2fd8d3954c85b71eb39e6eb323411ca48bfba174abbf1751d2d190ec4e3bd152d910b6c892f23f85469cd64bef5d7561d69475207c60f4542cc1257f29cba2b60e937fa112f8e61fdde36e4043d0c40b1eb73f12b5534b52d01b5e16cc6bce54889ca98332b8d289e4ab347234a96a1d5389bd183d7f991791a79f0ab8dd36cb05189e12ff133ef1c0f3ddf97d1319dc737e4acbd882d17e143bb083a8bc182820c46f4dd6bd98b76dbff06f8565f0004eb1a9840ee3f3bcae1442d575c4d8aeb08fb3e8276a09141d8139b74d6a76af72acf6955617309dea176a7a7f90cbd721e0f6df172266f725ed45095c9ac42202cbd84abae8b5494119a938a9c13c25dc960c282ae2a76f4e315ed20c60cbdd08750fd45cf5b2790f7ef045bcf4933936ffd18b5b65409bdc003b5f5ad8f9b8e36ae97b1f7b5f0af2803bd8ba823c07ebdc12f850eb5dcc7e39971b34d5fd6643064e0394cc77cc0fea6718fe96b7fa8b193f73106d03bd579b5cc090cb75640ec8090d19d96a3c3d5d8c7d3a43a4e20e15a0c9e0009fa11135246e1de9cf4507c1945bc86cb0a088c1c465feddac420e696be2b3c613261dd7d84a25b6410eca645efd87d9f4030c7bbc9fcd1a5def7ac55b1ccf202ae5de75a02a224d939e1b8d84f54e5d03a714d4989649f2baaa065d3e927f265702cfa8d8eb83cbea8c64bb01d19c5c184b8e2f5d107fc552b8c6596a09ef8008c83d1dc8ee77dc175036bbd2ca89a55b855a0f01cb9c322a9e20637c9a71e4d131e647d597b1c600dbec94bfa192465e3991a15b6381a73b784a15727dfd555a15f61575f5f1b8323b8fd41416dc9eeb4df87acd23f2453d14482695f0ec5b7ec434dcddaaf83e09e570e22c293906edad0ef967c7216959aedf96ab893d8b8d8c66abeab8ef62940b1c6a6ab7228099d72291c72a5db58282171c8d2c73678f13f3c61579902ea4572ae9e9158046e8e820bf4d82bc56d28e12b54fcca3e2c3e90cd0d8a991718bd2fcf9a65dcdcd1bdd04be44591ff9f838183843605f88f6b88971f887fd069e00f4a2894ce4249a8a70199a057fd69aae09c52bef16685e25b29e22f3d1b43f6469f035a9081033b9a7025c943a4d56fc0f3aed44e21a24d0a3c17a4d6c1360123ce0a4d9a22aaac577031c2ead3ef6399e4bf49bf0ed9ade88ec40ef21be714cf9efc112306cc85c194f758a6cdac27581d1f3929bf543452b7da444e03457ea6424f84ef9a372ecfda077ecf87bd083c89d247ea03cac2fb12a410b3f44f87c1b523b0bd0aa3375d4dbf19354416d87ef2183c6d1c383b29dd10f002272468fc70cdbddd42b5093425e5422", + "0x2aeddc77fe58c98d50bd37f1b90840f96ee5a0b09e7e9a96219dd66f0f74c37e2200b6e2483bae501aaf37daa4afffeb0d84c47f52330d8293ea648e1bba5fe0e35355057e63c167": "0x000000000000000000000000000000000c522159de5d549c217b26deed24558c4ea6e33ab8daf73f5410665acc1d5f845cbc79ba52668a29f5a5c62044bf72f6c666f2ea1347cd1d23c3e54d7a5dd0614eeabbb97403ae010a1fcbbc9cf50529f27e0eda03efec95e29b6ed44dcb075648", + "0x2aeddc77fe58c98d50bd37f1b90840f96ee5a0b09e7e9a96219dd66f0f74c37e22501e6d8f21e9dd5e97f331813198763da88ad2b1f5deb3f42373a93e8895c43de399aa6255da47": "0x0000000000000000000000000000000010f40703cb81f0aeb2691f6069bbb67a5a84b30d392b6c5906100b5a6cc57a781c5c8bb12c78741c7b0ff4659360c78bf5da3af34e842a60f58e53045ccb070302d2de3abc2fce0e6fb421d7a29d736a9ddcfdf51244022ffc483a291c4e4da9588c65e884140b3bfc129cf21cb7423ea9f6a72246c273c3ca4c77a00910f58136", + "0x2aeddc77fe58c98d50bd37f1b90840f96ee5a0b09e7e9a96219dd66f0f74c37e229ce4e5e00a4f0b1e6ea78e3190ac2cfde9c0041ea7a0e1f7b89d52f4a58f01f69258150b782466": "0x0000000000000000000000000000000004da5484b32d12a09f6c28114f2d9ef1a6cb2088cdd2c5d9be152737bbd165733f", + "0x2aeddc77fe58c98d50bd37f1b90840f96ee5a0b09e7e9a96219dd66f0f74c37e22d261d77c92c974201f968f24fc0df93fe98dab905ff103d00a9a232329bfe78c22663dbe60a12d": "0x000000000000000000000000000000000407e8861ce764f34220c198710b60b72f8c59c617fef101bdba96bf6f598016d3", + "0x2aeddc77fe58c98d50bd37f1b90840f96ee5a0b09e7e9a96219dd66f0f74c37e22dc4c22ba0bc0065c05d5f192c927b30b33c85470b53474f2a736a01c3c5da905384329a430f22e": "0x00000000000000000000000000000000045c05d5f192c927b30b33c85470b53474f2a736a01c3c5da905384329a430f22e", + "0x2aeddc77fe58c98d50bd37f1b90840f96ee5a0b09e7e9a96219dd66f0f74c37e23439dff64c47d6062f21f6587843801d599ed5855ae0ebdd2a84c822919e80cd6f12899e5088772": "0x00000000000000000000000000000000044b639041c549fb527faf54fd7e915d481955ae0bfb42842cfc3d63b5b98a0f31", + "0x2aeddc77fe58c98d50bd37f1b90840f96ee5a0b09e7e9a96219dd66f0f74c37e25235c4616852bcaa6c197a5b757309578dfde7a02e19aa9922b8f81a60e81bb0c6b7295090b3456": "0x00000000000000000000000000000000040fca29bfa87fda85b6d07265341c56bc44fe830e4bc1d7b8cd31f54cac6a32d6", + "0x2aeddc77fe58c98d50bd37f1b90840f96ee5a0b09e7e9a96219dd66f0f74c37e25c679865a91ba59c66f4d91ebc7dd0065a5a2837014e5f4cef5d36d36d4ba7c915137d885dd7640": "0x0000000000000000000000000000000004aef53be490b506e8e00bc24809e634fef3ed2b1f8f3bc9926a39e2b40c3c70fb", + "0x2aeddc77fe58c98d50bd37f1b90840f96ee5a0b09e7e9a96219dd66f0f74c37e2643c0564bb7e30e26842927c98a50ab1d439ab45f21c5beb6970556e1fd7b52df44977e4344b148": "0x0000000000000000000000000000000010f2b13a9cb72a219a88fbb88f7c5306fcccbaa21a22484a24bbb84b8acee8b50b2602783d96c4e25d8f6894e457ceb968bf1c9694295aee52514d4919056cdb1226842927c98a50ab1d439ab45f21c5beb6970556e1fd7b52df44977e4344b148ee69e45394d3fea77645868ce1992caf33fb25200b4ae2b41d1306a46dd5f720", + "0x2aeddc77fe58c98d50bd37f1b90840f96ee5a0b09e7e9a96219dd66f0f74c37e26a2abbc21cd770cd88a4b558274e57737ffd3fc9741848596199a29d77fe511804d20810cb76050": "0x0000000000000000000000000000000004023fe56458783b5ac1d399ab49e8ecfe911d282cf645ecc8b4d9803a130f685f", + "0x2aeddc77fe58c98d50bd37f1b90840f96ee5a0b09e7e9a96219dd66f0f74c37e26e9d47393173c428a65f2773ad69cccedc0a58ef7ebd2d446b882231b4b97044105b2035a8d9546": "0x00000000000000000000000000000000044a1123e20cbc903262ef39136378a2528eb7382d3b598cd240af1a965f402662", + "0x2aeddc77fe58c98d50bd37f1b90840f96ee5a0b09e7e9a96219dd66f0f74c37e2777a559c125897fb8897a746ceaa53376946a3da353c1c987df8c0caa4395ac0eaf0e6c74874054": "0x0000000000000000000000000000000004888593ed4e02aa8a39aed15ec8aa2f0ba2eae732b9e2bf7f6d72b6d012fd925e", + "0x2aeddc77fe58c98d50bd37f1b90840f96ee5a0b09e7e9a96219dd66f0f74c37e27dc7bc51117cc44d46e6f10cd59b0f6d7082dffb33d27c9f29801233f8e28fe3f5edf2d51762c6a": "0x00000000000000000000000000000000041d6cb02740c7ed074385a93d27f0f9fe5efc113a8e5961d964c54b0afc6bfa12", + "0x2aeddc77fe58c98d50bd37f1b90840f96ee5a0b09e7e9a96219dd66f0f74c37e28cb5aade7584f6236d7b7a05501f3e93e7eec83c53739147dd9824554e4907136371ca062820e3d": "0x0000000000000000000000000000000004904f9054a49d973dc073e09bdb9c9e49213558cf7b5a29d6f2671d8f6999656a", + "0x2aeddc77fe58c98d50bd37f1b90840f96ee5a0b09e7e9a96219dd66f0f74c37e28db6c1e91cbc43002385caf9a08b92ca458a0b817a8cc303cefd5a0c6e108cb939e04242b9e007d": "0x00000000000000000000000000000000042cce76137e2e2d9bb63e081d4074cfa4688d7d9781d2888f36634f646da62561", + "0x2aeddc77fe58c98d50bd37f1b90840f96ee5a0b09e7e9a96219dd66f0f74c37e290aec17ae7c197466fae573cabe4172bdfc60dfd00dff703a4323854715c151f868293db828190c": "0x0000000000000000000000000000000004f7034438a748412760539f824f38f3f9ecbf77ced8716de97c5ade5d2444c8c3", + "0x2aeddc77fe58c98d50bd37f1b90840f96ee5a0b09e7e9a96219dd66f0f74c37e2960a5a23c329652582e9acd4386d60a8d3de206a575ab9ab0c383f3b4ee88d2a2ed144afd356504": "0x0000000000000000000000000000000004953288a0e80d88a64db2db07ca48da06678f683fb99301500223d663dca35b7a", + "0x2aeddc77fe58c98d50bd37f1b90840f96ee5a0b09e7e9a96219dd66f0f74c37e29b138c94f24ba807c4e144380357ad3e690e74f5b7bbbe4b7d6ab1579d4c6d7c844ef003cad9a24": "0x000000000000000000000000000000000472a136cbd146b0596b9cbf73f4f2e402dda2683568e33d1a3db791ddfaac6a4d", + "0x2aeddc77fe58c98d50bd37f1b90840f96ee5a0b09e7e9a96219dd66f0f74c37e29c4999a48e5667768f6e4f77f043dfcb9fe88519996ee25ccae674ccda259bc49efec6b6eeb9607": "0x0000000000000000000000000000000010225ad9907fd7a3f7f3633f2251c3b390b338385358f1753ce35bd27328c7fdd1bd05066b950d256e451a29012b1fdd38e661516eeeb487d816bb2a65975baf016920834078df5f13662750273260531e585b9e802eb1dea6a98e7fe2f7555570ebb515975618eb35e252200dee0fc30b3db265686c72ca22708ad304084b975a", + "0x2aeddc77fe58c98d50bd37f1b90840f96ee5a0b09e7e9a96219dd66f0f74c37e2a9b352e5eaaff5751f78769768fc88c83546881a768523b3c70c2500159047a970ac4ef16768af6": "0x0000000000000000000000000000000004905f923a67cec79db9e1415567822f2c440e794c4a38b43144bfb1a044b2a2f2", + "0x2aeddc77fe58c98d50bd37f1b90840f96ee5a0b09e7e9a96219dd66f0f74c37e2ad59b47893766e9a215ba2d1b408fd5350b93f2566124331dabc06e94c16d7080d3cd5771d59958": "0x0000000000000000000000000000000008eb6a6d492311cb809fe02a7649fe2c815ac9a824be7761d7f5b28360d06b810c1f8ef3aac7ddc528f500ac380bfec2dbe0c58caba4540adc427fd3e3186bfeea", + "0x2aeddc77fe58c98d50bd37f1b90840f96ee5a0b09e7e9a96219dd66f0f74c37e2b031c075ea343ce443c76dcde19df9387486ded7845c6d85ec2a4c17f38f8b1e7a0a14de7968d7d": "0x0000000000000000000000000000000004727dba627f34c210eba395fc7f60d28b3a58c5dbd6b63fb4f9788ee764b2702a", + "0x2aeddc77fe58c98d50bd37f1b90840f96ee5a0b09e7e9a96219dd66f0f74c37e2bab42363fea46ad00f52ade889dac25285059b639359071c2aad88e3f1f60593f86cc460ce20213": "0x0000000000000000000000000000000004d2d790f992e31eec84ed33b3ddf3e92ecaeaed911f0026c2ca09087f3eb1d3eb", + "0x2aeddc77fe58c98d50bd37f1b90840f96ee5a0b09e7e9a96219dd66f0f74c37e2bc21eb1a6e88498ea524b9e0dd9bd336d31e71bc1a172388b10d4b6571ace5e7e6e836483110216": "0x00000000000000000000000000000000049e23e3588757c7744916bc6b65d9562fd12f807da8bfa23ca354ad5b40bece4f", + "0x2aeddc77fe58c98d50bd37f1b90840f96ee5a0b09e7e9a96219dd66f0f74c37e2c09493faa9e924efc5d04e7ff3965c8285a2c23aa573117deeed886bbe5e3be0974f1cf0a2ff216": "0x0000000000000000000000000000000030a24f97e96ae4e213d8eae1f35213c986e0ec03126812b24cc1bdc9948443044086d6e47051058a73623a0abe221e2cdf86a362a3da910618be17cbe3629eaf317cecf08ce1f6f9fbe70156ec68ff04ab4ad0dffd5f39fe72c955b7f319d7740c2e4e174e782224c6e32c71c85d399497af3cd209216738baf31130ed860a5877acabeb358e532ad64c9e4e9f5b3a2bef0358e8535cb4e1b8a7727cc24b7be643d0ccf4cb7501417f0d7bdb6d577e026612d02579686f0ff1137a10c843f5c963ce0b753196d88630621ff926331ce4780474fdf5b100fbcf96dfd4e984d1c669ac66f315467fc0b8d0d5d5d8906dae845567f911e24012ab0ebc185ed2dc6a66c016c699321be18f86dd04415e6f3152fe5b3bc13f4808bfb4617b9bedc2e1291076ce5a68ccc3f21da73f2b8747c87a71aec14a792bd55050a44cbe58c7196f5aa67923621f3a3395c3e2a58aeb89756e2dc11ba9ef1ac8bd4953cf2a2201344c69cc407f4deaec89a4090075f36639e151c616b8ed573e7e384ef7672d100b", + "0x2aeddc77fe58c98d50bd37f1b90840f96ee5a0b09e7e9a96219dd66f0f74c37e2c3ee724586db259eaab0cb55c147ffaf184a4c00513e85f6d5bb6416994fbdd0dd168f3c59a291b": "0x0000000000000000000000000000000004ecda6ddb746609cf2736a0b70823b52b11b15b1bb35a4021da70126290bbdc64", + "0x2aeddc77fe58c98d50bd37f1b90840f96ee5a0b09e7e9a96219dd66f0f74c37e2cd98d2b43b99a0b6a325e3630266fda0ef7f7725ef8199726e29d569d609f3cf068c4db7e82591a": "0x000000000000000000000000000000000c62a791daef6863829ce7969886db050a38050dd52ed6c1a685cf7897e67f165e969b1c4800a2e1700fc49adc3228a1faf72543f36ef784991a2a25d74632b26fa6644cb7298d69083173522d5e51c66dc5c88bb7e4358ab6d88b216d6574b010", + "0x2aeddc77fe58c98d50bd37f1b90840f96ee5a0b09e7e9a96219dd66f0f74c37e2d287fe916fe23dc925000bd5b83d502f56c49f2a91e3532af9f919d6eb52d750b72539c6b62d45b": "0x0000000000000000000000000000000004541145a8a9d8b066ecd0c7dff89c9d397a18e2e0e9d65a36cb2c1295c768e376", + "0x2aeddc77fe58c98d50bd37f1b90840f96ee5a0b09e7e9a96219dd66f0f74c37e2d859f3bd54b349892e02ce87428939cfbb7fbeeb1ee758b749a5854a1bd3ae9ce36b3bcb753010c": "0x00000000000000000000000000000000044396d758a45239e3ad43d8ffa0d171a6785aec18c571107c6675d53d082f09c7", + "0x2aeddc77fe58c98d50bd37f1b90840f96ee5a0b09e7e9a96219dd66f0f74c37e2df274fea56f1419fc659bba6d3985002708101d9c2aea9155bd520c105688751281cb40e4d37163": "0x0000000000000000000000000000000008e0fe63b7c5032e2437b3f8327e95b07eae600a8ad4f31e17db0f80a3208c4728f2c9cf52ac4784de6db0c160481ae4ebf7ce0d7066011e36e18948172c05d059", + "0x2aeddc77fe58c98d50bd37f1b90840f96ee5a0b09e7e9a96219dd66f0f74c37e2e61081843efc3b7105c06afbe01ff98801bf3e46b96d61d0d7aeadf7af7d6c39a20dbf946b0fe41": "0x0000000000000000000000000000000004f295175d63624a3f6e510b8c189db808a049704c4b99f49c2638e9d963d1a3ca", + "0x2aeddc77fe58c98d50bd37f1b90840f96ee5a0b09e7e9a96219dd66f0f74c37e2e7e56460089fc7a54c473bf199d05b878ab34e9a37d17d0a8bf70498edb5c759672e984fa38b432": "0x0000000000000000000000000000000004c01b6763a287079871d569b4c1ef94255494347450d13fa06d2ecb298c426d3c", + "0x2aeddc77fe58c98d50bd37f1b90840f96ee5a0b09e7e9a96219dd66f0f74c37e2ef7dd71f889f0050c841e6aea307d8704d5b7b7b71afad58548ce47dce090e25d01b84925e5c48d": "0x00000000000000000000000000000000081bded8b683a29a0938bbef126bd9510acfc57f2332a8009a305e94190da895695b485a5d58748bfe83392a1ade902a02c95084c00df2070dc8f32f13ad499e1f", + "0x2aeddc77fe58c98d50bd37f1b90840f96ee5a0b09e7e9a96219dd66f0f74c37e2f20db1fb9bc54324c042cc1451781f79ff3bc34cacd5329b21591b2b2d82ad57426a5079ad1c455": "0x0000000000000000000000000000000004ec496735eca64ceabe80e911ddbad8c072ac5b69d3d88ed8dada02a9cf5c66c8", + "0x2aeddc77fe58c98d50bd37f1b90840f96ee5a0b09e7e9a96219dd66f0f74c37e2f2145cd985eff31bcb916e7a7ef77dd1f610ed27ec519b4ec226028eb8edade41f95b217f89f620": "0x0000000000000000000000000000000010c82d85d99021f559a9a4f5387fca2bee170d488b97e00766b5ad19617c52c17e0efe4d35b7d336d66f5ae2cf6969014428415b9d32d8eb2c17b58829d505466715647f856e3beac82df2fd67403a0fbd18fa79f584646112d15d61a064a681c5c05809bc85b574b586d8cb6cff329b5e5666a7f56963c06a4c95fcf681271e24", + "0x2aeddc77fe58c98d50bd37f1b90840f96ee5a0b09e7e9a96219dd66f0f74c37e2f8f1ddeb924bbdf5cadb1617794ea8d20a5b0bf1e3275a815229a34c834c9eb6383602ad47ecc55": "0x00000000000000000000000000000000044beb8e393d37e827b64939797512b2988db9ea41f5b4d2f06a4f8c8fb955d89e", + "0x2aeddc77fe58c98d50bd37f1b90840f96ee5a0b09e7e9a96219dd66f0f74c37e2fe1803695779c79b2636043fc3b8dfa608167a9fb6fb9d065b9f2f5821dc4bfc9785a244b24a92a": "0x000000000000000000000000000000001c7c24bc10ff87531a3d2780dd51b94ed0b85818f4827ddc09ab394a53884c64441a746810bc697bd6b464f5115aef1127130712a70960abe590c8a6491f432232e69aa84285f761bb1942735db2c3d443e29dd3f3da5aa7a00038bafdf93abc5703a56ca86460efa365897ff7affd5f6d280ab3a0d857b37709ce67f551d1f88f5624e7bedddddd49110e4c76ecfc6d2406dc3bbde447a71ef0e511560f588f63ea00a7167ab2ecc7f024e26e62a15b24c02f0b30e967cb91621169e3c780ae4e1cbe59b1e375a52b9131fdb7a85c0992b8c5cdc3f4b4d90e19185972cef58b2a", + "0x2aeddc77fe58c98d50bd37f1b90840f96ee5a0b09e7e9a96219dd66f0f74c37e3161b54cf940118e9aa6373b24df370b863773f45f2bed6ebd80c886c58b4232e655a9b130b6d615": "0x00000000000000000000000000000000043a29d1002e1c81fb779d11e082da66b45a355067ab816aa015f5d5ce3d927068", + "0x2aeddc77fe58c98d50bd37f1b90840f96ee5a0b09e7e9a96219dd66f0f74c37e323ac9ca334c2bce400a075c48b7985fad91dda0b168b2185958c9fee280f145d2dfe24958a12737": "0x0000000000000000000000000000000008d3fb95a477ea8deb243947948b28d08677f5fbc3515d9365668056b12f028ce69d2acafdebef59f646598614d1e0f1ea7ebacf643f0ba096abd078d9a2e4ae96", + "0x2aeddc77fe58c98d50bd37f1b90840f96ee5a0b09e7e9a96219dd66f0f74c37e32ed1c932b701c300e993f475e1085cfe2d313b1089c3fbc33c78c178ed19bfc94be3d7937709371": "0x0000000000000000000000000000000004e66afee7026bccb1c5ccda9ff095c278ca0c40c7d44f645a9e60d2c1cf49a305", + "0x2aeddc77fe58c98d50bd37f1b90840f96ee5a0b09e7e9a96219dd66f0f74c37e32fa3d1c089ff9ebfe88f2849c8b51127fefbb618de330c811b4092da0b9272edf2b8b7fddc05c1f": "0x0000000000000000000000000000000004936c411f5a41fcab2c26fd03ea779dfce7ce65c93203c5538051e77258315834", + "0x2aeddc77fe58c98d50bd37f1b90840f96ee5a0b09e7e9a96219dd66f0f74c37e3308804a76f50044ce6e3dc917919ccb44e66c8a5d4c693b96265d5e7072433971fb38d083d0587e": "0x0000000000000000000000000000000004c0d4fa6e65eb6e8de70d275bd49773f00fa1c385a21608fe2f94a13036ce8661", + "0x2aeddc77fe58c98d50bd37f1b90840f96ee5a0b09e7e9a96219dd66f0f74c37e333c08553d75ed2cdab8ba7a028d62fe9a5088e46acdbd2039f01abd8baa7c695d9377661c3d406d": "0x0000000000000000000000000000000004988740c0cb624d6228e22704f9dddd8a526775c81506cb9eab96d3be870d4a04", + "0x2aeddc77fe58c98d50bd37f1b90840f96ee5a0b09e7e9a96219dd66f0f74c37e33446753bac3f7d8d49e16d1c4f6a051815c5865058cb218fe7d460fa893907bd0cf8596b493f45a": "0x0000000000000000000000000000000004c21c287be88281cfac16666331518cf2820f4de9c29d7caf15ffb596f12cd953", + "0x2aeddc77fe58c98d50bd37f1b90840f96ee5a0b09e7e9a96219dd66f0f74c37e33f1232919bc79e13a81aea610fd2332295967d1c7846599774a112f2d6cf7e3ebe92392b7b17779": "0x0000000000000000000000000000000004e62bc1402d84b145bae2ce9ac2e50f7f613b7a986734a896af65be8f51244c4e", + "0x2aeddc77fe58c98d50bd37f1b90840f96ee5a0b09e7e9a96219dd66f0f74c37e343126692e3c2e4112d49078cd721faa2f041d0cf96e0d8194561fdcb4ced457270e52f209e76c0f": "0x00000000000000000000000000000000049068a88ce95e5c34122578c16d46855386229be241a7e0656ef469a03db4ee19", + "0x2aeddc77fe58c98d50bd37f1b90840f96ee5a0b09e7e9a96219dd66f0f74c37e34bd1b4448aed1acf00168a3d082a8ccf93945b1f173fdaecc1ce76fc09bbde18423640194be7212": "0x0000000000000000000000000000000078c573b977a12a27f38f686571c67e01b848e24b49fb2ce07b8b0f12caf651b6eeeb14462cbcddfd07593831e6ebb7c4a2e5f0acf8c052f6d76aa550113bb72b688c7afec700f1f0c83226176063f349c34c3b100f192e4bc106c3305c1c5e4c386579df1779da496305c30a43dcdd9277e4984df2b941343e1086706c613db39364f9e43cd95c94ded79fa17bfec8a8d745932f4d7679f8b06aa9e13f915768b252e32efcfa98867081b563878242febcb31531cf4648cc496bbf851f39f31f6d3a5dfb7d614cd20d8ddf555c4a23acef0a71bd8723463f36f89e603211dd99b055e8dea9080f49b00804005fa39712a313dc6bc21c3de49f172b3f46e9f586e4eee6c7b76518ff52ab727047c1214470a0fb4fce60ed6ae06185a1501e9a4ce6bf4221d5348a254fa587bc69297dd25173e89f25220ec395ec495e3df9c41d3b47b5dc76e7833045cd155547da3afa84a1fe6b9f8d8556e8c7187c3b2f50a4675f5013d41624228728182b71bbe799dce7dc5df6963fc02730c6b4b3e84273e1bbce0e01ff970a8d2462a545370e0b992e069db055e417820aeb77e6870f9d0903460b53d4200f03a8183f00d5ed6c971942ddae9065693b4702f0f782e5c553837cd9bff26ac28b84a814643ab00556d90e873a921633bab990cc75b5a06dea8eabb61420c17a6e92eb2ca99f0e2cca15015784552ae332bf2105a592b80dc66ce201e876781c6466468f641ea7defd144b054fd1966e2292bab3c550f8871107598edcb29987227d3fc1d585227937f701af167165fb0a99b6a21983fdba049f3218e31dad244bf47477de316c3f46a721149ce003f4514eedc2042b854e6640619a9305b0571ee5a5666073612190b2035be70b6846a2f16c94e29908d38962d4ad80a2a5cef99de5288c0f299cb7fa7a3e41fb2db1a4c23fa44892be1360c5fd9b06ea650783b1d4ad13841ed6caf054ff5cbe72ec4636fce640bf1ae53bc95dfabf99a55a128f0cc1a12a58cdf161e58872515ee35cf87510536082d53dd69631266f8f9a76413f5f902d59578faf655a0dbf92938ed749fee838c81bd72f9daa984f4b569c43ddfa8b12c3f75e2e02f8c0ce9980e00daec2cb391c74a4055acee05be3352c7d09340c8c6f76c87170f1072bc0ce873e529381c4f5c8a2c6125fdd59c2b545e1032e0223a7ae0e3aa3c4ebbafe72576dec399441068e3c8af704356b5593f79cf9861e3c26748ac8ac6a4c2920582293228f56351d2667016768f8ff56cc85e23810144f87fcaad260080c7547bb6d3c20d0b4929b9d73245fa94cbc6c035f58068a57aee59359d7d464caf058fe55e30623df66dbca94", + "0x2aeddc77fe58c98d50bd37f1b90840f96ee5a0b09e7e9a96219dd66f0f74c37e34cdf837d56a264302302a200a9ead164617576a79dded74ccf9094d6222cdf93ed575422e9f5837": "0x000000000000000000000000000000000408d3e6f92d4020b4a2a6d4dff33fe485f2883070668660980fdc064f12dcc129", + "0x2aeddc77fe58c98d50bd37f1b90840f96ee5a0b09e7e9a96219dd66f0f74c37e3533fb45c1708948625a907225b8ed830c16996d75cda73ef03750b535a6d83ca2ba1246be2dd424": "0x0000000000000000000000000000000010c2e445df84e611e629ded39f69fb3ed7877398ad5ce82ae4028b1cbe997043cb9181d99f43daa05e74f15ff308adb8a4ef121fe4976904813de2e16ac447c3eefc44a7371ac4b798826aa05df8fd3cd5aa1b62f4a1a7cb9c95b7e83e99633a3ee2cd31d823eeedeaf516f7fdcc4c7287e3d23014e76f804b332d7b52571c2a6b", + "0x2aeddc77fe58c98d50bd37f1b90840f96ee5a0b09e7e9a96219dd66f0f74c37e35a390c3506c1387482a9a411b630d2c3f850f435c4566a6a93143422e6cce181320f022a7451236": "0x00000000000000000000000000000000108688b96ed623770a0b2712dd9661b3c1280da83237db214ba698be7783731b122cfde9047614f815e566dec170152a0e9a7b163f94d0a59e8abc4b84dbaa2e6348a9cf978cdd6826ae8be06a8a4c2b5080eba18ed88f5a01cd4db7b947515d71121cb3c0a7a70ec5db8b5e2ba95aa0320ece6b999a593c146471df768adad97e", + "0x2aeddc77fe58c98d50bd37f1b90840f96ee5a0b09e7e9a96219dd66f0f74c37e35c408ac02c2a02dfae63fdb20e3ec7589586b14ea019731b5089e2d1b22a7911e48603a5939780c": "0x0000000000000000000000000000000004fa98b8b13a1b03a3f86748ad19edb237b86ce74b4c4dcc08492907df447f7026", + "0x2aeddc77fe58c98d50bd37f1b90840f96ee5a0b09e7e9a96219dd66f0f74c37e360c398fd5e777baf6d6531d9623034efed118d00dc62831eb6f017dcb45d66ec6af44947ef41431": "0x0000000000000000000000000000000004602d88c1c8aef782a7eba2fc345663405cce57081d4a34003b895057d96d8e42", + "0x2aeddc77fe58c98d50bd37f1b90840f96ee5a0b09e7e9a96219dd66f0f74c37e368ce1bdc40db94c34f589d251903b0ac5a22b1d13d54696fba34b77f5d21f5244de907171144763": "0x000000000000000000000000000000000460bcf3dbbcdcb2254472d74e7522e08b6e35bfab991d39e17c8e35ab634e3c28", + "0x2aeddc77fe58c98d50bd37f1b90840f96ee5a0b09e7e9a96219dd66f0f74c37e36a17a0db79ef688c664fbde2dbcea2d4180fc9e285ac56ecb6f89a9b88cbee9b407bbceea7da912": "0x0000000000000000000000000000000004100a7405e03b712786ff8d6b522fe258843ec33d366eb61379c98aa028bf380c", + "0x2aeddc77fe58c98d50bd37f1b90840f96ee5a0b09e7e9a96219dd66f0f74c37e36becd4b5e8bdbbe828618dad92559461b479508086bc781d88434e5372229cf66ffc887672e9b34": "0x0000000000000000000000000000000008ea17387e7283543fb633e2a9e0f68d39e172cd5624c7095e6d81ad3468f35b701ccd666d5c96fc362fd7fb1633ff09d05b3394ad29e7574e4231f5ab2e0f276c", + "0x2aeddc77fe58c98d50bd37f1b90840f96ee5a0b09e7e9a96219dd66f0f74c37e3753decbc1ae388b6849627c337067117e864eff154c6125539fa6e4eaa980712e7594cf78447874": "0x00000000000000000000000000000000045092144ba4cf9a4997c6dcae1ec2f9b8cd1065ff5d1f97812c5700132036a504", + "0x2aeddc77fe58c98d50bd37f1b90840f96ee5a0b09e7e9a96219dd66f0f74c37e375546d9339430d36aa9e19b08ef554ef0b123940b685c0d64eabd9a1ec487e43bb7e1f3d981c062": "0x00000000000000000000000000000000044ac0609d3d326fa83a76b4e89a445ff2c0e6436b338481041af7500057c870a6", + "0x2aeddc77fe58c98d50bd37f1b90840f96ee5a0b09e7e9a96219dd66f0f74c37e375605537adb7dfd3d6d2d20735ec00c7753d3e6071ad1e2280288a98d7d89c2a2b7fe08bf6d05bd": "0x00000000000000000000000000000000088e2499f22749aef04333796fe92b73c06cf4e358a552604ff3e550725774f924bad66ea053eac162ae6fa88c672a16dc18d932399e7159d0e2ef25c62189e637", + "0x2aeddc77fe58c98d50bd37f1b90840f96ee5a0b09e7e9a96219dd66f0f74c37e378b219e43b8dedff0fd6298e6d06eefc52fb2f12dc1a6ff9e8958ac2a3efebc7f5673dc33808170": "0x0000000000000000000000000000000004b82ba825d0fa34373ebb741509f70042068219d805f221b75330b4513f62e674", + "0x2aeddc77fe58c98d50bd37f1b90840f96ee5a0b09e7e9a96219dd66f0f74c37e37fc013628a8c12f22fff76bb4a0a5d66cff0392dbc083abbac3b3046f6fcc328abf0ddd16ca0837": "0x0000000000000000000000000000000004a63f88c1fbb368cfd13ca5e7a68e16da2e80b94fb382948eea95616685598235", + "0x2aeddc77fe58c98d50bd37f1b90840f96ee5a0b09e7e9a96219dd66f0f74c37e38172c8cfb5a713e5a718199b3c87bd8c24c35f027b2b4ba2789a85782a79cc6a924f9e4241c3005": "0x00000000000000000000000000000000045a718199b3c87bd8c24c35f027b2b4ba2789a85782a79cc6a924f9e4241c3005", + "0x2aeddc77fe58c98d50bd37f1b90840f96ee5a0b09e7e9a96219dd66f0f74c37e383198d18bf4db66169b1ca15010ef10b423afee4c0fca7e42f745b39e1fe4197436ec352b7f1708": "0x00000000000000000000000000000000044c50bd7cf1308738e5758e3f5063ffbacc50d2944f95506b8b4710d1f7a03536", + "0x2aeddc77fe58c98d50bd37f1b90840f96ee5a0b09e7e9a96219dd66f0f74c37e386a2f35e87b835c78283798169eabf7cd6924745cb60df616354b36e53549fd8dd71e815386f525": "0x000000000000000000000000000000000878283798169eabf7cd6924745cb60df616354b36e53549fd8dd71e815386f525b842b822ff26324247b6ac5a4f3eaa2bb97ab63a9ca95c2ff07775a1858f0173", + "0x2aeddc77fe58c98d50bd37f1b90840f96ee5a0b09e7e9a96219dd66f0f74c37e39a60ff17fca37777ec07e354ed4f92abdd5a1570470994410ad04181deb63229bd98ff39b73170a": "0x000000000000000000000000000000000454cbb80bdac7fd85808d631bc4007c2b928e88ef08e8773d7b26e0acce33dd39", + "0x2aeddc77fe58c98d50bd37f1b90840f96ee5a0b09e7e9a96219dd66f0f74c37e3a304428675bf6f7e6247d2909686256b09006b07e758ecc128364a926f1223ef04b38628a5a3a5e": "0x0000000000000000000000000000000008f2382813004a234ea40eacc434ee04b04e52977a2907023a2d2cc44d464120574416405ae9e2ded76e049abaac98028161a04e23bdd02ed40fc9e1e0826ff65e", + "0x2aeddc77fe58c98d50bd37f1b90840f96ee5a0b09e7e9a96219dd66f0f74c37e3b8fa2e75a1b9c5bcea3dabe52b2a665b1e19bf8c6913a5d54e06d6413ca3ddbec8f9a22415ec477": "0x0000000000000000000000000000000018ca5164772b835ac12c7e86d391ec217e65f05be0f43b75a059fdb0b3e8a1c44c54e0103cb355b3f6f357104c4cea54675909f687aa106a4e47d741dfde35e376de4ea9ea77e628210eb1aee0c6816cca8de5235e04a861059b889c6b396fbf15a08ca28409640a6ce8108289d3a279cf6fc3f0657b60f3c41f89d04c0e5fbb2dd06a4dfc33d452ca4fbf37fd660a153b0d87011761701591ed79e5bb875960444cee1a8fd3bca977c086368843e54330002df861543497ac55e3818e4111cc26", + "0x2aeddc77fe58c98d50bd37f1b90840f96ee5a0b09e7e9a96219dd66f0f74c37e3de3c64163d245c278c7e23425c0433a78c7f295bee57069c78743b4630161530af5e6e5ad5a7024": "0x000000000000000000000000000000000c78c7e23425c0433a78c7f295bee57069c78743b4630161530af5e6e5ad5a70246eaa97150a12560dfe00d1cb77f161ab7c29b6243193186f2d02e933c4c4067c46d59d9963c62e1d8f82335ec3768bd5aa4cc268abdd209b779d139d99eca26b", + "0x2aeddc77fe58c98d50bd37f1b90840f96ee5a0b09e7e9a96219dd66f0f74c37e3e3e798a3a6296aaf8d542920fa20b0dd5e126de37f7c0142db98b51a6caa4968922467b42b95a74": "0x0000000000000000000000000000000004739b4e65cbeea7cadf808f0df0154218982008f8cb4ce04a18b89625e69ab6b1", + "0x2aeddc77fe58c98d50bd37f1b90840f96ee5a0b09e7e9a96219dd66f0f74c37e3edfdd48fc779cd5a80ea94af8a39eb7ba8d9afb913147e67eae84f48aad7b9ce6ee05094fe0394e": "0x0000000000000000000000000000000004fd82c8f29cee3c6170e1f21d2d060586e2508f5a3dc977f2f179ed52d33aa923", + "0x2aeddc77fe58c98d50bd37f1b90840f96ee5a0b09e7e9a96219dd66f0f74c37e3ffe32ddffac26d1225c1cf2356a5a5cd7e13c8e5dbee6c4c89e1c5f610c1050131cc58b4d96e75a": "0x00000000000000000000000000000000044ad44dc061d183f5adb794ba6708425fd6a3e1c306152fe63fb22075d1f7347d", + "0x2aeddc77fe58c98d50bd37f1b90840f96ee5a0b09e7e9a96219dd66f0f74c37e411a5418773a1a2568f8bfef657c69a5c34721cbaa618ae9eb2108566f9a2606cf5055578e0c2511": "0x0000000000000000000000000000000008bc154c7a8b77c508d364f2ad31111f48c1eebcd3367da39f5fd907b510e5e170f2395f3e80b47fe6ce9eaf63553371c59c73b403bdc28862c86ab1040e62226a", + "0x2aeddc77fe58c98d50bd37f1b90840f96ee5a0b09e7e9a96219dd66f0f74c37e415252cc5998dac14e516d9d6527c3bdcc45105195b8e23480bc0f257308b1f4fef03e06efbb1c5b": "0x000000000000000000000000000000000484993faa382230fb6bae24747cb90b01087b26817950513c4b313168b517950a", + "0x2aeddc77fe58c98d50bd37f1b90840f96ee5a0b09e7e9a96219dd66f0f74c37e4229207fadf4b0c2366c1d734b33c714b0e0e9f164426e66e3bfa97b917b23e5d3674f4a2074f86f": "0x0000000000000000000000000000000008b2fde580d330e81fd2b163a77bf1797f3fd19e98099fec1bbe33217c7f18b77d74047a9abeb7a65811ffaf6ce18a99cb02e092d317eead7302b23e5b99ef3c14", + "0x2aeddc77fe58c98d50bd37f1b90840f96ee5a0b09e7e9a96219dd66f0f74c37e42946832d384cb2c5e1eb942e5f591bc1d902fc6a04dd7ecadf5f4916f2597df0505c6c521412c4b": "0x00000000000000000000000000000000208a650412c92229bf1a2eb1c0cab9c133d54c5b82cc723b202ee634e925effa6a3c6d21b257bbfa6eaef65227c3ca8f934d4df946f53f65aee505dfa6b741c852fc1855c2c5d97b41f55fd7b122cabeb3c2529f1e27dd836d131e88f5d6a66a09faca0437ebd16050e22dffe85c091c5a8e24feb20d488444e9b9e7e7cbc78013f227ec6d922254e93c2342a87fe0840cecfa015478fc5ae7b28bb18c66c3a70de8b27a414bbf2ca10db6202c922e1d33359b65c8d4967fc76f926d93f54dd9165c05d424a33d6e9ac92c3863c26aec3515226a439192e9fb28dd47db38dff05fc6645597fb2f300ac88b96e8283b06d99319905bc509151e03dc83748708197e", + "0x2aeddc77fe58c98d50bd37f1b90840f96ee5a0b09e7e9a96219dd66f0f74c37e42ade399737c4384882a9309f1e5f87abb745dc51d5dcc338e3dbe7b818fd8a9768e27d97e57ec13": "0x0000000000000000000000000000000004d296d443e8532e4977e9d78145f6ec9eadbec4fd2b10158e82985549046fe568", + "0x2aeddc77fe58c98d50bd37f1b90840f96ee5a0b09e7e9a96219dd66f0f74c37e42b0e5e788b77418280221db3cd2515ba48cff6c400cf4624b9459eca62f30523972ee5b608e967b": "0x0000000000000000000000000000000004005e13effb82cec8d1e3de31eefc750ea3afb8df4ee1ffc18a66cf56ae4fe178", + "0x2aeddc77fe58c98d50bd37f1b90840f96ee5a0b09e7e9a96219dd66f0f74c37e42f7186af73e2c106edfd181c979c11a1d853c8fdef7b18e85ec39bb67ce723130b25fc24232c358": "0x0000000000000000000000000000000004acd510542672c65c7c05d56c4c6424a70a0e426f3899f2eb86751cc2e08ef124", + "0x2aeddc77fe58c98d50bd37f1b90840f96ee5a0b09e7e9a96219dd66f0f74c37e4315c981ebc9c224e49a94c01d7c0511480422e00ef7030ff64f314591b50d7057deadbd6411112e": "0x0000000000000000000000000000000008fa6bd8e8fcf8cd5be5d5cf808b5b5cb20aeaf43d7cf5551f1b33b0f029120016ea595939a7255c7eac3f67f54c75929152fb73018a56bb468445373c17200447", + "0x2aeddc77fe58c98d50bd37f1b90840f96ee5a0b09e7e9a96219dd66f0f74c37e43bb1018fc2bff6592536c5469fd64b2adaee0a10c5936bb0d4c8e4c5e4d31185fbc0c9136e1f205": "0x0000000000000000000000000000000004d7a15c23db646cb253f769875604c28b184a2487b5dff9c282bd65087e7b4238", + "0x2aeddc77fe58c98d50bd37f1b90840f96ee5a0b09e7e9a96219dd66f0f74c37e443ad277a8dbe9aba845ea35913a0fbdec49687ebc5b1579bb632c080ce61b02919ba40bcf889276": "0x000000000000000000000000000000000cb4105912d0268f239b12bfa0aaa290903ccbb52e0ad2126b73a4b20c9189bd1bfca8ea3766270fe9df1ba7a4a7298a908878ed61581b9769100fbdd4164b00607282bd520ed3b58e948d1e3ec6d993c607c87f153a9b90954fa973cdf3adfc54", + "0x2aeddc77fe58c98d50bd37f1b90840f96ee5a0b09e7e9a96219dd66f0f74c37e44509eb7f7220ceaeebbde3ff2bb37ca11414154e92c0521ac8051ea48d0d84b39714b2347763648": "0x000000000000000000000000000000001072795595ce1298481aeca61391ee534ab7955411342e091fcb079401a784d438d6bacc09599d6647899ed6734cc33a655c56e6bf08d2273ba8464eb1d4a0830b6e5b9e2cbd37299c34a07fe45c6f143aa715e1bfccc4db8c82814dd82a0aa35cfe41a0fab97ce06654fe9813a999a9d6dfb51bc7ab1f35dbbb27bbb3eac4c164", + "0x2aeddc77fe58c98d50bd37f1b90840f96ee5a0b09e7e9a96219dd66f0f74c37e44555228869870c2e666c8204234e3e9dc671cc875c4f22316e6a7b67bb8b0538d8d77674468ed50": "0x000000000000000000000000000000000406419ac9e6a0b6d955fc0274eb9911fddac424b804fa29062ea417f05d64803f", + "0x2aeddc77fe58c98d50bd37f1b90840f96ee5a0b09e7e9a96219dd66f0f74c37e4456b32654fe47f91a8ab26aba64d6176b6aa462a2a7ef6252ca1063cf978dcb6f6c64fec81e7861": "0x00000000000000000000000000000000082ed9d00721b2fe294f0f2af432a1a2d98a45cf3d6db2939ae20f5bf25625ecf8148abf367d1fcc88ac026490727eccbeb507e35714b327c4a3dbe404622184b2", + "0x2aeddc77fe58c98d50bd37f1b90840f96ee5a0b09e7e9a96219dd66f0f74c37e44a4a90b1106c3b5aed98e15e3ed392e38654215c3d1fa8143de53460386b60139fbb45c036c1b43": "0x00000000000000000000000000000000a078018b68f1983978069a54f1befb11b0702529b1cb9bb0163999d9bbeb85391f5c97521b3cb9261f89f6b05b6ad17e9d148ba5f2cc03daabbfff35e0bc2e3f0f54ec418763624a46b49693114ba91a0137b37c1e47cc3fdcb2db75c9c4b11c795058c8963e2b60c6f1e6c921a3893414f370b48ad0c2d2d937c7786febb29003329a36786940b598924622428c95d5c41812d55b9ea2f091ad99b2fbc944331df0825186ee2e14875b4da41144acdac7d5aeeda144951b84cb93c5b62388dd57ce304677ff08c2d76d65ad5bc3adacb74b685907cdf72fe0f155c31dc4c8b0472ec9fc5a5358c74ffff03b8712e8dd1e50e93ca0babd01dff5de303a64f07f3a5c975241098f4ce19cd95187485c1b0006584a560c101890f32d65a67e787700fa6c823ba7c33395d2f298934f304b44af030504cf1af0f1a3f29c78442e07508805b2b3d962de88736fcbcccefb08f9915ad1ddab9d1e31782954ef1ea3e622305b166a309fbb4a05d24e70b726218dbb1b5d3e8d4e1488524481032e0acb00041eda8cf4ea9ed59862c6f5ad3a51e7ef62eff19b629cb241a10d5fd7f96d22305b1686b3030de938cfe6a01467a664fd1b42e4f43fab7295963640c5128a7b305b166542492b1615c15fb92c573ee387b90427312d08338b9c211b85a27a20cca9c8d2749a01cf11872c61580b40f227d566afedd3b40cd29849276414c350b8d56768e91cbccbdf754d7f60db1fedd96eae27b591e65d2fc8afb99b27c20b5c97523e781c4c65e7df12bcab25d2f3ad96a2e73c9252da3b889bcf77aecc5a9c9d52f08adf4aa10b316922daa16d396cfb66bf6d3b87454d7a468e19060f683c84672d8f0f25ceea258d980ca234e25ac03cf2d78f925340ce77237844147c88d38deed3dd10c90cab2c1a5b59040baa3c1742b2439d6c4ac83df7da5d894e5c975240a88ac1dc2d87fb2de37a5d8759307dd7cc9281114515ca26876f530b305b1665aadfdadf6d13f6c8eb36db7e3868ba648e86bdb7d60f23677ea6b33788d38dd7b7e450c426b33bd49db5efe92e702e0c799a5adab42be4fb21ed756688d38e0b14f3b08bed993ea4fe1b8ab124190191340fe8de0466ea642fd56511041eda8a25068f57f573d5b152e2c8947c7ab80dead270769184cf63c77af554305b1689cfee594c19a642a2fcd554074c93d62181c0d4117ebe196bd7c62b795c9752253a165c2eccaa4dd8644eb754e3c760f586e935efbdd7c3b629cc06425c975241672d5275044da23dcd085d64949b82c83e963a2bae2230af259f527c5c9752508d09c36f243da599f0e850f3bea8f0cf5c43eaefa73bd9c6a075750bdcadf01d571672f755b4032af1cfa3784d389da711ea341209b86f840784937a88d38df37c92f9cee029f6290428a9848f70dd8f10d519a6c8a861101863cd40041edab68d8fa56e9c4845bb931beb45b2e457162753e65c440d11f83cc828715c975226ca9eedc6f15bb8f513c0fe5a3e813c4ea2fce105febce11d5b89ff01605cefe161fa9cb1c1649080f78f9cf7943320746e75dbb4b1cbdabbbd6a6638204c52b467988d585dd9cb7cebc94d6e56d8b89042ee692b5739f7d78c39a5545ed6723c4d9632bd0c61bf182c0904ae64fe1dde3f5f1ffc532d41fa14e2840588d38ddf4d661801a1ab2efe073a9f35e0acd5c3c896aa28d8b5b20e2e88436e5c97523bb1c1be25aad6bfb7a52d7e1a55fab08a78c2099daf42951adf7133535c97524a02c01e505359a29988f9098c6b1034dcb3ed8af5873fac659a10763c", + "0x2aeddc77fe58c98d50bd37f1b90840f96ee5a0b09e7e9a96219dd66f0f74c37e44f53fc133ec6c80a0d32bc7ae5d421990bdb847fc38cade9b388ce8138ab4e4ae957fc7ca59bd2c": "0x000000000000000000000000000000000488bc16ce9ffb289186e900a2c7bafd486c3ac4c2c612497a5bf14f8aa2dcdb09", + "0x2aeddc77fe58c98d50bd37f1b90840f96ee5a0b09e7e9a96219dd66f0f74c37e453efa586e0ab504d20f2ce6c2c876745bbb399c6290cf4e3ee75ce31bbc7ec11342fd5118b98e3c": "0x00000000000000000000000000000000042c249c9b361d3c490f66848e4ad2fe71438455108b3a1f0698160c6d1d27fb24", + "0x2aeddc77fe58c98d50bd37f1b90840f96ee5a0b09e7e9a96219dd66f0f74c37e458263f3dd29a31aca42f0b5c7957571706f29d2828291b148b4b162100ddcac72c507fd8ab69b2e": "0x0000000000000000000000000000000008766ebc87370f898dd73004e524f0019b36a511b071efcc5f685cd935cd6ac57ae2623f940ce24961b8e483b3b00c94e84fd32a5f13a67a09ef5a19d28af59435", + "0x2aeddc77fe58c98d50bd37f1b90840f96ee5a0b09e7e9a96219dd66f0f74c37e459cc19119e455ad94b3d04ef219a8970ac5f76658fdee1005b4b7ffee3fc02355f60db1a778f826": "0x00000000000000000000000000000000048c216c3e8fe71b422c34003bcb536257a3ef17928e93792f8d8de4748b81446a", + "0x2aeddc77fe58c98d50bd37f1b90840f96ee5a0b09e7e9a96219dd66f0f74c37e45be453e8a7bff0f1c7376c9f2afef25e542556d2af805dfa691a414efb9e0fc9a8e33f625294f67": "0x000000000000000000000000000000000440e30e1462871a4a8a38dbf705b96b986d699b62ed53e890b8f42544e3bd7b38", + "0x2aeddc77fe58c98d50bd37f1b90840f96ee5a0b09e7e9a96219dd66f0f74c37e45d43cb8401e3564f40cd7a2181289e32776625b9f3a193f749e33ce1bdeb76cfaabece606c7324c": "0x00000000000000000000000000000000046cfe88656d6a99bbf56d216614a02ef9f0182f63dfc21d7dfedacb4ff517f135", + "0x2aeddc77fe58c98d50bd37f1b90840f96ee5a0b09e7e9a96219dd66f0f74c37e46374d36cdcac1f68e28e91f200ae0e50fec4354a429a7e4e00f684f594a33437dff6e8c4ed18053": "0x0000000000000000000000000000000004759dc44004f91bfe44588e84d9c60517627929b322b7d00b8979035c3fc0be87", + "0x2aeddc77fe58c98d50bd37f1b90840f96ee5a0b09e7e9a96219dd66f0f74c37e4642619111762c48be1c7627fbc96a38d3a3cf746ae545f60e2510ed80961537d9b4924421fbb562": "0x00000000000000000000000000000000041d3635e81c3048b1b2459aefff519b68d0100710ff64578709ca3da808412054", + "0x2aeddc77fe58c98d50bd37f1b90840f96ee5a0b09e7e9a96219dd66f0f74c37e46b931982fa83f40c009ab06d6b49cd62f2801c4b0029a5343c51747f6716c788780bfeb2730af66": "0x0000000000000000000000000000000008c009ab06d6b49cd62f2801c4b0029a5343c51747f6716c788780bfeb2730af66ce26c4cd5d39e3dec824a79059cf0746e3aaed0821017aa493da14687d5e550b", + "0x2aeddc77fe58c98d50bd37f1b90840f96ee5a0b09e7e9a96219dd66f0f74c37e46fa647d7b60b7824ef63a0f97791221290fd19207cbb23ec5783221b5016afa55161b01dbb0125d": "0x0000000000000000000000000000000004ef8d3f3e96613631bf0c63444db7abcc063f40cfcd2f4b477615443fb8e84d5f", + "0x2aeddc77fe58c98d50bd37f1b90840f96ee5a0b09e7e9a96219dd66f0f74c37e47bedb9f0d77b46d6883b9f834076b9c1368e7692ec0a01ae97a52c5cdca957b5d31103423cfbe45": "0x000000000000000000000000000000000820d879dee526c91e9a590785b4982690fc4a04d41fb7e49c83389e6848132b0d0e794356479178e2d043755c671a3db6b1882700744cc0f570a84fd33e257e26", + "0x2aeddc77fe58c98d50bd37f1b90840f96ee5a0b09e7e9a96219dd66f0f74c37e484f9e39f4f0e8475cce1eed57740222d643b9c92a594bec58f9b9968bfd4d63d495a7fe5237ab1e": "0x000000000000000000000000000000000488c83f9b6b21778914870c7fd18ce9b3b44831ca8706611d6b2fec736a5ecc4e", + "0x2aeddc77fe58c98d50bd37f1b90840f96ee5a0b09e7e9a96219dd66f0f74c37e489667186afa0e91ca5bc1915da74aba3aadd7ce7b809045d5eb5b73559259755fdcd85a40a5dc6e": "0x00000000000000000000000000000000049f7951a3a51ead847837ceb367ad2166b0dd1411c860fb01cf7ce94cad08022e", + "0x2aeddc77fe58c98d50bd37f1b90840f96ee5a0b09e7e9a96219dd66f0f74c37e4900c2cf5eb1d4d5dce117ad72d855b586a1c7ab1e2e1400b00418037000a81a26d131eff8486b77": "0x0000000000000000000000000000000004027d4770a8fb3ee70bb1d12b64f93c794dae984ed5e991267c7e776c77470f5a", + "0x2aeddc77fe58c98d50bd37f1b90840f96ee5a0b09e7e9a96219dd66f0f74c37e494a0eac89f0ff78c63b6d81d7d307b9f4464304330a840f5159c78a804dd344c5fcbfb3da9aad11": "0x0000000000000000000000000000000004d693e6d764ce80662d891b0e1496fc7afdfd3470eeb4d703ce721460bb459d6b", + "0x2aeddc77fe58c98d50bd37f1b90840f96ee5a0b09e7e9a96219dd66f0f74c37e49577d51da67dbbadc86d7e1dba377a90f087a942c0c2777851b447a16af68cfac09c2e58ecf7e1d": "0x00000000000000000000000000000000082ec6d11607a14dd26f32576e47831719d548c856ce4c188091790cd93ba826061ae31e3543602bdd7fe69218e5c8d16c782f96969e2f7e323ec5096ffb294e44", + "0x2aeddc77fe58c98d50bd37f1b90840f96ee5a0b09e7e9a96219dd66f0f74c37e4997fd81d8f83eff7294d22dea735215a7ac4a2aee260eb25d1beaad4b02bd8dacf87bd611a96c3f": "0x00000000000000000000000000000000047294d22dea735215a7ac4a2aee260eb25d1beaad4b02bd8dacf87bd611a96c3f", + "0x2aeddc77fe58c98d50bd37f1b90840f96ee5a0b09e7e9a96219dd66f0f74c37e4b290c17b4e25a4a36e132f4b16bd325ddb6a3c63562f23c18dfd20bb2c785d391f625f481097c1f": "0x000000000000000000000000000000000432e223d306f0e5bb9a9d6dcc9023ef06edc7717db691cd8c5d85d33b3a1fb136", + "0x2aeddc77fe58c98d50bd37f1b90840f96ee5a0b09e7e9a96219dd66f0f74c37e4b5632672e4e08b2e2fec50feac8a6c83a3e9f869ce04ab800420b2c80c4310f2de2e9f0adfa301d": "0x0000000000000000000000000000000004764e2315d026e1e02073b27ae98b6866388a0208294c4ca8e4d70e25f4ddbf18", + "0x2aeddc77fe58c98d50bd37f1b90840f96ee5a0b09e7e9a96219dd66f0f74c37e4b9d785f0afee887423e5d0451428d77e1f81f6f20c87427e355468da3ac8eea9eee7f041871a733": "0x00000000000000000000000000000000046aa3fa5a328b8a928c0aedc22aa88d14e807d2552c31bda8b23f3ac2cf01565e", + "0x2aeddc77fe58c98d50bd37f1b90840f96ee5a0b09e7e9a96219dd66f0f74c37e4bbfbd1503dacab9f01c087c4a752cbf56ae4672f910acad4b234a830818356b8378afcd8e042360": "0x00000000000000000000000000000000180e46029cb6daf09d2408e111ffb14010387ffbe77b16539839cbff1473a3a4023051ea9c01a7134f6a3223ea95a09c4dfe0bde5b0eb9ff7169fdb85d7a9bbd73a61a8e0ccd37645a2dd65916d9bcf3b77ecdf395ecc3beef72f3ad5565bb3353dea318de2228da64b91c671dd7f325df63959f9c51c86a36f28ec94126f320709e992661473c1dc00ad7f67b734bec003561ebddbb7fe0db3759b717ad20fd2546591c7794e2cb60b8a342f82bf14b2cfea945671453f92e330917366ed5f946", + "0x2aeddc77fe58c98d50bd37f1b90840f96ee5a0b09e7e9a96219dd66f0f74c37e4bc05de7e42ebb50ceeccdb6802df2253998f9d4f928b120d51110d1d2afd969b95232bc16768702": "0x0000000000000000000000000000000004ecfd5be6a880094d44062af80777e61f10e15d6a8910cf7222bb10dcff874eca", + "0x2aeddc77fe58c98d50bd37f1b90840f96ee5a0b09e7e9a96219dd66f0f74c37e4d35c327c115f99b08745476e8a2fb16504c77a75b2dd20b6f56cfb71c87125f1707a702753af24e": "0x00000000000000000000000000000000049dfee84695666c414061c119c231b91511e18267044792868388c73f59306474", + "0x2aeddc77fe58c98d50bd37f1b90840f96ee5a0b09e7e9a96219dd66f0f74c37e4d699313bc760a036a81f13352076dce1dfe8f357fd805bbece6ec16efabad52a2c24e6824e16315": "0x000000000000000000000000000000000495d056d702a9431c14cc2c46634fcb656e162dca4b5a2100789373a07695f6b8", + "0x2aeddc77fe58c98d50bd37f1b90840f96ee5a0b09e7e9a96219dd66f0f74c37e4e0e08d8f728b4dd32068fb3b800c5df40df16619761b3418e40d9455784b6a293d2425e35ef2c27": "0x0000000000000000000000000000000008831b9437615fae78c29e32df5b9ca228b4e9b4b31eccc8c090834cf6a85c8e29196375cde4e10495687128f72d513b94bc323bbe7dc36f305133ad7cea4c6da8", + "0x2aeddc77fe58c98d50bd37f1b90840f96ee5a0b09e7e9a96219dd66f0f74c37e4ed12f7f95496d053674aa73951219dbd27b3e3fc5847b806c68c1de38fd4f22f9493a461c80e903": "0x000000000000000000000000000000000cd0accc7028daefa6de2f047e4650d3ad13d5e25bb0bf2fae4eb8ff8e216749199e62629f1f1b6e219c95d80577ba4215ffeee870b4c6f6672e2191bbc3a4b7502415e5310193e362840035d0283a5911d358c1553afeabd87ea4d66d35351128", + "0x2aeddc77fe58c98d50bd37f1b90840f96ee5a0b09e7e9a96219dd66f0f74c37e4f133aa79b057d66fef5977196fe3fe5c456a767e6b06013ca62762b282de97040add4ad2c53db61": "0x000000000000000000000000000000001040ffc76cc196faba27d81c0c8925911628bea264b949bff7a26edc041bfce66af8f71fd7d5dbabcdf5a640f194881f3f16c13e2bc18e54cacd08dd60fba0907ce00e404cb030e7bfb50b9615ea9a2f8f75601ac9f6128d1263a7fb5d22de741bdeb6ff39e56549c7a265ac798934d66b541c41c2e2212c34bd76b29635b4cd23", + "0x2aeddc77fe58c98d50bd37f1b90840f96ee5a0b09e7e9a96219dd66f0f74c37e4fc324df3bb6d99258bb56063a47ee6e4a4d0bfe444682394a1e4657fa39f4622f2a0285689c1b3c": "0x00000000000000000000000000000000043b839ff2a9cba91f5d0a511651c76f3ae7e0eb8bc76d7862338f987e506ba6de", + "0x2aeddc77fe58c98d50bd37f1b90840f96ee5a0b09e7e9a96219dd66f0f74c37e50004b04910a1297929aa2bfe7b52500b288c943b7c24a90928cd8a6f7ec8eec44763d9f74198401": "0x0000000000000000000000000000000004f2b7e775b59951428fefeac1c8f7f40b24103e02315552065e37d58ea80c7d77", + "0x2aeddc77fe58c98d50bd37f1b90840f96ee5a0b09e7e9a96219dd66f0f74c37e50079469344a3846844f55022b2b8667129c167068a9c2a6bc292f2d312336bd98339d686b575a1b": "0x00000000000000000000000000000000043e8086aa5e41114ace08f4330aa4d5adca61f5dab191bba7ab6b2596f1c40c18", + "0x2aeddc77fe58c98d50bd37f1b90840f96ee5a0b09e7e9a96219dd66f0f74c37e5151486ca217f604d23f678af47c89d76031edc91e43784bcf9991b131f957d312fced2c5187fb47": "0x000000000000000000000000000000000450e1946cc920aa86edf541dcd4bc35efbf4b28671b87c68b5abfb22f655de453", + "0x2aeddc77fe58c98d50bd37f1b90840f96ee5a0b09e7e9a96219dd66f0f74c37e51db8a617be61c665e0a4ca74bbb4da39c79954e7875519fa67049795c02a360412f3ee41a020506": "0x00000000000000000000000000000000049406aac741b57c529a2b06b06124a2a9b8f8374e072e4b251b13a5c0cc9f617e", + "0x2aeddc77fe58c98d50bd37f1b90840f96ee5a0b09e7e9a96219dd66f0f74c37e5296f5f3e605a0e3e8b2603f6baee5bc32a9b9e4eee9168499fa553d35edb56aef0035ff7e1f165e": "0x000000000000000000000000000000001070d7ff9f5cd0e46762d7d7d1c8dc840a4026755fe13c51237ff8601377d4fba36964958c102b007555e5fbd10a3f98ee67fb2bc270fa0d20fe2371916450079b86929ec01fdfdecf2c5ad0c4f9b537e65084f053980fa1215fb9377dc325f52d06b430745802c7c8d5cb3537dde6dda1c74dd2251837c781be4e0aebfde8d673", + "0x2aeddc77fe58c98d50bd37f1b90840f96ee5a0b09e7e9a96219dd66f0f74c37e5361b1ae059eb11e0650a2e41ea97b60bbd3f87aa30d605562069075deaaf79559959230928a2487": "0x0000000000000000000000000000000008463fb9341e83f58071dffd0feb3915815e4f7055c74f0e4ac002214cf06d6588fc46341527cd1a52b60dd5884d8ac5aa272c27cd3b3cc6750ffa51ffe6b34ab6", + "0x2aeddc77fe58c98d50bd37f1b90840f96ee5a0b09e7e9a96219dd66f0f74c37e5439cf6aa71671f74608fc7527698d3f4d4cfcc6074f01c2ed59112ad670dd5206b3658bbb62a073": "0x00000000000000000000000000000000042aac721ff23bb9448f8ddec8ecd159961a23f604f8fd22d729c3390e9f36f843", + "0x2aeddc77fe58c98d50bd37f1b90840f96ee5a0b09e7e9a96219dd66f0f74c37e5579d397caf9629d608aa0febae80d8c228709183cf997bc87b0aa219cda0928408df22ac7ffef39": "0x0000000000000000000000000000000004bcf0343edbf88dbd0b2d302af4a027cf7a1b45be2fbed9e9b11b6bb6bcc426b6", + "0x2aeddc77fe58c98d50bd37f1b90840f96ee5a0b09e7e9a96219dd66f0f74c37e562122059d1dbce57ca460cc927a04fbc91f4ddda54149556d1a85196bc753d054aca1fb7621e349": "0x0000000000000000000000000000000004027b1e50e1acb6c1ff8777599be3350bbbd0236fd3866c367f420393d3adee41", + "0x2aeddc77fe58c98d50bd37f1b90840f96ee5a0b09e7e9a96219dd66f0f74c37e567dc72806fd2ef9d453b6e497b6a89979fb34eea715720d37c2381c8c51458be04296fd059dcc3a": "0x00000000000000000000000000000000086ca5cd252f0f61e8a9c5eb72ad6d9452fcc1de451f7bcffe04cee9ce73c8ff0f402d50604742f5071645e00cf27f318d0a0fa805bda1daeec21e11ff9387e923", + "0x2aeddc77fe58c98d50bd37f1b90840f96ee5a0b09e7e9a96219dd66f0f74c37e56cebd3283e0ea933a3884dbc6806e8b4cccbf2c407d800c12141c3d7cacde442a649a6a2822ac17": "0x0000000000000000000000000000000004f49bb2abd8dd96beaca34bd5bfb81b5edb5186922b92c3b1f5977cc401b79554", + "0x2aeddc77fe58c98d50bd37f1b90840f96ee5a0b09e7e9a96219dd66f0f74c37e5786fc402111e82d5202845d849d9eb6a7e5a414492a86d205be4a374ede34e98fc2440de4809a3e": "0x0000000000000000000000000000000004d6945be0cef12df3e9d25d4bfed7c4f6fbe980487ccdcf13891998454d4c7d3c", + "0x2aeddc77fe58c98d50bd37f1b90840f96ee5a0b09e7e9a96219dd66f0f74c37e57b1fed518565181aaa635f88e75ad58af28925d0c21a804d87a449469e45970c3a52f57aba7b366": "0x00000000000000000000000000000000046a3770dc90105517476a48c8280337f2c1e39dba204c254f7bb51c8d4ebb435a", + "0x2aeddc77fe58c98d50bd37f1b90840f96ee5a0b09e7e9a96219dd66f0f74c37e57c41eaef46fdefb2ca8e96b721f074e95a3f7d994c370dab688fc85134de7e2e7d4589d0a306c51": "0x00000000000000000000000000000000088e4ac154f73a0576603db7786e98d6a1db1e72e3a2b32d2540828395dbd3f7d786d678feab565ecb54f78dcca7036db237002aa86783283b8721de7611d7fab2", + "0x2aeddc77fe58c98d50bd37f1b90840f96ee5a0b09e7e9a96219dd66f0f74c37e57e0f36f0fe2bdee54efb33a98824d6330a8f074481df98b5123305473559bef960180791f849252": "0x000000000000000000000000000000000492a409f971d4db36b2d2d520adc5ea15c5ac9c012d22e4e551552d250aaae57d", + "0x2aeddc77fe58c98d50bd37f1b90840f96ee5a0b09e7e9a96219dd66f0f74c37e57f4780677cf709b4ec0381e4427ed6567f7a5c328288ced36c33becea6ececd8145001f4230ac1b": "0x0000000000000000000000000000000004564491c88a293f54f2fe2cc09b0ec63f226bc77ebf6df8f998fbc7551d0fa10a", + "0x2aeddc77fe58c98d50bd37f1b90840f96ee5a0b09e7e9a96219dd66f0f74c37e585c0f93d15e98cb42f3c525c66f2a4eacfa88479f7537670d2e1f45f4ec25703a111f5f003ba15d": "0x0000000000000000000000000000000004fe57cc05a0401fad57f17da9b903ef6d679b4d16c107a89f7a8c3da798d10919", + "0x2aeddc77fe58c98d50bd37f1b90840f96ee5a0b09e7e9a96219dd66f0f74c37e5879c1214022b88dc8566f6d3669729e877cd5e453d59f6be01ae6f31b7a9c9925160e70072f7242": "0x000000000000000000000000000000000434a2536cdfc1e92e55a4f4c1310aa2cb76257a87b0e66cea1f2d392c7080be22", + "0x2aeddc77fe58c98d50bd37f1b90840f96ee5a0b09e7e9a96219dd66f0f74c37e587c6bbae1bb420cf2d0eed0f21b82d4b15802153cde2a229f257f01d003694b2973ef785a734766": "0x0000000000000000000000000000000004603ebd73cf850b644af5650cc070cf1328601427c712b21aa9746609de2ad447", + "0x2aeddc77fe58c98d50bd37f1b90840f96ee5a0b09e7e9a96219dd66f0f74c37e58d8557741d41ae44e4ac8070fea95496b63cdcb6987de88f63dc75a295eace6ce5079149169300c": "0x00000000000000000000000000000000040879c078b9026ffc8f5b7ca4f1af1ff0f51c592958f24b43ea5433a34f0cac02", + "0x2aeddc77fe58c98d50bd37f1b90840f96ee5a0b09e7e9a96219dd66f0f74c37e5a5afe08a0a9de9ed6aadb9a7f66a45224f6f83011f854c0b5758c626b213f97cbffded94830507d": "0x00000000000000000000000000000000186817038f23e3b1e7d91f641929205495b7be633fc2247d0bcc5a6f9709a8f82d68c1fc61924efb992b4e4c2c7a21d528dca21d3073fd304f536fd99a5cf1794a6d6f646c70792f6e6f706c73014d0000000000000000000000000000000000006d6f646c70792f6e6f706c73004d0000000000000000000000000000000000006d6f646c70792f6e6f706c7301630000000000000000000000000000000000006d6f646c70792f6e6f706c730063000000000000000000000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f96ee5a0b09e7e9a96219dd66f0f74c37e5acf1d24617d25ba6a88b4d1ab30ab4708521d6c6d480a858d92692c0b0cff67e1a6904e23b84112": "0x00000000000000000000000000000000041253640274e26277dde50bc1d72ed0b3f627e4c6b66d8343d4c52ae97afd0f03", + "0x2aeddc77fe58c98d50bd37f1b90840f96ee5a0b09e7e9a96219dd66f0f74c37e5af3c641a81d6a63eaacc14e67deba7935dc28c86bb8b6bdb64239065b718fed6b8691ce14163350": "0x00000000000000000000000000000000042c01bce1cfd949c169cf6d216d5c446a8c947147b5b7f128b6a46dfe92f90f00", + "0x2aeddc77fe58c98d50bd37f1b90840f96ee5a0b09e7e9a96219dd66f0f74c37e5b4c4e58d29949859a2cb674ea2f4866664769a1663fd6aa321d9cfb89b67c402c881891700c0f57": "0x0000000000000000000000000000000008801df817f435be03321e6a77b0fab3183b9716117accc0f3db95c9f6f9434954e04176c772d8e5b3758231c8155b2265e9522e5047b15f388a23cc707767923e", + "0x2aeddc77fe58c98d50bd37f1b90840f96ee5a0b09e7e9a96219dd66f0f74c37e5be79f90404ad9e0e4a66ee66171e3238670377bc9ffbd7cb4bda47baf25e6ed80c2070942ee3f72": "0x0000000000000000000000000000000010808652b2296e43e858df65b69d5a3942ba76744dd8d0cf390ecdefc89b3a553bf4243300b12f9067d1fcf01c8e05f598ec2dfaa142a33398177f8b6e32ecfb2f8e602e63afb364ac583747b0a8bab092d5b20ee98f0495ce7562a8c992ac9f175213e3c8881ed30ead22d177f5c25c4cb8bf46cf2d04a8ce55ddbc06118a9516", + "0x2aeddc77fe58c98d50bd37f1b90840f96ee5a0b09e7e9a96219dd66f0f74c37e5d3dec38e02e37251c6d8b40be9990c19e993d238e6e3613cfc6cbc51979d5fa61dd6ea259385609": "0x00000000000000000000000000000000402889d414f8bb29201637b8ae394fd131642a3eb4764a82730e494d6e60a6c4bc36ed432555d82a6fe15f2517dc871f1d02c72d8d5aa1bce703288d180ff1fdf6be86d32d322797f67dd5d386d29d8285cb32504a767956fc58ed8f04ff703c4a44d50e5b2db8b483e5731d39c1e71f33d6ab32318c144f5dc41e57d1d21ee779860a5fb3fb398d56fe3180ba927cc0f0c9308cac7f6af98d4fc7624627343c4aa243baa53ed09e1a0a8879b132121047f10b53b52b4e8111292a196a1513673745276fb671d5e24c15c73f6766680b83e94bd709644fec1d5829f1126ef1fc2a88508e0d4bb18e50ed1435a4260541b1c53ed009a64801727c195d1f81c08fdac48166c755e708cb83a61db9dc635e91cb496e2659e07fde8aeb09130802010e6a1241c7ef9541ddaad26287d92df0abacf7ac4a7fc4df046e4b866c05db4aabf657af299a3b7d16d7c4d27876099924e5905d4d85d683988726e31b25037cb612cc166f2df9f0fe89f79e2b568a6e92d61ca5f5f53050ef8744edf74aced0fb49820d872869c2370f72f871556e9584aeefb7b7de62e6559c69f1503cbdb545594e4ff12db88b9c74fecc23b4a9bb35e999a5c9a6424ec47f3e0f5529fb655e7c49a3654ea5a5313645948de60749792de736cb3870da7b401e78734eac3b60679d98218b5d055c770d3a2a406e2e56a97083100bec05cb83f530632dc8c313", + "0x2aeddc77fe58c98d50bd37f1b90840f96ee5a0b09e7e9a96219dd66f0f74c37e5de66fa01fb4c2d708b3b1930f36bf7fa336c7abc044e75fea45cf1c903081e7e0bfbd664a80093a": "0x0000000000000000000000000000000004c94a444165f95b45857e4bf1c4b0f784eb2e6f16054a87dce443de41c6d09c1c", + "0x2aeddc77fe58c98d50bd37f1b90840f96ee5a0b09e7e9a96219dd66f0f74c37e5e25f5c22e4254863073c378b0833da59cda1d49d711f37c9ae20ed30dc3dbb842ead63dde578331": "0x00000000000000000000000000000000046a7db4fd5d907242e97c2db57fa12f1eff6a103556f8e99f916483ac6674c372", + "0x2aeddc77fe58c98d50bd37f1b90840f96ee5a0b09e7e9a96219dd66f0f74c37e5ee8405cff42241194339db8b404ea216d60433f00ed67b0cdcd9e29d21355615d967161db0cb04c": "0x000000000000000000000000000000000414b04bcc309f1abd5fae50084923f7d14fc5b9eaf257c0e2c5dafcd83e3cb363", + "0x2aeddc77fe58c98d50bd37f1b90840f96ee5a0b09e7e9a96219dd66f0f74c37e5f1b8b6e45fb190ccca9cb5657907dcb0bb01d335b17564e77994536edd05ddd50524a9355c2221e": "0x00000000000000000000000000000000046eb0bb735fa04cc282b87141ed4d60afada62fc213bda5ea0d0569c2a8c25d25", + "0x2aeddc77fe58c98d50bd37f1b90840f96ee5a0b09e7e9a96219dd66f0f74c37e5fb6a4114e90fbedc87dd7c321ad3dca39e53d05541bf9d17306d681ab556029b0f172156e12b603": "0x0000000000000000000000000000000004e8fc1e37b0b57aae49b99fb66be1cd0454d275d34a1c031ae4b796fa30d38736", + "0x2aeddc77fe58c98d50bd37f1b90840f96ee5a0b09e7e9a96219dd66f0f74c37e6067f41bd57795d6945e90a1afc83f0c74a3ffe96b40c4ebb5397af04126bc2db23036c043be4a63": "0x00000000000000000000000000000000081aef0e83444feabcf8eda628195f0d756082152cad2aaea5dab16de839b50931c40595c253aabacb254a3a476c0ed1b1fdc9368157d2e6d85dc38f5eddddf13f", + "0x2aeddc77fe58c98d50bd37f1b90840f96ee5a0b09e7e9a96219dd66f0f74c37e60707c14d6e8780e128e3b8a2d3b98071ba399c17206f84350e65653537dbbd646cb5908efff9d49": "0x0000000000000000000000000000000008120460743583c4ebc3076d422b73bef41b48b87e6c07aeecb07df3cf95565eec4ec19498a19021a78fbf00ef07d366245bad3cc89f5837a7004b97a50c4a5e0c", + "0x2aeddc77fe58c98d50bd37f1b90840f96ee5a0b09e7e9a96219dd66f0f74c37e60b67be86271e2f36e99996cc6c41e39696f7c3bc4248e548473b68fe2ba26567771be07b7eb5b19": "0x0000000000000000000000000000000004aee302e198305536eef798b55edd01e28516bfd2d16888597da705ee0e74df0d", + "0x2aeddc77fe58c98d50bd37f1b90840f96ee5a0b09e7e9a96219dd66f0f74c37e6244e474aa91e041ae9749dfdee466ed67835efa51f04d74db27d75e919d7050e4f5b7f481f77a14": "0x00000000000000000000000000000000041cf675676957827846bdae1e0518c92b31a6e0759b3616955445ba3cf8a8111d", + "0x2aeddc77fe58c98d50bd37f1b90840f96ee5a0b09e7e9a96219dd66f0f74c37e628acd4748784be3a2da2913d7db19baf0a41dc40a73d75bc6001ce1691c3ded78e4e86387881b4c": "0x000000000000000000000000000000000c8ab2f02be4ea327d42477029cd7e8ca99a1b1ec34a9502cbf42c1701cdeee77438bc883d8fb7ae97eb3a7862cff1252172f4a901264c84b7feee0a900a64f77db2dbc35ccf086294a0d24e1091d08ca3b5c2a487071c4fb54070e666cc99e02d", + "0x2aeddc77fe58c98d50bd37f1b90840f96ee5a0b09e7e9a96219dd66f0f74c37e62c6144c430228802e62b548856a9ff975d160a0df8219bd36a7807620ac1ae2eeeb34498ba3e470": "0x00000000000000000000000000000000046c736a063c16e476c5d534aedf7e9c95a40f13c95aceb085ef74155d4b37800b", + "0x2aeddc77fe58c98d50bd37f1b90840f96ee5a0b09e7e9a96219dd66f0f74c37e633914b3a4ceda021eb38b0d5178bc680c10a204f81164946a25078c6d3b5f6813cef61c3aef4843": "0x00000000000000000000000000000000186a92b1cb54e218fd9815b34f7a3a35ed39165a29edae89c7086040b59d074c725059875dcee1d4a9908203728cea5bc20ef93a366beac56fa161e04feca0344316a025114b9898b0e78a9472f31364689261cfcb35daf692c62f36012706db1908ec5cff0e253ab3a5d73aa4cf0db459f5128ed41f6b4d3dfbd99924f4346c581c6861821c1863896ec24a799c6ad302e7173b8674e399251bcc571e4977c7293cf08a632438014746be9061a9a74ccd8d79204032cf03d8fc605d452647c133", + "0x2aeddc77fe58c98d50bd37f1b90840f96ee5a0b09e7e9a96219dd66f0f74c37e6354c3c5f32f80e56ce8f0f322c021ca4991c83240d0feb94ad1678835b51d228999252bf9223e49": "0x0000000000000000000000000000000004f954fd2279cdc545fb8b89133ef97c121308e4ca8e26dc2f7d3c3d9b2dc52dbc", + "0x2aeddc77fe58c98d50bd37f1b90840f96ee5a0b09e7e9a96219dd66f0f74c37e63e8632182788bd60a439f839504ef07c5cf8daf62beb17546e808ed1026c8a683be8207245f300f": "0x000000000000000000000000000000000809f7f25aee06632399bd9de5e4a311cfbd1846ecc34f8abc3bb8118a45c98a2eb4b4df0af75ca82e3289a23c6c32eea3d2ad337ce4d335029798b3735c8d6367", + "0x2aeddc77fe58c98d50bd37f1b90840f96ee5a0b09e7e9a96219dd66f0f74c37e63f4f567548c9f8c2843d91b23b106e3020b7a903da075113d1aaca1db7ac30e119d6250fb6f5961": "0x0000000000000000000000000000000004d6ba1aefd3bd5f72b993e0b6c5f9ab818e96e654e2500b1a547f5104896aa660", + "0x2aeddc77fe58c98d50bd37f1b90840f96ee5a0b09e7e9a96219dd66f0f74c37e645a2111e24537a2c088a8a35f9a31008c7ac0d4103078bb14b3d50213e4b92bf03ea98c081f173c": "0x0000000000000000000000000000000004ea4565b84bbc645ba42d3ce16887c42062314fe6aca7ab36a1fd942d7f31c76d", + "0x2aeddc77fe58c98d50bd37f1b90840f96ee5a0b09e7e9a96219dd66f0f74c37e64acb2a5e7697e7428778f95bd35e3fec4ee72a0d252c47097380c3ffdf93a9600b364ea119c0502": "0x000000000000000000000000000000000424d573f4df9151235e457956765e6446cf33077033bbca48d8d5c6c9a1d7fd33", + "0x2aeddc77fe58c98d50bd37f1b90840f96ee5a0b09e7e9a96219dd66f0f74c37e64fffce989e2fabc6a0051ef580a2b9dd19a368b82ec20f9a605b0207f2e8d364e6c985b5b2ba871": "0x00000000000000000000000000000000040a9e884e29b1c07ae4918e17e7ec48bbfe9622cd9badab882d14064c8d672b3d", + "0x2aeddc77fe58c98d50bd37f1b90840f96ee5a0b09e7e9a96219dd66f0f74c37e6553c10b93169dc66e8a3622a7355ab70892bc48236c461076d5163f55309b7e5d0a459d17c6272a": "0x00000000000000000000000000000000047a1b5cf762b0c34865a94bbfb0382ecf0cb030a97e582c4f219c51441ec0b805", + "0x2aeddc77fe58c98d50bd37f1b90840f96ee5a0b09e7e9a96219dd66f0f74c37e6670b1e816a2cedaaa2b3e0a8702aebcb83d552838a17902b2403b0f16c4e52a4514fe02df532e3c": "0x000000000000000000000000000000002460a8e45eea9783d521beeb12cb15c6e9094e5d755749b801ff1a532d0934a90de88efbf462925faaafc04b00555e946a843a6a018de2e47cfca41b0804a9f128aa5cd92797a91f08d3feb5b497e3e329800710e13726accb52d2cec9f16b0164aa5cd92797a91f08d3feb5b497e3e329800710e13726accb52d2cec9f16b0164aa5cd92797a91f08d3feb5b497e3e329800710e13726accb52d2cec9f16b0164aa5cd92797a91f08d3feb5b497e3e329800710e13726accb52d2cec9f16b0164aa5cd92797a91f08d3feb5b497e3e329800710e13726accb52d2cec9f16b0164aa5cd92797a91f08d3feb5b497e3e329800710e13726accb52d2cec9f16b0164aa5cd92797a91f08d3feb5b497e3e329800710e13726accb52d2cec9f16b0164", + "0x2aeddc77fe58c98d50bd37f1b90840f96ee5a0b09e7e9a96219dd66f0f74c37e668bbbac68a19cb7a02f7333e25590e4f568ae8a2ddc93a879e92e48fa3cf1666ac56e020c106d55": "0x0000000000000000000000000000000010f836649df542b24a1b63d80916ee743d4734640aa796648649685dbdd430c3626418bc819ab0a29b18e03aaf851463e3718bdb8649f5b864ce9654febf64c95070610bb9d4abd640e545cf56c9be0e8886b9ec274ea2e4d7facf8dbc575a9447026d79399d627961c528d648413b2aa54595245d97158a8b90900287dee28216", + "0x2aeddc77fe58c98d50bd37f1b90840f96ee5a0b09e7e9a96219dd66f0f74c37e668ce779b7a9f3801e76b9da6373b204c3db21d2a7097a79afcf32f642a516980ae26c910e70a35c": "0x00000000000000000000000000000000044e7dac693f453f3c407caea7909b1f56c8385dd3ea46059c9b0cdb32c19fba3b", + "0x2aeddc77fe58c98d50bd37f1b90840f96ee5a0b09e7e9a96219dd66f0f74c37e66d850d0167dfb3ff429460ae52548e754c712a7cfc75f1bf7c9295da165293ca52ccc686db5c02d": "0x00000000000000000000000000000000084613a2044c0cc5b2f0faca94f2d6e7b7533c1ca3610cca54ba03ab9c5831d82664dd9ec1480c8ae7a38a6566f4634c7f1b5253a0fcd426b3c712d8e2779ff71c", + "0x2aeddc77fe58c98d50bd37f1b90840f96ee5a0b09e7e9a96219dd66f0f74c37e68180e8198681ff7e0d744a6f291a2dc1e6d744d5ae0747e314b046739be170638ecc185ff4a9b5f": "0x000000000000000000000000000000000800c703a1cde92ffaf1f8312c1fdb3a81140f7e76789d55ae1f0683025c428649541a4100aab4ff5eed5dbb5245c488365a4ebe149b8c3d5462a8e7609dff226e", + "0x2aeddc77fe58c98d50bd37f1b90840f96ee5a0b09e7e9a96219dd66f0f74c37e6823ed8df7d5f458c46ff658221e07564fde2764017590264f9dfced3538e283856c43e0ee456e51": "0x0000000000000000000000000000000028845c9d99f3070604aeab0b883b0f8774de633c1e7b91a0376df2342122fd41489e7b589d0d5c36284021ae227a2e2be43e1dd1b67c0df432648e5026dfac6f43c0f326fa9866f007e8ea4125d5364b3d7061ebbbd9a24341c40a3ad8de3d113c809246069a0bc7cee32210e5e5c1a523e10db11d0d86abd29a3979e68dc01725d6e2246ffbf94311de0e749da628bfe1b40ec0251caa056fc6c2050b09074a3d8cf5dbc7c0ac18cccaaba93224d0c254df33169cf4d38befa64b443b6c4fb75b600786fada3d88a3e440751d50f3e522f9b7b28dda4e0f674c9faa24360a082e7c50145c707078b4d38802058b2d16fd80748729aac222af64be9e55e854da2aaef5713b3583a5730c08c16d252f9fbda97536c8a26168256b998f7e9fc1c60200247daf7503a9b41fb6c52c11c760f769266b44fa97bfeea3e0c68f0e3db04f", + "0x2aeddc77fe58c98d50bd37f1b90840f96ee5a0b09e7e9a96219dd66f0f74c37e685887d42c2579e03839e4be40e252a56e2d7c8e89a0c8eb990df5910714fea61c6e1d3b1c4c5502": "0x000000000000000000000000000000000483dc7edbb29fe81e5e29f18ee1c35a90b6aad5637057e3087699d38e7eea7394", + "0x2aeddc77fe58c98d50bd37f1b90840f96ee5a0b09e7e9a96219dd66f0f74c37e689a20d8714b51d538cadf9abf7492ce1df73d8b7ee82e10c2a0571970e2aa5ded4b9a6f91a49833": "0x000000000000000000000000000000000488c3d536bd6f68f296a34c8c3df53f1fb5321622d5f21739b6a76670500e413c", + "0x2aeddc77fe58c98d50bd37f1b90840f96ee5a0b09e7e9a96219dd66f0f74c37e697ead568e820ccfd2eb07f02043788e254d9e2df57be11566d241c56302b91199b4647947af3020": "0x000000000000000000000000000000000852ff057f98f0c1bed31b2fd1ccd8de4d4acf957e79b3f71eb69820bf0dc1d22d02881d4f53d1205e5bdf3864a12c724927270a38a1139e0d6434eed97b930163", + "0x2aeddc77fe58c98d50bd37f1b90840f96ee5a0b09e7e9a96219dd66f0f74c37e69937a5fa154cc0722a58635dd1a211d33750333282985df00d84e87b160293d6b39e89ea4bc7d67": "0x000000000000000000000000000000000476497a6036a1ef7d02ede96d44f39094a5fd50e69d524990946cf5e6e6f1da2c", + "0x2aeddc77fe58c98d50bd37f1b90840f96ee5a0b09e7e9a96219dd66f0f74c37e69b743ba383eda3afe7d71599a2b67c5085142c626641ccfc1f44919270fcac28d2ecfd41e0c7e3c": "0x00000000000000000000000000000000044c9984b5187f51b9b35d16a7df5b38a2e069e568bf813532ba08068477772205", + "0x2aeddc77fe58c98d50bd37f1b90840f96ee5a0b09e7e9a96219dd66f0f74c37e6a2edd04aff025a00a71c6a0fbf9b63ac089c5395bdea4917a84aabb3475d4454147c4d24ce1013a": "0x000000000000000000000000000000000c2bfbb8610a814c9052c287849831e4e28789a020afae5a23c9a19d3f37864a4986505f7c520a5d79d531e99903d5a18615f4510652500f511c8052d8e6a42721f64689da7688eec693a364879994be8568da0f7ff5223c391b6b58626f827527", + "0x2aeddc77fe58c98d50bd37f1b90840f96ee5a0b09e7e9a96219dd66f0f74c37e6ab589167a0b898fcc9f261e20561ee1a137a7c03770706d09a6f85e36e7a313f04d92faefbd3d43": "0x00000000000000000000000000000000040002dd621e14bf09425ab305ae1139310c1c0f78f2d3632c7ea507feb7f82900", + "0x2aeddc77fe58c98d50bd37f1b90840f96ee5a0b09e7e9a96219dd66f0f74c37e6b6157a13ed645fa040298f71f02d7b6a67c0ecee7d7a62ea51dc6daecebf4dd9ad72e0510537a58": "0x0000000000000000000000000000000004fab7ede8984030252e6392d2201f91bcd558470d35785c4bf89f6d7cd86c6e66", + "0x2aeddc77fe58c98d50bd37f1b90840f96ee5a0b09e7e9a96219dd66f0f74c37e6be5d0bab82378087042479798003022a5753c8547cb0de8ef25e2471e40889ff3909fe714e24c5d": "0x0000000000000000000000000000000008f20ddf4f2db1f9f800d70ce19dee3812a5d72bc275f413de1ee186ea7473bd18e0169ecd64ca393045cc15687b0f3355f7c86eef2d25182c731a45e55f2d165c", + "0x2aeddc77fe58c98d50bd37f1b90840f96ee5a0b09e7e9a96219dd66f0f74c37e6bf9c9353fd020348c33b686a457b74f9b1a61b4446404e522d122064d6713ffacee88bfa9a15861": "0x000000000000000000000000000000000438cd946bf9de9d576d29db5fc442e5078a03f73b67ba76d8717634b7be4c5a23", + "0x2aeddc77fe58c98d50bd37f1b90840f96ee5a0b09e7e9a96219dd66f0f74c37e6c4d2026575763437cdc1a6a5a7f23437b6528edcdf553d0685f940a4e6e85579727ef3dc574563a": "0x000000000000000000000000000000000c6366490cf9fcc50f7edbecb28e3b78330a0e35d3e073cfb3538ae6540f0542b0815e86a39ceed754266101e55e352c131c877e72ba6f9652dc45fb3fd3757be4373d025abe0b6342867c03f3772e5e3fcfa7b13d7d5451ddc934efee37894a6c", + "0x2aeddc77fe58c98d50bd37f1b90840f96ee5a0b09e7e9a96219dd66f0f74c37e6c53b7f96dcb583d9c2b14c09923911fe0ff6918b7c7702a91762aede2c2cdd0f1f0bdcf7b9f2a5a": "0x0000000000000000000000000000000004a56bd842d168e9b1eae2ef3d1f6d323b9bd4b8db997ffd2ff52369e5c0ba5512", + "0x2aeddc77fe58c98d50bd37f1b90840f96ee5a0b09e7e9a96219dd66f0f74c37e6c7206770c39d9295a5f7eb7050fb96d8d7895d9afce428a064ce66e3b094805bcad9a8e68cb9934": "0x0000000000000000000000000000000010b3c0b3afec6c57fc99dc2656c38ecae97b5c01f2d44bc9da56714141676e3ff21239360b36af37935b370032d2306b6c99c2e06b0312c2de4ad61c263b82886c067a2e439cc384440cf187331543175270b479ba695e2c4d6ba9528bbb6be460f201e84471e485a37aa3988c97ad57db1297d862ed5405d864708654e430260e", + "0x2aeddc77fe58c98d50bd37f1b90840f96ee5a0b09e7e9a96219dd66f0f74c37e6cd2b2fd45e2e3d0702a6dc9592ec94ce9e1f07e2a0559d7f43f932101bace2400d0e92419218732": "0x0000000000000000000000000000000008befe117ae4a987baebd13ac5c3b611ded994a75dc9ef2dfcab5071688ec9e2fbbefe117ae4a987baebd13ac5c3b611ded994a75dc9ef2dfcab5071688ec9e2fb", + "0x2aeddc77fe58c98d50bd37f1b90840f96ee5a0b09e7e9a96219dd66f0f74c37e6cebd0b9de064aab0e038990f47761a17f45c2bb01c4c7746f4ad67c7d0c1dfbd6915372faae911f": "0x00000000000000000000000000000000080c92d4e41eddd3bec4ce4caf3610213e3b3b143a6c0319766961aecc27e124ffa7f6170f731a0acda2c9edc8ac9fc21a0b33e448378730b2392cc0bb76b55546", + "0x2aeddc77fe58c98d50bd37f1b90840f96ee5a0b09e7e9a96219dd66f0f74c37e6d301a445678938ac43aabf384c6baf54ef9712a96be7c46533b538c05d4e6c687fe09b109664b28": "0x000000000000000000000000000000000875a6c848edd2d131588ed2fb322ef45909d4aed3b7ea1197fce14220a68fcfe3611f3cd11a51748d355ff0686f5c5bbc2a7b0e91b6efa0fb4f9aae77c53942c8", + "0x2aeddc77fe58c98d50bd37f1b90840f96ee5a0b09e7e9a96219dd66f0f74c37e6d81d41850c8478a76016fc20a6457ff8953bf29686c5698c28bbfa860669ddd07b386c910f1107d": "0x0000000000000000000000000000000004cc4790e6ee2ebf4271fffa10d4bcc2a4460ab377a49ddbedfbb647090c6a97aa", + "0x2aeddc77fe58c98d50bd37f1b90840f96ee5a0b09e7e9a96219dd66f0f74c37e6de5c15d472fd831e4e00e63c3647fc8c0a3d1b163ac988b6f0a7c3d05a01e209d4adef8e285037b": "0x00000000000000000000000000000000041024e48276b150fbff7c44baddfce92ba5d90057d518d3b29bcfaa421c13ab7b", + "0x2aeddc77fe58c98d50bd37f1b90840f96ee5a0b09e7e9a96219dd66f0f74c37e6ec642500076ba25a6c5f0595d6ed85d6260bc682d4a68a4b4e605d43c67d56f2765d19698549772": "0x0000000000000000000000000000000008e541547dbea2dac6e485f82ea71b8b1f6fb6696aa65cab783b20f9a6c574e6445c8186e944c4df5cbb64eb1080932db445d11f69fb4da145a98d0d6aabb4c009", + "0x2aeddc77fe58c98d50bd37f1b90840f96ee5a0b09e7e9a96219dd66f0f74c37e6f3d6f5d8945a2a9d896f718b4ad053ba53468ba0347060b4a80f03fa72e9c14da5e2e7ea80e3f2c": "0x000000000000000000000000000000000470a8fd1a49157402789a0c495dc9c9d12e87a64805374661b32f1d715ca22f5a", + "0x2aeddc77fe58c98d50bd37f1b90840f96ee5a0b09e7e9a96219dd66f0f74c37e6f9bf1c5c47f9bff1c378d545f64248bedae80ec34f8f29551fc9f814f8491f8fea50f10fff6e229": "0x0000000000000000000000000000000004599aa7c71c2716d534f7f4ec936d9bc547b4e32fad199466a389b09b139f3f8b", + "0x2aeddc77fe58c98d50bd37f1b90840f96ee5a0b09e7e9a96219dd66f0f74c37e70023b9d2a2c164748ca001326b583070e370be3bc6680d09cad47649584a5c992bd388c693b9a54": "0x0000000000000000000000000000000048e4dc1df8790688cc413fea804c4158d1142db0312e091578306e1ec9fcd6bb7772ae12a9ae7729206f6988826c71f0f3076971462d1ac94efff198392464a6574aaa077ac4202f4f7e1135489106099452441129dc5aad89cd5dd4335918fa3dea08268d10b6dd05b9db75c7b7abc2b95e9b24d47f7b2a6147a56dcc745a0b4f06929a0b268c8a51c457e031e971ba6d1624b2ecccfc94185a8b593549ef7b401ad58fdac86f68d5a3a9a8e07163426d717ef0426d3e03604ae3bf4ed481a9236ecbc9b76728dae4396541cd517384e9898d5bec4875bdd1971c97041fa281119eb6835f83b4313045b2a156d5af104e172dc687b2bd07554ff3699748c4105016ee0e830501e14db6f33efb672620f030b65bcd30a91152c9b9abb66f4c117c8a1e84fa7220a6f820ca42a6dbe689b545ba1def88a7f1bd98d7aa46a9ab742ede38c0e7726f26fb4ce2b3bc8a17ded6197309efbf24d70d0425728eff597d50e28ceca047d61c081d502fb5b66527b2dc7438684d607682e9dc082640667213ea6f0d87d39b6b348f609c20246f065864972f409b809e94636fad2e6e779059809275c61d0a44ede0bb18a54adf2b684d44d1759e516e46634aad562fff1c2f78905d56c02810911e1ebaf201ac246eff919f4e71a5bfa5b29eaf6819663944426c1e2855920b16c78a37f7b6f480163f2a876a889f78b1ef2d11ebc9fd14592cd1a4b07571dd2c61dfa5ffd65b190a203d082e9176e791a25bcf242de28501d41ef941dae80043db2c5bcecb8501ff3f159ce810271ab6fdcbf979de7cd373", + "0x2aeddc77fe58c98d50bd37f1b90840f96ee5a0b09e7e9a96219dd66f0f74c37e704211a750c9b855eed08a5b10b1835610d66ce4fa273c8e2436b978c9f65442efb6074871b48a6a": "0x0000000000000000000000000000000004c83b05f03d7e0511d29dca7a11f3631f6a0bf373ee6f96bf99882421dd261a4b", + "0x2aeddc77fe58c98d50bd37f1b90840f96ee5a0b09e7e9a96219dd66f0f74c37e7061508d0facf9d35a1a549172a49f7591155007c51680ad8ad77571cea04acd1b0b84459e779234": "0x0000000000000000000000000000000004ba65343515a46a4aa9932cbdf0105d123c9d4ba9bef3be885c46f52c8c058d66", + "0x2aeddc77fe58c98d50bd37f1b90840f96ee5a0b09e7e9a96219dd66f0f74c37e718a792663e13c111e015452870e49b4e4c3e054556b19683e8895586bfa58638a74a5782ab4f712": "0x00000000000000000000000000000000048e57071fe8c6591960d214a1100419ff2e2e92d4989a99646354df48ef91e664", + "0x2aeddc77fe58c98d50bd37f1b90840f96ee5a0b09e7e9a96219dd66f0f74c37e7214db08aea29f4c2a5bd5797da40fe8be1b94dd3260ef86d6b01cfc891c5c1cd160ad7fa198de57": "0x0000000000000000000000000000000010527638f35f3b999cb645e1e70a49e7b798a89c36b289bd366056d39115c18ae420cbc85619baeb354c068a5799d8ffa8b822505221d5357d7e70f2a3ebe08ea11ea9ff7a769863d12182a9439c3666f3fbbaedec8b5427d3c3e93633cebb4ae00da80f8169a692da1a6a0bda931750ed897b1ef4b0bc9bc6e0cbc906981e2b6a", + "0x2aeddc77fe58c98d50bd37f1b90840f96ee5a0b09e7e9a96219dd66f0f74c37e7231a73eec660398046ff960b0d51db710b8ca414171afd47c9612311b69fa9416622dfb42a33124": "0x00000000000000000000000000000000044f00d8607ea768fa23a0befe7cead74f5f99102a70f53aae2cf68922f526523e", + "0x2aeddc77fe58c98d50bd37f1b90840f96ee5a0b09e7e9a96219dd66f0f74c37e73006ea8baa58afe58f26dd10efac24a7fd1813d6aa72a8e60bee976f7da28e492ad033fc1822315": "0x000000000000000000000000000000000453b9577bbf862a61bfd4c7302c3a43bd26a9b50370e3cb6586c8e267c1b87180", + "0x2aeddc77fe58c98d50bd37f1b90840f96ee5a0b09e7e9a96219dd66f0f74c37e737675dbae64b33e3284bc8ce3083b62e671d1c5bd61db5b3fea95a77967341ca8834a69cffcfd5f": "0x0000000000000000000000000000000008d21bad21a85a2c91d823216610c964d9fef7dddff9f1864b2a7b4a8e667c1f5326e07a9cb1d3b8827960bbbee94197ad2204ea98db2d54da63b57bd9eac4374f", + "0x2aeddc77fe58c98d50bd37f1b90840f96ee5a0b09e7e9a96219dd66f0f74c37e7396af96b1f453f59e826b5434525d00c118f3f6b0a29b7f432be7bbd18659d472c5f07298e76949": "0x0000000000000000000000000000000008847074f1fb351eaa06337823c68f2a9fb28c98db976bc5cc16867e4b84bc1060b8e7e832b85afd9cac90cf30ab4477265f14901bc0f25b2142c2e488bce87352", + "0x2aeddc77fe58c98d50bd37f1b90840f96ee5a0b09e7e9a96219dd66f0f74c37e74083880a0b640654a003aeae28534daddcc861d7d3e91b576683544217044cefcf4803ced1fbc69": "0x00000000000000000000000000000000049ca08cd9b7fdd71d23d3a07906fac5a51b77c703f290adb2b5099b4334407913", + "0x2aeddc77fe58c98d50bd37f1b90840f96ee5a0b09e7e9a96219dd66f0f74c37e74e73ec4f7c76752d65d5c1484e5faf8ad32907ab729add8ffc2ffe0f29bc18015bec2c3f8ac7c66": "0x0000000000000000000000000000000004c99cae7c82bcc7d4c6d39b376a3f9a61242bf4ff1225866f5f93acbbf8ac922a", + "0x2aeddc77fe58c98d50bd37f1b90840f96ee5a0b09e7e9a96219dd66f0f74c37e752ce2fc0e55cd08ac33b989d0b4dd35d2fb8af4cd04cc5a3831e59023cb884044f5cda0541f1064": "0x0000000000000000000000000000000024463e61911efe5b07ac64fbdd0b388a7b9569d067a6a34f01ce88bbfd9357f29f2f9c09c8a70b63d73be60dfe13947a17839970667250b900c8560ed4d042841d06beb838b0ba3114b2d1342cf7011c397879da3fb4b4ffd4df534e6948d4913eb8270b6d0325eac9f3ffd34032017f7848eaa460ca9a96a90a5296e34af91f96ea073956416e6c3fb74d4423f458a028c9674f147468dc0e2ca6d2c140bcdf4d3525a2d8318f0a082d428d90eeeccba905e0001fdad3a04d6abe49dd79e1518670375a0d07a2172cf390b17cce40e34997aa99c1762e9fe3f96a91ed60c7354b5767532cfd7c17f35bb22551c3364d9737749661b25f431f04df8364c9db3954dde48b0a82d440116e0620963bfc19d1520435a7b64c4b36e5b258be8a9974e0", + "0x2aeddc77fe58c98d50bd37f1b90840f96ee5a0b09e7e9a96219dd66f0f74c37e753ac717444b23dd1cf3e5e0a3f8f198a63f5f7284fe493c23e88161d92d2cd418e52d050e3bd22b": "0x0000000000000000000000000000000004b0495e49f3241a065bbf17983665997e582b1535c5410530897e3889993f711d", + "0x2aeddc77fe58c98d50bd37f1b90840f96ee5a0b09e7e9a96219dd66f0f74c37e753bb535f9a5c087d4e6d6256f56677bcdbc0543f1a2c40aa82497b33af1748fc10113b1e2a1b460": "0x0000000000000000000000000000000024e2dfbb25f8e8e6047e14474e054090c283b6c8d34fbcc7370fff8292592f934eae8c6dd7bf2e52a684bbda1831b6eea8040b7fa459da6a487a9988a9d84f6b0c48f5c152ca97d46d67467f3b6c7e2fff11e1f95abc0ea7298255c026ff65d92b280daf6efb2a16974f928da1abda06f2997f18a8db3cc73dab3cdc97d13fa52094082abb5e84b31a7cb7e0e69fd711f013ac426d62f1e157b762d284ee6efe2be6fe75fdd65d00f6ea16c22ba1ce89e45441b80c597eca58690664288f1ca146f40945c32b5bb894f311b2a680d927a1d26080b3b4b1c8b5bcabb196918d0e2da6cf293e01355a99ab2429bc7d9f56bd24beb526079ac3eb0a00c3c70e4f64655ad5faadcc4848cc8acadadf39c4a9893e13e8993e270364eba8ce53b8374c6f", + "0x2aeddc77fe58c98d50bd37f1b90840f96ee5a0b09e7e9a96219dd66f0f74c37e7571a6ecb5a2dbf4548dcb6c3aabe041e7f7ee65af37818dc7ff1ff1a4300008100322c39e9c610b": "0x0000000000000000000000000000000018f87441058c9c1d89f27cd68a74ced729f5393936f7c041de6732df7217d17cfcea4cf3795941a47d46c2b433ee328d7d2a71c85007251569a6e1fa5535af173dd38bb685e02bad927a5425d733b7f89077e5b2b6c09e8e8990c98dde3275067c97a214d9d7e4d9756f50d6b43a18a8ee671cb1512b46f2c2c8c1309694dc75bfeaeb9d2bee9133ac09633b0361b04567f3997d6aa139a401c12f929be161d9f65c5c5a4a025f3d8be84fa9ea36383c2cd168c8a018d50c88a34154afe9ecf04f", + "0x2aeddc77fe58c98d50bd37f1b90840f96ee5a0b09e7e9a96219dd66f0f74c37e7661b26815a3370c9ef2c74b5a6820a16eb04205a9d177c4244a94cdcfe1275039ef8704480a3905": "0x00000000000000000000000000000000049ef2c74b5a6820a16eb04205a9d177c4244a94cdcfe1275039ef8704480a3905", + "0x2aeddc77fe58c98d50bd37f1b90840f96ee5a0b09e7e9a96219dd66f0f74c37e7680539dbbaf0658cecae006fbf10a81337d87455340ce6112b125a971482490e02d75a27bb2c33c": "0x000000000000000000000000000000000478c0205b88370e3af02a0d22ff0411cb0335a823f02f604c692a9bb1914f2262", + "0x2aeddc77fe58c98d50bd37f1b90840f96ee5a0b09e7e9a96219dd66f0f74c37e76d10d82508ddae096e24e9b5ab82dc275b82318a52cebed1cae3e25be096d5f288229b256359e43": "0x0000000000000000000000000000000004c2de6256e9ff0ba9b97f862290f69ec0f72b31fa0a6843e0175e9e81a0165d6b", + "0x2aeddc77fe58c98d50bd37f1b90840f96ee5a0b09e7e9a96219dd66f0f74c37e782e7be4e56dc7e9ae963c00a7c164fce3f4a8ed94ba0a87e83cc1a7b192726836819cf1f63c522b": "0x00000000000000000000000000000000048689cf01de26619d9e77cfb38911661940f6fd4b6379d8bd5558b8b967d51db6", + "0x2aeddc77fe58c98d50bd37f1b90840f96ee5a0b09e7e9a96219dd66f0f74c37e78331d8cc49f0ef276f45a1045fe47a639befe802be7eeea599080222e2f45fba46492039609cc07": "0x0000000000000000000000000000000004ce52792eba24d1a81f5979865ac647e16fa810d48fa38b2840de291115171e06", + "0x2aeddc77fe58c98d50bd37f1b90840f96ee5a0b09e7e9a96219dd66f0f74c37e78401030f0261c10a49deb88afa394b7eb478483a65a8c8f060b7de319dc6f65776a84d9e8f40e7e": "0x00000000000000000000000000000000142494641f85af0c7f9d2e3c942fd250dd7c2ecc7e5dcc401fb3ebca0573edc571be6ac75cc8c52d2d3b88dd29c0352b579f4891c52f76508269f2328fece4d07d8c600da2883fe70c639e6375b81f45d5225acf4777c4586a3672c2568b9c676cbd65fafff9dc200e3945e786ca92ba36a9aa333b09bb500b632e8827f8f7ab380e8b9d19878dc5c50ed1ab180f4e76cf7e208851fc6a869b28dbc1ce6208dc0e", + "0x2aeddc77fe58c98d50bd37f1b90840f96ee5a0b09e7e9a96219dd66f0f74c37e78793b4db20d123c8e111a2e445cc0f64b5809496887b3130718d969db6637c0ebf1118c39b15c55": "0x00000000000000000000000000000000040a16d6fd4dc2954c449699e5f6e3c7d2f0dc64df5b8008135fd60eb3eac61e6f", + "0x2aeddc77fe58c98d50bd37f1b90840f96ee5a0b09e7e9a96219dd66f0f74c37e792e04f3dda19263a61514d5cabf81b3f62650806870ad83b2e5059538b846b6dd9963e010566a17": "0x000000000000000000000000000000000446105c0b02b08c1a4e094e2bbc42fab06c13cdd155bff92dd844d3bd727f2612", + "0x2aeddc77fe58c98d50bd37f1b90840f96ee5a0b09e7e9a96219dd66f0f74c37e794c7db721956af68a56b1da8dc3f4bd58630c15f5754ee634528a007ab510c86a7e1fe6e62f4166": "0x0000000000000000000000000000000004b497cbcd9414ec2922ff86acf2e22ad1b49aa07be1182a9490c47d3170e6861b", + "0x2aeddc77fe58c98d50bd37f1b90840f96ee5a0b09e7e9a96219dd66f0f74c37e7a0fd3be900ddd6b0a7ac5be69a8243f8880d5fd015b2e8f8f30ce6c7162f8bcb5ad1a1fa4246d32": "0x0000000000000000000000000000000004080bd036530545e5e07ad813a408fa757bdd643e76b9d1171417d7eff0d7fe4b", + "0x2aeddc77fe58c98d50bd37f1b90840f96ee5a0b09e7e9a96219dd66f0f74c37e7afcd22bd458c5e66aa7f16d0ce7a6288dd1d2f1779fafb18d4c60ee78e89ab3dd3bc0979aad386e": "0x0000000000000000000000000000000004800bea28742b7e03bf213fd6cbd84e862ccdc18e30b94635f5778a8103133f36", + "0x2aeddc77fe58c98d50bd37f1b90840f96ee5a0b09e7e9a96219dd66f0f74c37e7bbbb302ea3c73fd6a1e7cf7558378809fa376f7eec7b065d30759f8a4e7b721ec2ae74b313f0855": "0x0000000000000000000000000000000004a8c96b926e3a1baf17e8f1cab2e0df7229b36c661e9d29f4c005b2dfb0835218", + "0x2aeddc77fe58c98d50bd37f1b90840f96ee5a0b09e7e9a96219dd66f0f74c37e7bc80f4306d5529f7a54e6a55c0453407909789a06c3ee6719f8735ac370d6f17dc342717fd76819": "0x00000000000000000000000000000000200650217af71d75baa1bbc577761208886a474cfe4c24435b0295586f2f66a571ce00415c4b594b4c5085fc803c7eb7872847b7b50fbb0ad93cf0fb95c7a0bf68e2cbbeac13b1017c8a5a32551d77e89017551a2f9438743446de2dc2ed13ec4d7c731b26739bf75d9607468391f9d743d3ee7f65f8e668d770174f74dcab7f433818c289aad92bbce3185cbc77619f99bb38a139fd9428ec6c2c97f964d0146770d4121446293f928e59d4f8a5eea096ebe1c2538002fcbf7b7845dd2e19ee6d424ecaa1e5d069bb89c743c3ddb44d9cb023aff0ad78e3c502bd39b0abbf7715e2c6bbc2bf8ac332d8f9f45013049439bd2d31008db521ffe472e8c4c4e0c348", + "0x2aeddc77fe58c98d50bd37f1b90840f96ee5a0b09e7e9a96219dd66f0f74c37e7bf2c0491ddcbed34e908afcf0fb6b394bd1a043bc8b226fac33b4742731b9cde5d324f450eb3006": "0x00000000000000000000000000000000100a750504f5da1835d98bf849ebc018742d544c86edbcab2525a8acc2178fed596cdfaeaa8c9eba3e4d30f66d1b53a97f830612cdcdb1ee1d203a797ef4973125c21bde30a8d12e4e5d4dd612ff510d84e23afe81bdb222e1037a7c7fafd8962b4033dc4a810332f94b2874b5aa564424b0583f0e866c908346ae4b2bcb4f5e0e", + "0x2aeddc77fe58c98d50bd37f1b90840f96ee5a0b09e7e9a96219dd66f0f74c37e7c1466766d8e06522ce1929ab903f695bdeeeb79a588774d71468362129136f1b7f7b31a32958f98": "0x00000000000000000000000000000000048e9871679378b82009f51f30eec29bcddfe60c4f7d22c24f74883b47d935a565", + "0x2aeddc77fe58c98d50bd37f1b90840f96ee5a0b09e7e9a96219dd66f0f74c37e7c9b151305dcded7e26969331bf77ce04768009026a5362d51e5bccc12f788b8cda2a43ef218bd04": "0x0000000000000000000000000000000010e26969331bf77ce04768009026a5362d51e5bccc12f788b8cda2a43ef218bd04fca5925e677ffb072b404634eb297becf53c269e32c7393c9b9dec8d256dad21a434a662f5ab9e81bb83c07ab5282538bafe448f142d2b6b119362b1bebbe1767493915ecb44badd479418bd0ef0f753952690f6ceeb421a0fe567edf2fdb228", + "0x2aeddc77fe58c98d50bd37f1b90840f96ee5a0b09e7e9a96219dd66f0f74c37e7ce6fa220b1f0d1ba06446b3474c3d9dcfb759f3df134cf4b6620b2559c4e1b99d3be4d010378f40": "0x00000000000000000000000000000000048bbf421fcb86d5fd3e28a4762d295b722fae2260d0f3d548fe6eb8cd741c286e", + "0x2aeddc77fe58c98d50bd37f1b90840f96ee5a0b09e7e9a96219dd66f0f74c37e7d26f412c600f65a48745d28d9e9596ca41b7f7bcb03f874757f4f0716a7237e566662a6393bc125": "0x0000000000000000000000000000000004483ea32669fca11e7415c4e24e088cb3df49defae82f0f9d069ea0aa75839e38", + "0x2aeddc77fe58c98d50bd37f1b90840f96ee5a0b09e7e9a96219dd66f0f74c37e7d2dd084386fd77b18cf1686419c41dc5d3e76d373e3176c32c6d23c755fe1fc357f9c755ffc0019": "0x0000000000000000000000000000000018c0dd6bb9243edbd211dac2b9b37fd29003be77cf21455af7c2c680af8812b6041c761954d8265833c4b21c7296a314229af2391b34fc090aa76a817b2e79836af4c68c01b58b381bcb8b1fe58cab96f90271910ec55c23214c68815130b5a81ba8ad44d6bd00b9ebeda2a48ccdad36d0ca29bd930ca2856cc8ce1c109f938625822adab3c579b87a5731f551e8f311cefbffbf514b27b94a6af35fc23562c945a6148a5ba31e548196ff678386e2c8792fb3bea265b6c2475e62eab64254946e", + "0x2aeddc77fe58c98d50bd37f1b90840f96ee5a0b09e7e9a96219dd66f0f74c37e7d363e805ca7dc102e6dde560aa0f00b08d0db5e3c2f199181be3ca53d2e7a0a742aa5692433060d": "0x0000000000000000000000000000000004ed1d56154af1862efb63fc12298d73411b024a7b5312346ca95effe7011efec3", + "0x2aeddc77fe58c98d50bd37f1b90840f96ee5a0b09e7e9a96219dd66f0f74c37e7d3c67d22eef172a8c20d46f86242eea89c400d5c478207e05c76bbab29a748af8aac90d627e1a01": "0x000000000000000000000000000000000888624098732487bb9f92045e3d405bd1b7f9432dbd705c3ba58c5e86d1353c696679005100a874118c6c38e5b3183ef6cb71193480d1de0699f9bb6bfedf1f24", + "0x2aeddc77fe58c98d50bd37f1b90840f96ee5a0b09e7e9a96219dd66f0f74c37e7d73ff709d9ae6a4d53c9c6e61431448ceef1eb49542ddee942dd3d6c81c19d53efbab8acb02f00f": "0x0000000000000000000000000000000004f45c6d9ac359665373662814fb3b30355638036ee2aee6807b2f2b228ec1d6e5", + "0x2aeddc77fe58c98d50bd37f1b90840f96ee5a0b09e7e9a96219dd66f0f74c37e7d76b3fc859618eb1a41e8f79310cf5b804b038d19f28b535261fc5c1c3d1dcfdc49e6bf5a946d32": "0x0000000000000000000000000000000004a248e7a6ef290c55ae9f1383eef475298bf04a1a78fc22f186cce5a797ebf508", + "0x2aeddc77fe58c98d50bd37f1b90840f96ee5a0b09e7e9a96219dd66f0f74c37e7da4d6e045faa8163a731ac0ae7375a2cce5b504484d91f1c49923b3425072e36e12b0afd5f2a857": "0x0000000000000000000000000000000008a570c6ce21a0b2f432dfd11756cca948259a8b281196ccec975c681372a06280cd5f012106aaea7652374847b9658c8c300f0f0b26e484e99f7c1e3d32d83a10", + "0x2aeddc77fe58c98d50bd37f1b90840f96ee5a0b09e7e9a96219dd66f0f74c37e7db14798f78c92e409ed7dc92692f6d1b8bf5e71b68f9019a16f825e4eb71bb22c5bcbb9fec300d1": "0x0000000000000000000000000000000004e7934d8edca47f33d004647a350aaa7ca31871f8ffe6038f187e1689cf34dcdd", + "0x2aeddc77fe58c98d50bd37f1b90840f96ee5a0b09e7e9a96219dd66f0f74c37e7e1d98e7b551be5a30fd1beaa72357f61ba1fe7e90aa8c5080fcd49b2c82e1b8315bcd9a223cbe41": "0x0000000000000000000000000000000008e1926d2b7dcec1ba035361a2d58a3ddbbc4386ba5bd61d5dd57d22d508154decd10cd1c9ae335b7b25abad42b89554a8d9c9fdce81a11b856604cdfa6edccffe", + "0x2aeddc77fe58c98d50bd37f1b90840f96ee5a0b09e7e9a96219dd66f0f74c37e81a8aa27b7c69abc7c7d2fe83c4af79c49136f0f8c5f1a00cd8d0aa91c94fe74d0145cb96d688f66": "0x000000000000000000000000000000000c2efecb509bcbfa0ebbe40f7bbc6a74d4a90cfd7e982ce06c2f11fdcc70efeb5a8057b9f8b71f7e97f0bbb2dd94b1a047992ff072d07aa77f0a3fba1c288840251a232a8dc0c50a8faa639ed22d11410c00f5b812bd14ffa6f3f554d8edad4172", + "0x2aeddc77fe58c98d50bd37f1b90840f96ee5a0b09e7e9a96219dd66f0f74c37e8337944019a68ea6a6500e450888dd3758b301a0f99d433264362547ca7d0f7631ea53871aa3be35": "0x0000000000000000000000000000000004007f0252d2dda00e8007d8ba227234f9407f28a0584158c1a74b2e4401ba921e", + "0x2aeddc77fe58c98d50bd37f1b90840f96ee5a0b09e7e9a96219dd66f0f74c37e83ad6aeb3e5890e926090dc5275e53b65763f135108a9111289aa1ca6331a8ddb3440059cd33d75f": "0x000000000000000000000000000000000426090dc5275e53b65763f135108a9111289aa1ca6331a8ddb3440059cd33d75f", + "0x2aeddc77fe58c98d50bd37f1b90840f96ee5a0b09e7e9a96219dd66f0f74c37e841c66ae33e977e77eb07fd02281d018a4c45bab914fc6e2a0f81620663b53ab62432ae62a07194d": "0x000000000000000000000000000000000448b36ca55541b8f8c030a3a844a247a85e731764d015bdede53205fb5b355a25", + "0x2aeddc77fe58c98d50bd37f1b90840f96ee5a0b09e7e9a96219dd66f0f74c37e842664827980e15e54faa9f0cc59a977e73147865791a9272cd4980db5ff2eee27096d34ff2fab69": "0x0000000000000000000000000000000004fefa1659ff7e86a20f110974463d76eb0238f0e02f6b526df7d586b0657d52d8", + "0x2aeddc77fe58c98d50bd37f1b90840f96ee5a0b09e7e9a96219dd66f0f74c37e84ccbb22b59b800b7213534fb02c7638d8d7caf1f62b983225c5aa76b8c14d249f7a704b50ba850a": "0x000000000000000000000000000000000430cca6318e5c3cea1c72f33f541532ab6609b50853627fcd587bd5883d52f75c", + "0x2aeddc77fe58c98d50bd37f1b90840f96ee5a0b09e7e9a96219dd66f0f74c37e8549b7fd2bfcfdd9bc0525c374a8198f3288a0733918321dfc26532e253d94da3a6a27a4c3e31760": "0x0000000000000000000000000000000004cafd506351cbb8a3af1f69479dc08628bcdc05de50e86e2f94aaa21306727b2c", + "0x2aeddc77fe58c98d50bd37f1b90840f96ee5a0b09e7e9a96219dd66f0f74c37e85d657f1acd3f2c92458c79f1b8d080257ba31830f364170c90b6b173be1832ebace48595d193b2b": "0x0000000000000000000000000000000004160e772b488c83753ee69cadc56cdfe71937dec6a69b4bee87e4cfeb4bf8d475", + "0x2aeddc77fe58c98d50bd37f1b90840f96ee5a0b09e7e9a96219dd66f0f74c37e860033e5e332e23d6a2bd95c44c00bcad3fef2f7226ad90b8b93c3c1b9679236d5abfdb39c895844": "0x0000000000000000000000000000000004bf7c2411b8362b3beedd04428317c3eeb3639379c64eaa724d44eb77b15cc85b", + "0x2aeddc77fe58c98d50bd37f1b90840f96ee5a0b09e7e9a96219dd66f0f74c37e8621671899b86161726ac63a0a6a700ad7e1178fef89a87620bbc152a19f74708defc7f08bbc6556": "0x000000000000000000000000000000000410a315981265a9951067374fb624c1976dcf865c9dc43d08e3031ead35a06219", + "0x2aeddc77fe58c98d50bd37f1b90840f96ee5a0b09e7e9a96219dd66f0f74c37e8641dd739c11a1441994df5bf0f44342b1719bfbb1561286bd81b6d84f577f55ef45fe7ad6f50e4a": "0x0000000000000000000000000000000004e396927763007571ab5c30a835b67c150993def51b98681dd7a69e87d7125cf7", + "0x2aeddc77fe58c98d50bd37f1b90840f96ee5a0b09e7e9a96219dd66f0f74c37e86672c8d8603d645de7fc70edbc29190008415c3b6122dc6390b738453c6f1213b59942b2b76e54a": "0x0000000000000000000000000000000008c2e34786dcde41bcaf6c5c3dedd1320c792f0a0bf3c448e03275d7f9cefb765312ba1a34fc5e9b81ba8d7e486f223a2cb47e30c8dc185888aaac0eb25c5f605b", + "0x2aeddc77fe58c98d50bd37f1b90840f96ee5a0b09e7e9a96219dd66f0f74c37e867fc6e4929b002af04c95a6ac10a0db5af28ac44776f95949dd543f494f8b8787925c41fccf7e0f": "0x00000000000000000000000000000000045e5085f483896c9bfc341a80912faf167a1ef9229fe8b2989de7b6bad03c63cb", + "0x2aeddc77fe58c98d50bd37f1b90840f96ee5a0b09e7e9a96219dd66f0f74c37e86e553fb01bfcb3d16f24ecfa07199b88f010d94f47864ace2c0357aa4f37898f85cb39992e2036d": "0x00000000000000000000000000000000044e6717194ee8da5cb1669a5636c8821f764ecffa0bb0e43b610b8bb1fb1f197a", + "0x2aeddc77fe58c98d50bd37f1b90840f96ee5a0b09e7e9a96219dd66f0f74c37e87843e0e467379078c79cbd600c63f0cc90b34e7301b7cef8c93f7a404cbacecab96901fe53d4640": "0x000000000000000000000000000000000418a06c67746e98a3cc1680079a706c133d5e77d0c8721728cdd7c8525b42b752", + "0x2aeddc77fe58c98d50bd37f1b90840f96ee5a0b09e7e9a96219dd66f0f74c37e87f8d378447f4f51b8a038b439b411fb7c6cc2d7315292a3d1649601641cbbe0825ab7fa90ce3002": "0x00000000000000000000000000000000048e81ad73b19ae9a28e6e7020f70d862a8e379ce88dc1546a2a8724a7c4b5601e", + "0x2aeddc77fe58c98d50bd37f1b90840f96ee5a0b09e7e9a96219dd66f0f74c37e885ebea0f5080b1300f53cf59ee4bae1fc47b5df521d48a3cc2d02d5c15fd5d3bfa3d6a4a2e6a576": "0x00000000000000000000000000000000081af4af68069a4772fc4e73cba9d1479943982c64e124ec73bb1cbc70f66bcf3f3a6a0745688c52b4709f65fa2e4508dfa0940ccc0d282cd16be9bc043b2f4a04", + "0x2aeddc77fe58c98d50bd37f1b90840f96ee5a0b09e7e9a96219dd66f0f74c37e8876172ab0d0bba3f89b361ea400867da22fa6a069fdd840819fdc24fee6cc3763b6cf3a8a20246b": "0x00000000000000000000000000000000047a0d37cd4a96cb4e0445c91d19d6c84856f994d5e099e0f911b6855605833860", + "0x2aeddc77fe58c98d50bd37f1b90840f96ee5a0b09e7e9a96219dd66f0f74c37e88de95e48f84c3689085297d964ea873a23b63151b4c82189c1314c31fda6f2d71f83133d0877c5c": "0x000000000000000000000000000000000cf25f7a8dd6b648eac453d60b0052dee3cefce2ff56830eb7cc98292c8885f958326e27145577ff5e9bcd3f75bba30fca9622705f65a07ecf04a5d692b284ce72547be45207a849ca9ec68e16de6964b581b36449cb04256febdfdad833e7e670", + "0x2aeddc77fe58c98d50bd37f1b90840f96ee5a0b09e7e9a96219dd66f0f74c37e88f2bab6b4633034bee287e579da5137412f2c3bd4d5ae4c6a11c4c420e04261157e04842a2ea641": "0x00000000000000000000000000000000048cc54beb3db37569467a12154f037da2f6d859d11b72db7cc8f615c7456bc923", + "0x2aeddc77fe58c98d50bd37f1b90840f96ee5a0b09e7e9a96219dd66f0f74c37e8902cecf825f2867273e55ba58de0184bb96e5e691dcc9171ec58658d2b94c42c7e4ca7574f6a076": "0x000000000000000000000000000000000433815302aca0725e74939106884963f32a80056aba37aa94dfe6220c039cc87e", + "0x2aeddc77fe58c98d50bd37f1b90840f96ee5a0b09e7e9a96219dd66f0f74c37e8954d9b6c7704b5c0a912cf4f0c7894598d81d26f2c24f6e5c2541f312462bb576593e9dc549146d": "0x00000000000000000000000000000000040c8bdf19914b8931589d6658da943de4de04cc1102902a9e30d3d3bc68892c02", + "0x2aeddc77fe58c98d50bd37f1b90840f96ee5a0b09e7e9a96219dd66f0f74c37e8997871f06793d390456840228e994122a2750c966571ca20d2456db20a7cb84603ed8e2d5503776": "0x000000000000000000000000000000000460384fabe173278be399e99aaafc7d5b3eb2547af81fbc8039eb6fc49ae008bb", + "0x2aeddc77fe58c98d50bd37f1b90840f96ee5a0b09e7e9a96219dd66f0f74c37e8afa4a7f5b70a3e0904168b519b2745aa1480867fbc7db364c79e03fafd6e30ccc1691e7214ef860": "0x0000000000000000000000000000000004b20ba612ec45aa1ccb1ede3e2838ed2b4f5eadad5d80a873d74ead94b9689850", + "0x2aeddc77fe58c98d50bd37f1b90840f96ee5a0b09e7e9a96219dd66f0f74c37e8b299234c2604004face99d3401cb9b45ee1bc0ec52f4cb35914dc5ad27806230534230eedb8413d": "0x000000000000000000000000000000000862be3477b75e8497245a053f1f51f752421fb039f6bfe04a397e85be7e193440f69837f9346b574bee364518dfa08ec7723533632fbabbab594623d83157a67b", + "0x2aeddc77fe58c98d50bd37f1b90840f96ee5a0b09e7e9a96219dd66f0f74c37e8c1c29593b2d5db604c73bb4b37fd89e159ea8dda26c4021a4af572826ad6397d8fa9942c18b3568": "0x000000000000000000000000000000001c58ac509e6e93bcf6ac0800a070f28bd477fb9e9717ff7779d035094e361b150438833de858facacb267fefbade2fe127da59cb1d3653e5acdaf5aaa1c0bb6f255b7812d3e31417cabe45153f522a4047b09e9662795cc7c7372cfb02f6dc39192a30902e14ea5ffdb5135aed31d3940e0df7027a27d079c6a67d135981f4760146a4204de252ad6bb8587604684eb6b0d8d7c5f9f8e7ca0132bcdc6d53131e47c49ea8deb91aae7843e2cdfba3a91fb9910efab535670b9da55bd5abdb7e542a4ea8dd0f74def3f37653a2bc9932edbaa87ba9a185c55cd8b5bd733ea86c6257", + "0x2aeddc77fe58c98d50bd37f1b90840f96ee5a0b09e7e9a96219dd66f0f74c37e8c24c3ef8bc4c3e412c0e71d326f83f4e6089448e147fdab51b0b7398a7d0cc9a88b0571432e7310": "0x00000000000000000000000000000000910112c0e71d46088235059834f57282e18f93197b164a04be4082b6dfd88d86f53112c0e71d466c86c2834663f4edc4bf268a2746f02da7a7334344582db793062b12c0e71d489fee1707d4857f5f4cca6e9ccc10a81fb25b9cdf5c2d872d0f3a5c12c0e71d2a6032287a5bdb910afd1522f52f26c1d619395f3c8d1d18ed23c12b12c0e71d133bb870cfcff34b784d933b5ab71a4f90987f854522f076bd23f21412c0e71cee9f575993304f4b1b5dd21ab495dbad0b4613f39c8c4f49ef24140612c0e71cf3f161c02727017e5ce4f8f6e245fa61bec1a3a1ac960fe11e917c2612c0e71cf41a90f7205b9034bdc9380a95bc18669cd5b4d6b9452f73d468e74c12c0e71cf317d94584299468b9a292c7e69d3ce2ba40e4819166c78dce18e85912c0e71d0d3a5ede1ed512ea065c3970ff43788f057c99ffa3afe8ede608da0e12c0e71d10a91f1a202191134bc06e790e98829eb7d76881e3c8b42dbe8a6d4112c0e71d210ce61c449fc8f5f3f521209d2906e445239a938303741301d0ef7c12c0e71d208c668db313147edb94aa31af86ca4e55d4900fed5eda638862b80312c0e71d1e59aa52904247d6ede8d053ec5c65dfb3dc8c1e632acf34c030a25512c0e71d25be2e5d1c5893ed30710dc6c645e8f26b3e1c3ca43800fb99fcfa4a12c0e71d25d4ac0ea242b6e44fc9625e1a4dcfe17e6cf9dfdc0bb233ec58955612c0e71d364ec914b6b740ad7c055dbd9a15aa2cdf4f6b3349970e15b6b73e0112c0e71d43df157fee32bea33e2335ca841ecf4689f61b53af12109a990e8b3812c0e71d4b14d52ccb248e416cad1ddfc7283a09f2625c601528d29f9a294b4f12c0e71d4ebd6afa6a6462c87da8f8da65e320b207a3958a76e854432b5cdd0212c0e71d56bc0e445558b892aea1eb53639aaf99ec6f51aba44607213c3dfe2e12c0e71d6034eaeb56b1637b948fefd184ecfebeffe8dab40a37c6cdf3971a4012c0e71c47eb3e0eca577bc8ce7ec63eb978b1e36e73daea0449935e5496850c12c0e71c49ca78c235b4cc7c02b0dd42d2ba68cae14091330453206d11f34a5612c0e71c4fcce3bde2baa598b4b4b15e3674286d0dc2c03441be1bd48408d92a12c0e71cb40d9d91814a130bf4ee7008a6e83563520ad677eb2034209fa20e5512c0e71c6d383ed080fca5ac67242f4365fce824e3b989af1388d5a94f38b93412c0e71cc202669b8b8f008fd88fc91048ddec2434e536b37adc066ae2d1653e12c0e71ca519959bc745598c859160abc7bdaac3949ca44ad9712c4a35e80c3e12c0e71cd7c05aaf2bd4ceaaeddad56e206f8b7be033b915ca7e8391aaa56a0e12c0e71cdddce276170fdafc609d13aa23bc51e46a52772dcf1e378130b6b01412c0e71cd31ae09c2af44df1c49f572234348e1637127de385daad38c2bd363212c0e71c92f12577507a7ceef4da940099fd984e976858d6d4c6826ff76e254412c0e71c73acdcfb922d6d2daaca383ec2d7a0cbcfe42ac84bb16da1c25c8c2e12c0e71c9f53cee8937a8a3a30c639efe4e9e61faa222953bfff2cc0a782956c12c0e71c712fc750ea7987ebc3adbf181c53f54133d3378fa5d7268bace38a0512c0e71cac0a27a2fd30bc24907dfcf124197d52af6e9c9506f5bae59bf0887912c0e71c62cf1da0300cb62510765cc22eb8eaf487bd2abe160f4c231e28a34012c0e71ca560b3ce013e7ea6f20692d95ceba300e0b354cafdb4095a94a27e6812c0e71c651e27773fa58160878f81a68b7b054ccdccad776181f757e763e51412c0e71c512bfec8bb542308c909c7b50f401219848e9cd7ee84c2bf2519644912c0e71c89568cdf09515dad33fa70b04cb39e21d8be64dee93e17569f96212912c0e71c65c6d73c4787dc93561ade71071ffc5d78756ba4f606fe91a6e3452112c0e71c6c063c135438f8997461cbe25e61d7569fe4c3f9f07db032f75a581c12c0e71c83c45d50d2f831c6574ab25eabed7842fc69f51bba122c617531d72512c0e71cdeadb03446fd3519d1dcd4f690e40df4ab0d193b476a94a0b6588c2812c0e71cb1a9c147998723d2dc7ef44affbf359be54830a570a5840e2734c47c12c0e71d06dd205beae5054c937e4170b53866e429f4be7a98318c261b3a0b2d12c0e71d0f4707cb93bd1de1eeec36c3e1f995dc51eeedba0cb52287d2fd3c7d12c0e71d378b0a623f2b9eb1b44430061c4f2bab9da7943fd286326a98b54a6c12c0e71d2b06750f95b1dc2ccf25272d0e77de2fa9efb9499be95ef938d6d76612c0e71d5287b03cc78c4c2faefffc4cacd47bf65ba7bd0bc5d4facc08cf932312c0e71d4911dde07af70a1bafe6ae84ef07a43280a736d0c19395a58793541212c0e71d2f08b6d34a5103c892d4baa26995bf4b184eb7507f9e111014e58b7912c0e71d17404deaa91eca3e64e911f5e43ebbfb80fb21f97c4d453ed79bee3612c0e71d5b27b11da4fee8ee2b71b1535daaccd5775846c26ba02d082124466712c0e71d3ed7229dfea16555ba040cce63fba1fa33cd5296c4393fa61114a86d12c0e71d2ffe345813bd81eea02b361a65b0b88ef0e5ee8a0a2268a8ad9bbe2c12c0e71d36450dd3d651da12ea3ff51a9f306650744f4c164ceaa7b2cc08454612c0e71d122033fe390632d7275542273a8afc911afdba254ba4b7f33087906412c0e71d5e85f0442d53fd7419af7a23a2908f88ebcced94150e396bb64ef64412c0e71cb2e754bb49f1758439d6729debf9a30cf5b9a797ec564f00592a2f5f12c0e71c4aba6d53775e0a27ff00a6090b2d9bb4171096109a5aa2a59328df6112c0e71c4dd67a196937bcfc45ed0384d81a3b7e8a5b9746ac82081c4bf3096412c0e71c5200cf1cf22ac62ae2910eb3e485a104f610f1535ed1e844b78e291412c0e71c578bac3ac4c85fb1d9f0645451aa4503782c3f0f3260486b8d3e612312c0e71c6323105cc5215aec99c36c3931fabbe7dc4a439329be146133235a3612c0e71cde22f076b79de5a6fc30cd47be3f5629d4be7fde35d769e7480f491112c0e71c4b17ed34d92d3794d3cac294945580552a9200d74dbaeb0a17a2ce7e12c0e71cdc8163ee018634a900a6e973a87e8740b6c9c4400ca1fae2ac8f4e0412c0e71c9d62c402a345adadf6d07c72b92a9df6035128105150414c0f759a2312c0e71cbbe5966e17c328e1a6f43729e44d4dc326af5ea40f9c0e103b19cf1e12c0e71c74bc9329f210cf3871cb0df4e3139420f8cd1260ed214f6e310d596912c0e71c8c7444fd30b0ba7ccac70112280c31a7b57682c59443918e741b713c12c0e71c471767a1c8d1f0fbdc97763c8730745526c890b3d603d90337caca4412c0e71c85b306f02dce509fbd905815ba90fd450199f70a6e00a5634134036012c0e71cad505181147127f5267ae6187fe470ce00c91bd1d1adfd0227a7333a12c0e71cab33ca9929a6406d6634c55c8d28c63c99b18fb6a2c1eca3037b144a12c0e71c9fdf776b26f8b4def79ecfeb98cf14bba80546f54124e4725da6036f12c0e71c9c7a0df0270f56ecec10f80525ff477398256a84db44f8362cc9cb7a12c0e71cc0578209ed2ff07931f254566de682bd7407f07913ca1c4a30e7a63312c0e71cb50b65d27c7147f5ea52a5a805f8f75301ecb5d9577244659659965b12c0e71c782aad6c734c6714946bf965fe464aaaf2e15c7d43409f936540ea7212c0e71ce93b3b5ce42fde862b4d609631d600ee1cc3f3717268e7b9b3e1467a12c0e71cba3dffa43d603a1637f373c134f4eb3b0ca902a937e218cf992b4f1b12c0e71ccf0639294d8ecb643d6dad93d9660836463f91d1b66292fd9b1ab05f12c0e71c89b2c75caab9eb9b3ee5a918dc734c5c595ee569e64ed37a306de97412c0e71c8bc9217a6448d34afd0c1d226663a864a4141b65d13f8bbc743d133512c0e71ca3fd568c3120f3c6eb7825d957104fd5e9bd9848ef36a1d5de03b00812c0e71c7daf0347415ea3623b1441a1f89b5115bfe82a57a132f72d186a246912c0e71c9267977ff8cfbf27005fca3918833daf0d77537e8f879fb9fcdf2b0912c0e71c55443e88a1777244fd0816a9f44562ca36e5b9d95d45f3d79a1cb56012c0e71c508ea654da98971a9a27caa027e9478b84c319ecc1fb63288ffd9b0d12c0e71c536b024440ad0fd64324c6eebdc0e497207ff42489ca8a2489f6e32712c0e71cfab0ec8e02f65d8114492d2c9177d3add541219bd8ddc00ef4e9b66a12c0e71c648c0ea092b2481ad9657956548a531fa3a89a140d3d8f9359fce54b12c0e71cbe21aa863d666ff694ca4aa3a1f0e89a9e75ffcdb6c629fa1d00646012c0e71cb214fffe90a9fd96c396cd776ae64fe664bd26e6072e7328b1df575612c0e71cae4be30aa91dc1e77bf2bde98af86c4d385e9c0868d8af4a5025880312c0e71d330bdafa9c3a6218dcea201399a6cfe0fa73c2692e7a83492614e40a", + "0x2aeddc77fe58c98d50bd37f1b90840f96ee5a0b09e7e9a96219dd66f0f74c37e8d136d7c7984d254da01077bdc025fd779cc21c9760727ec07e52aa132410b82e5fabacb6f45b055": "0x0000000000000000000000000000000004bea06b45bcad97ae3126af1a6e864197180af4b7e6513da3032228b2bdb26368", + "0x2aeddc77fe58c98d50bd37f1b90840f96ee5a0b09e7e9a96219dd66f0f74c37e8d5f7ebde4f481a866f7b3f3db597d3032c2d767568aa550249c946600a61276910b9c1d21a93371": "0x00000000000000000000000000000000049c674dc7b750bf4d5d5d0db23578adbd9602cac61f6292fd788879a44c87256a", + "0x2aeddc77fe58c98d50bd37f1b90840f96ee5a0b09e7e9a96219dd66f0f74c37e8e029dc73c6ca9b6f00272047a1369138c7948e8d193757bd7d6319254926d2b91175398d8250e30": "0x0000000000000000000000000000000004ecd0f078418756af923fefc497d98efcdd243170af2694cb75a2becfe2811732", + "0x2aeddc77fe58c98d50bd37f1b90840f96ee5a0b09e7e9a96219dd66f0f74c37e8ec37554e12de10ab08b555a5a3b2725e01ba15eb40aa32dc5b781532854b797808ed45e752b047c": "0x0000000000000000000000000000000008d85561d4ee89c473f4220a4a5ca0c8eaeb01fe8d0740aed291ad796d4b2da175821bc7f162ddbc6418c08a018d072e2980a4257c8584435e5b6251f6e27cdf19", + "0x2aeddc77fe58c98d50bd37f1b90840f96ee5a0b09e7e9a96219dd66f0f74c37e8ec91a2d2c36d0707a8b217ad8d80016336be124846210559ebf720aecd25ea0d0d11c10f1839e71": "0x0000000000000000000000000000000008d84e08c6dda9a41fd1d44b01b65c7787b48723679a1d0c83d1d9a54798ccf01e5e11390e1f7b87f6e2a59603d7979e4e26259c41f011eba0e6f3ed6996e7151d", + "0x2aeddc77fe58c98d50bd37f1b90840f96ee5a0b09e7e9a96219dd66f0f74c37e8f10571113e0ae6b447326399643ec639a0bfde97d8b37f8dd0ca9fcb3c74a1ce017f0476f3e2770": "0x00000000000000000000000000000000041644a3ce3456b8954eeca77a5b67d7e9d26eba9f922b82daff95057f543ed03f", + "0x2aeddc77fe58c98d50bd37f1b90840f96ee5a0b09e7e9a96219dd66f0f74c37e8f88e4319e34d2ea16476866c0074663b7d9046023a2b3fbf447c833f4fccfa3dd7a482235f1ec7f": "0x0000000000000000000000000000000004848acf74babbd40295e54caaaf41e505891996968bee93eedcaa8e5b4105c779", + "0x2aeddc77fe58c98d50bd37f1b90840f96ee5a0b09e7e9a96219dd66f0f74c37e8f943fb275b495a03e3622fb285dddefdf8f9ac2ab59aa34e2abb5a316e9ebdc020317220e75f879": "0x0000000000000000000000000000000008a227e750a30259349ff46ad36105156f552fedee92bc3b81470cea913d30d6cde81c8e2c7bc6a6b6de522487e8829344e992a3440f957a52c86d93038b9b3dc8", + "0x2aeddc77fe58c98d50bd37f1b90840f96ee5a0b09e7e9a96219dd66f0f74c37e90073106f69e036ffaba4f34d61e2defae2db1f7c712007824c194ad921959efdb4a65dd174a590c": "0x000000000000000000000000000000000c40de8fe2227bbb0358570c01c31ce0ebb4b7540c1302ab6a6d021cd0ae5d5942f206c1276f16bd43aca4fa9d596a7164a310b83bdf34350c1480ed4854cf9729a83fc2798fabbdc8d93db99a27dda9b8f6615cfef0b16a3a0aca93a49e527475", + "0x2aeddc77fe58c98d50bd37f1b90840f96ee5a0b09e7e9a96219dd66f0f74c37e90b1c53cf7dcddbd8a320af9e031a3396f15acdcc65c43008124068226505ee7e12bbb0a12012e60": "0x00000000000000000000000000000000088478f51feef5a376deda20303e61c855e0b96451f692ead53d838130bce9cd086c98dfc795cd34290966dfa3a4f690a2c703dfaa31792854885295a61cfdd670", + "0x2aeddc77fe58c98d50bd37f1b90840f96ee5a0b09e7e9a96219dd66f0f74c37e90b34a3937b9efce6482a21b7e92055e74bc9b182ded5b0cb86e6f7706090c916f60e8235b8fe51a": "0x000000000000000000000000000000000499a833467b3227e480dd06ccad8eb537c399e3851d8acd1b3d1c3e711db83686", + "0x2aeddc77fe58c98d50bd37f1b90840f96ee5a0b09e7e9a96219dd66f0f74c37e9155332d1321391214cd612ff7f390b9e90584767a00a4e9b740b61c0f2134698bbac79c6649764d": "0x0000000000000000000000000000000004c61e997a53022149bda8907ce19e1780b9ae75e23fdd6b44fd5a6adb4ff91801", + "0x2aeddc77fe58c98d50bd37f1b90840f96ee5a0b09e7e9a96219dd66f0f74c37e917bdd412b89d0510cce9e210c473fd1f20178fe889c178956ea1cf325c54b1a439a88bc62fe7851": "0x000000000000000000000000000000000434fe2832004fffcc1e28aec7ac35d29142b892f10d8d0c301cd26c37860a0579", + "0x2aeddc77fe58c98d50bd37f1b90840f96ee5a0b09e7e9a96219dd66f0f74c37e921d891bcf4e728ce683743954d0cb555a54ab21cfb8161f74e689a051d1ac1dbbb94df70be3d81e": "0x00000000000000000000000000000000084409776e3d248cea53e8d6fce41bc1795b83793fe794119a63b82a7e837e9f59f45cc1889ea605f6e375289fdb22c1acf7e99fc60cca3ba5cad46a21661a7720", + "0x2aeddc77fe58c98d50bd37f1b90840f96ee5a0b09e7e9a96219dd66f0f74c37e925643626036602a9a92ad7c6dcc51fec9f6d98f8316406ca42bd04dbb029d3ce454330a20fac077": "0x0000000000000000000000000000000008148e8ac56079d875671a8e379e8ce3726be04f32f36a3f8237c2713dd354be1bc6379520320c2c68f6e75938afa22a71c7f3bdcd1308ba1e7795a2fa2d9b9066", + "0x2aeddc77fe58c98d50bd37f1b90840f96ee5a0b09e7e9a96219dd66f0f74c37e927911426652f14cf4492a28ead0b315fc68069bcc39470c409d12b4e48259384d63da411bad0129": "0x0000000000000000000000000000000004d448d47466cd9abc75c90e52f3aae5d03e772ca2f13db8516aad2ec15d341d2e", + "0x2aeddc77fe58c98d50bd37f1b90840f96ee5a0b09e7e9a96219dd66f0f74c37e92b894b9740836cdce2e98564f421ca69a64608d68480080f5f317f4de4e400af3c065181e0c8a11": "0x0000000000000000000000000000000004ce2e98564f421ca69a64608d68480080f5f317f4de4e400af3c065181e0c8a11", + "0x2aeddc77fe58c98d50bd37f1b90840f96ee5a0b09e7e9a96219dd66f0f74c37e9446885b0b18680ae8e0ac0aa68a0c138a3aa84813f0accae4ed7d6ae4b4905495026f16eda4e069": "0x0000000000000000000000000000000004e8e0ac0aa68a0c138a3aa84813f0accae4ed7d6ae4b4905495026f16eda4e069", + "0x2aeddc77fe58c98d50bd37f1b90840f96ee5a0b09e7e9a96219dd66f0f74c37e9464a51c61bcb648ee56126859de69a3539f0e8910ca7e775243f18c6257954a65e020eb229be912": "0x00000000000000000000000000000000043e4473a8a5c626a2b1eab5002c13537480b487a04ce85ae09292a7c458b3be06", + "0x2aeddc77fe58c98d50bd37f1b90840f96ee5a0b09e7e9a96219dd66f0f74c37e9512e7cebb2ab2b2206dd955d4ade8d59bab18cba031e664ae888491d173084bc9a0efabf0be195e": "0x000000000000000000000000000000000454c3bc9063fba6c75163f3e051f1387121c0120d3bfe764e68764f02ea33bb48", + "0x2aeddc77fe58c98d50bd37f1b90840f96ee5a0b09e7e9a96219dd66f0f74c37e95e5354b81f0f460da9f7fd3d9612a68d2ead69dde53297b172b7db514d0d261e7c5be987df7f32a": "0x0000000000000000000000000000000004a65bbeb4425c55a611da4116e848b0cc39686a11f88dee6aacceac6bc5eca657", + "0x2aeddc77fe58c98d50bd37f1b90840f96ee5a0b09e7e9a96219dd66f0f74c37e95f941adaa91654a28322946bfaec48af9564e56ee4134655dc1748ffc206c3694a9c6bddbe8332f": "0x000000000000000000000000000000000438684912197a8fb0da1f815281bb2f52f170d07b4d96450ac6ac06cb4bd42d6d", + "0x2aeddc77fe58c98d50bd37f1b90840f96ee5a0b09e7e9a96219dd66f0f74c37e9639866340f488369cb0d4ddd32f9332dac7059de238b8e489afb55502d1756d7f50b78b58e20c70": "0x000000000000000000000000000000000cd07218db071b0b88f5979d57b52ad2b7706856f7be0021d30df75fc9ecfd2f64ce4f4b5eb5e648247f1796de1f52ccb6d6e763684ab786e21239f26af6d8d252703d07f2ac096e6b0b998fad5997c7c9b1e1f417603c350e76ad99e5c19aec04", + "0x2aeddc77fe58c98d50bd37f1b90840f96ee5a0b09e7e9a96219dd66f0f74c37e967dd10b13066df77243fc7f5f476ee7c5fad9de673f1ccfdf59c3e92530c09d6d584ff19452c87c": "0x00000000000000000000000000000000047243fc7f5f476ee7c5fad9de673f1ccfdf59c3e92530c09d6d584ff19452c87c", + "0x2aeddc77fe58c98d50bd37f1b90840f96ee5a0b09e7e9a96219dd66f0f74c37e96f4aad0cdd32c3e8a6d7fd62a2ca5609d25c2574a275de76a6fc5322482aa0b0d29f0a8f8f83b53": "0x0000000000000000000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f96ee5a0b09e7e9a96219dd66f0f74c37e998cd9a07d23d28d50ef3cbba6eefa5127e662a1286c69c3f8cd10aa328d394df9e69919af449b45": "0x0000000000000000000000000000000004f4c6e1ea78fa82de3a28d27e20c93b4b8109fd93489d864a73fe7bd4eadf2061", + "0x2aeddc77fe58c98d50bd37f1b90840f96ee5a0b09e7e9a96219dd66f0f74c37e99ad9accdb6256f3d8783497b4c06f05dfa6ca91a0502e77ea7ffbc5c33c7142a5d9d1f0322d783b": "0x0000000000000000000000000000000004740cfb483a7e7c4d04abc9fc3651beeaea5633eed75f65c0380d424312412357", + "0x2aeddc77fe58c98d50bd37f1b90840f96ee5a0b09e7e9a96219dd66f0f74c37e9a24c66abe29ea3716d5b643fdfb1b22d5dfd3a50157104df0580c910d2754987afc25fe0aaf5827": "0x0000000000000000000000000000000004c05795cea6af4d0bb72417772d60d0e8ca43f5790448fc92f764088b0d4f4b1a", + "0x2aeddc77fe58c98d50bd37f1b90840f96ee5a0b09e7e9a96219dd66f0f74c37e9aea00c445f734edbaf3f15b9e83dcfc18b50fe91e601fdf446c008c72c3d17799c21a64877e8d3a": "0x000000000000000000000000000000000420f949b07ac91763cef16c15fb78d5370271add31799ab7ea2e940a89af4672b", + "0x2aeddc77fe58c98d50bd37f1b90840f96ee5a0b09e7e9a96219dd66f0f74c37e9afb96de5bd6c558f6b21d624832094b03aa672e016462a020e217cc67b1434785b99114a2b4fa5a": "0x00000000000000000000000000000000a41a7938fede32e1275281b3eee5708706d88444a6dc898a4dec463f1eb298463fca2ecbecab066ed29eb6f04bc145a5fe6ee36cc0144f46a722862cf28dba2c6768ef8bec8b0e59e7c456392b9f560a48c0abc26faeb75715b1ec4a804f469f10d618111c1eb2afe48d95bf0501243748e399e23a538bad0db61fe474f4f2b90f14ededef8a62c8642099e5b094ef95519a5e2a1898ec9783c2bac2c71f71cd160cb5554f54c346c7996d2f6ad6c5bedcdc094b6ce0bb9a4afc7db6ae865cd378bc921beb233fc0c3ebb3f98676aad4aea89f81a08f57251e24e2c02f0dc0a901de89b93418a2be5e997eebd4b815754518fc3b7db32b2c31bf97c8297f8ff7528886a23f6aa185a4d262ade722584c6f1e384ce10b269bfb898abf8785cd934a92f63201ab158aa8283fe585a2bf19ceefb00c45eb7b9eb6063b2ee66a108532caa6c46edcc1d2a38bbfc4e200c3851762178268d7a3e565ab99728c18ae037654f79360caefa910ba4bc6e26760fbd44a07a9fd4244c6fc7f58b0ce620fe15c10448cf888bdc13a933c0d1d33653f83d3b34bd775038e0f5900c5363aafee013245a2e5ac185dedd4f63f9899990dc2d467a359dd573a7adf0817e06948451de62bfe4941f647a18c74850008608346ad2c9623378dc3b8856f4d9a17ccb17654ba6fba820d02b4f0def9908ed99ed988d415d9b7c272a1d9394fd670ea8950886a977a6d8063db1b9c58daf3906841f3e2577b07cee9595c5c7e98f7b3aa6612c7ad0576988c680601696eba2ec9b035e6f99fc5579637089d06a24d3ff650a057612349296f2777068dd47c499f36c5caa498c22b48f26c09b9498ade826fa6b7d31c38534c4c6dd648a247e5ed408172cd647084f554747823fe69304f43282272e3e8b07aa02117d8a80fee926dde3a9417a2809b971623dcad89445a3f9ef20ea6b98e87f656d7f23e0b2a310f45d6a6550a211e7df67540cd8b9c4b4aacf39cf23dd3530b4078b43141f0a0ce5c19549909b0ce4bc163984e045d9b652ad8cd53e45f24d5e7c2cacb60dfc3a4dc6260682150104828e62d3a0142c0082e8036bee650826ea445368d4643b0ad2341924bb357c8ee1596fd1235ecf32616bc1a5fbe6783b4c4fa8be371150435d5cace22115338b33a9966b4de2ef82df20bc9dd454ad586a9c7d259068e87412a8ea309a006e06857a04707041227017e437bd1edbcf02649eb8a4103c8668f5903ceffd5b2a4215c0d211affbe5f6cc20f540f6c1dc4dba60d21936788a5bc5628f26333e27b14cd091145d92d8f255055807b7c54a1143ebefe17d711170a5971227a8a8b593c769fdce803812028407201429e0f6beb3a79213b46c4f59f002ff4da66dbb0bfcb66cae1cc1a50749cbecddcf7044de2e7f8aff6dddd8660e28ef5214c59623dd37a62d950da795f70f955feb0ffd847cc972e17e979619e0bc0739673db8604848204bf61af00717afc36665eb89509814350a32bc136f095dc1c9224dac890c0112b5f4b53ac6c086f2422947fdbebd39a68f8708064bd5d9caab70d1d6a51abff895db91f56551244669ebe06bb78a7513e888ab43c70dd2f0c80e90189b02fbf62ecfdfdf66f54572de1db5ea15bc7731401c4fb92ba2ab3f7c387acdbbc2590a673bef4e2488ca5a28e878867689b757883005b39b269cc76cffb757bc672bd9cb1874cd505d2f17cc6203b5746b14c65b94077e29f02d0b1d56a0ba445458c2d7cf9d55a54e8e0a4bce889b5d71d9c9dbcd6687dfda6458cf22bca0a342f5db49d8258ca6a72f67d9caa91e4c5777b9edbb0f7297d7f294627685c9af7eab3563ef66ffc20", + "0x2aeddc77fe58c98d50bd37f1b90840f96ee5a0b09e7e9a96219dd66f0f74c37e9ba746407882e793d49fca4c127d246783d23e388e34c09446b624d2d5e1f7773c9590823d451019": "0x0000000000000000000000000000000004285f7ae7cc2580d54ec3be6fb7fa3ab6f2c1a32352c793b29163822091839e31", + "0x2aeddc77fe58c98d50bd37f1b90840f96ee5a0b09e7e9a96219dd66f0f74c37e9be10627200d7958fa65ad25c6a51ba28504fe803d9e3d542135924ba9fc0736cd3f1d9b83901778": "0x00000000000000000000000000000000048278ef29ec5edfc3f2694075448853b34a387e0299bcc326c41e9507a5f0ac2f", + "0x2aeddc77fe58c98d50bd37f1b90840f96ee5a0b09e7e9a96219dd66f0f74c37e9cd04164b151c8211a903015b9ceaaf0f183eb409d3a38c4f0c9a685066ed90b32c834940c689e1c": "0x000000000000000000000000000000000444ed131039b1a6d98896aa12e996d928f7adb00a832fe5c11b719e7d4a4d9b0f", + "0x2aeddc77fe58c98d50bd37f1b90840f96ee5a0b09e7e9a96219dd66f0f74c37e9cd0ac122701f28d7ec5e89c029a05224b2759566042a94c54966d125934a8ff8beb8e0b017cbd67": "0x0000000000000000000000000000000004e85558af1d02241a456725d7ae7370cd1a5299713a970a312c99d9b14d90debc", + "0x2aeddc77fe58c98d50bd37f1b90840f96ee5a0b09e7e9a96219dd66f0f74c37e9d20d76620b47fa66610405d8ddaba4dcfca1fe4d14f83496de1055fe97efca594f2813a82900e40": "0x000000000000000000000000000000000452acbe4b065282c5b36e7c1b552ccd1bae6039f9e2abc5fa4be566a8f5f10e45", + "0x2aeddc77fe58c98d50bd37f1b90840f96ee5a0b09e7e9a96219dd66f0f74c37e9d34cfa440b95864d3754204488186b41e90a93d0607992b9cb992932ff66c2faef8a984dfe4a234": "0x0000000000000000000000000000000014d3247cacd091a8f95e795c76e84bc34db75ba76e13a79c1c4671f12f433ee83dd376b1daf289d513fd22426812d5a7c48a58dd121e4c043627e00fd216557873e5c49f7bc76b9e1b91566945e2eb539d960da57ca8e9ccd0e6030e4b11b60099e57259886f2db2014f3bcf26e8baa581816f49c13e010bff9f52d5d9ea3ae68ae573ce3c1ed2c09f46eef869e472f6fc1e1345949d22b585d2dab0198ed34727", + "0x2aeddc77fe58c98d50bd37f1b90840f96ee5a0b09e7e9a96219dd66f0f74c37e9d41368f1d880a3b3ef88f51188ea054ff03b902d8706c6d9b1ea56c119b34e0b88e915b5d02da5d": "0x0000000000000000000000000000000004f86ca83eaea9aace8ba08ee406a2ca470fb8d274a9fb496cac6e8797721c5977", + "0x2aeddc77fe58c98d50bd37f1b90840f96ee5a0b09e7e9a96219dd66f0f74c37e9dcc277753735b96e04ca25cf1cbc516ed1c138492a7f2e606f60c5a9ac96cb405eaa3914fd12973": "0x000000000000000000000000000000000884e7a9749fd2b23ce7f7b775dd0f3808d6cdab42ba064fb242afdf0283e60a20d6574db78e7c0315546032b1775930c40d4cca7562e9210cbde93344aad7aa54", + "0x2aeddc77fe58c98d50bd37f1b90840f96ee5a0b09e7e9a96219dd66f0f74c37e9dcee803646fe05ab0ef511fbed15d88d75933d12bb50b56d1bbed109380b2fe0c7ec72d44119152": "0x0000000000000000000000000000000008ac0c25ae153af1c54bd0eb9c02dbd01e3b462be18089e560a9cd19890dceac6e90255910ad0897e5c6746e33cf138d8f38a6b46b685d06da2802f83917827c04", + "0x2aeddc77fe58c98d50bd37f1b90840f96ee5a0b09e7e9a96219dd66f0f74c37e9dd0a74dfe9045f7184d701295be7bb38b2c0c58a35bf8edc592671c53d149d206e037dc7c9beb7b": "0x000000000000000000000000000000000c7a43965f93ab8e28323fe1c19ce8156b9d0a941e56661f2b172da1bf74a2de64163c64722e9d2ead4a7d5d88e4a3e565737094f0d4bdca0fc90d6870a8d1271e807a095defd81e409429e0f0036df659f3472f90e3b9376e669b71adb898702c", + "0x2aeddc77fe58c98d50bd37f1b90840f96ee5a0b09e7e9a96219dd66f0f74c37e9e5b705cbdcc776ab4410d33f13c053dca87be657a0ae3cc87655baf43f7efdd454ff74e3a9d8a2f": "0x0000000000000000000000000000000004882b91920f9e4483d2910d72403ecc9522283079ff6770b58be852648e008d44", + "0x2aeddc77fe58c98d50bd37f1b90840f96ee5a0b09e7e9a96219dd66f0f74c37e9ed6094855a6dc83081c465a655cf27eaa73bdf9554abcb46ca2d56fe7fb0a20835c1a5ddec4a325": "0x0000000000000000000000000000000004051e046a4125b20b4a9df6a8d1d5f81f6155279dfaa2050c7970d4470b890e8b", + "0x2aeddc77fe58c98d50bd37f1b90840f96ee5a0b09e7e9a96219dd66f0f74c37e9ef6562b57d1a60490c7f4e84347dc6e4e176f9156b2347378faa9b538a857b404cee3e341706305": "0x00000000000000000000000000000000082d2a9ef6dff17530bba04671deccf9754c7cdf0b079e0ac825a43c5c0e274620e50c1ab151d60148984c5494bdd23ddd7e5520a8b4873de12ca413a6f37bc3cd", + "0x2aeddc77fe58c98d50bd37f1b90840f96ee5a0b09e7e9a96219dd66f0f74c37e9f053c2746e722456610a5024c2a5db3d02056d4344d120ec7be283100d71a6715f09275167e4f38": "0x000000000000000000000000000000002c0daa7f988ac07541286ffd6ac83affa9d4f0e119c04eba5f1fb74e51719867c983b401968c58e31e421f96e07dd85ce91d985abbccc84bcea5e8f098d97fab563159dccdbf4c37ba277b4becdae7ef002bd7ab17d62fc7419dd68967e41a358b7b9a284d4e600ad4d23bcc2a12a3e52130d96586145ad8246bb3db4a7cb2e0f0e8f0c9814b8cfe6b4a46e4ee7f2b9fd93aa98485c646f07e973e57293a107059661242bc6a8ea761d8668371ad17f9d036982ffbc68af2c28ebcbf2d30ad16e1fdce688a422833948306f4aabf043af4be9fb2be40fc763787f30233b2510573dd2404caa71709d521271bcd64cb771df96abc1454c1bc2db5be8fd84f9f317dfdcd5afc6aaf6c47e499c5c21097386bf5eeda93a13448eb7b9ddc4fcd0e13a413dbe68838d76d77ca594e3e55c937ef7886fe2e8e46de8fe11f20cdf106b29cc09b9c71f2c39942154cf7749268d6978f82a55ab68d6a412c628b2ced7f9d3e", + "0x2aeddc77fe58c98d50bd37f1b90840f96ee5a0b09e7e9a96219dd66f0f74c37e9ffd1362c0ca2353c85cebb3f21b5e97737a7bbc14d8376a79dbba9c2849a28edae77c776d1e4a08": "0x0000000000000000000000000000000004ccba4ab664396955d9309b5ddad39f02b7cbbf76743a9e8969949c3e8a2f5ea4", + "0x2aeddc77fe58c98d50bd37f1b90840f96ee5a0b09e7e9a96219dd66f0f74c37ea062138be3539cdbd8876695e0680719107b9ccb595ad5d8bfdc4ccc8e8e4656091fcfe652c0f155": "0x000000000000000000000000000000000476ad7b338e915c739fa6055381d937bd4541d12ca755533161da8611aceca14f", + "0x2aeddc77fe58c98d50bd37f1b90840f96ee5a0b09e7e9a96219dd66f0f74c37ea078de63f42f4d3d89abf449cfb7d9b862b775abe556bccbe647820fd4d7a50b63872b657c96506f": "0x00000000000000000000000000000000045883a7c739d00f1d125475cda89e7ceff0f406badf56a7c1270c16f850f62cd5", + "0x2aeddc77fe58c98d50bd37f1b90840f96ee5a0b09e7e9a96219dd66f0f74c37ea0b881b0063a363a02bf32e061073c44300056b416cd66a4fde1e6c120dbc0089bb65134f5693a3b": "0x00000000000000000000000000000000042eab66a1c3116f15f55dd2996db419e367106043a4c5491a5eeab1d33a17460b", + "0x2aeddc77fe58c98d50bd37f1b90840f96ee5a0b09e7e9a96219dd66f0f74c37ea0c7bc8aeaa262f14ac4eaed36e5c54f045b46cb54f533b2d3949c0ca7137e89ef03ee3f56f8155f": "0x0000000000000000000000000000000010c0e9ec31daccb76e9baaa030b5780a85787b3f1e2ef54fa8f4b857c64552a4e0a28d12dd5c12e1bc0f85ba2935bff3b257089ef59869ad310056febaa579395996043b3a00f3e936328165ca3f780b594dc2ff0d9e72659a9e13ad74c3bdad4b8be18f3fe77e8807a0fc3201a7689f4742a12ff44622e1dc241d1a08088ab6ec", + "0x2aeddc77fe58c98d50bd37f1b90840f96ee5a0b09e7e9a96219dd66f0f74c37ea10e77c34a7d9ba5b8a2a7e1c5807c9b5241a00382d483537eeaac2fc756dfde564af6a368fbc275": "0x0000000000000000000000000000000004af5a44d6d0b15f2cf84afdea4c76b1321f84da230a61b0c73d755d9cf5171a6d", + "0x2aeddc77fe58c98d50bd37f1b90840f96ee5a0b09e7e9a96219dd66f0f74c37ea11a320b9a8feb01f857311106c8d7b0daf6e096db9a0d759b52403e439ab23fd6559780a8b1c803": "0x00000000000000000000000000000000043a337becdfacffca71fe67fec208733754f035958d349d36b30225fd47798f6a", + "0x2aeddc77fe58c98d50bd37f1b90840f96ee5a0b09e7e9a96219dd66f0f74c37ea17e7770b29efc26845498df40e85e2ba9d9e213d1f476e7b147aab6a9098f1bb250e00251ef8f5c": "0x000000000000000000000000000000000c2e05b8c395e198a2efa9bcdf3ac31424d984bb2b9a1cd6635a6e60c9b6a0097b28add2af7269292c685caa58101bae5d78297eff522e3f6b239fd4fff6b5213239083183c6b196c695c642c6e521ecf55a337cc2bd5df2df8fc6d6c0c7d49c7e", + "0x2aeddc77fe58c98d50bd37f1b90840f96ee5a0b09e7e9a96219dd66f0f74c37ea20215acf2cee769a26f9a811e752199217945e52bb96fb08229d7904bc030f6df73b5b4e6bbdb6e": "0x0000000000000000000000000000000008645903e6212a6142af81631297af316fdd60dfe4f02cfefe20d20153e7945720ca66d6f03e32d64a1a0b23baf1da3ee469d7d63c69ca26ccf3b47752d1171d02", + "0x2aeddc77fe58c98d50bd37f1b90840f96ee5a0b09e7e9a96219dd66f0f74c37ea2aee766ebb6fb7c4edf81ba4fbeb6ea13cd45ba93cc1d689a6e2e5c6dfc35a458a971823a324218": "0x0000000000000000000000000000000004aa580379e5714c790f17e4af93773d158e30eb08f5a4d24abe4f535776b5721e", + "0x2aeddc77fe58c98d50bd37f1b90840f96ee5a0b09e7e9a96219dd66f0f74c37ea35b58e91836d05e60c6e940d5c74596755e6bb1b31ec98958db10d841dfaf66954b5542c95c462b": "0x0000000000000000000000000000000004a46e73069e5a05c232b0487e1523e7a426270e43445d0dbc1744222fd4f6881c", + "0x2aeddc77fe58c98d50bd37f1b90840f96ee5a0b09e7e9a96219dd66f0f74c37ea3833fe87343f3df36b5dcb29928d8a462f493e0250e895158fc4fc54eb5d00a2a6701fe36a4283d": "0x0000000000000000000000000000000008e79c699eb894e1a203b2c6deeaad557fd51fa352841d2d178d3bf78aa0bb1172dab0125fdf270b1af39164693d9bb3251d63b78742a99693632359e0dc6c4882", + "0x2aeddc77fe58c98d50bd37f1b90840f96ee5a0b09e7e9a96219dd66f0f74c37ea3a4e6df5615cbd134a3f0845fecdf74f7aeb569953da8cf8f8217a9a167a4e7d6b3438d8bb6d828": "0x00000000000000000000000000000000084194458149444dc0e0ae7addb00b669d89f3979309ef9eb635f148c2b879e8784e3d6c92a32e9ec43fd78e7d7b967fa28ed347d96028d73f37113300cfa565e5", + "0x2aeddc77fe58c98d50bd37f1b90840f96ee5a0b09e7e9a96219dd66f0f74c37ea409a5b38e9a0943eceb07c477bd40d22f83b08cce78f2375bc1e4cf188c0de1ffef592570383e59": "0x0000000000000000000000000000000004ac2fb3fedf57f058e0c786f94c46f57eb68ad57982f0b96f56d5d438119ebf37", + "0x2aeddc77fe58c98d50bd37f1b90840f96ee5a0b09e7e9a96219dd66f0f74c37ea443701cf93179113acdfb6cd734dd3e624b6512e0903724c1c90a516c03c81a9af756491ea8e15e": "0x000000000000000000000000000000000424102b17c177cf80ebd64796a17ea2c44b68aca3a03fc35be96f6d3ffc60716d", + "0x2aeddc77fe58c98d50bd37f1b90840f96ee5a0b09e7e9a96219dd66f0f74c37ea46019660a76ac1f5889dcc187231dbcba0bc0dad136d1ecb09633bc7cd5e27e04daa0277009ff2f": "0x0000000000000000000000000000000004e6a1e58c3cb43cd4bc65bc251f9c7a1a3de5bc3f815a643d658c8c018158aa01", + "0x2aeddc77fe58c98d50bd37f1b90840f96ee5a0b09e7e9a96219dd66f0f74c37ea461cd7dfddc684c664b2886e95f12e168b420f06b90c11d8cdfa7ee747bc12e235a6d5efbae6e12": "0x000000000000000000000000000000000416cec430366d2ba6b46f6b084f62ec4f76967ec6fc65101e6de60c92d2751977", + "0x2aeddc77fe58c98d50bd37f1b90840f96ee5a0b09e7e9a96219dd66f0f74c37ea4ddec1e6dbcf011629c17f4f4a24ec53f85a7beb1c70b13379fb8e4f969560704d2c25133ba8d24": "0x000000000000000000000000000000000c468a99f3bf7d3a5ec5cd3932ffbb436ecd78a9c635286d544661acd5f9f8de15d4fda909c31173d9691cf6c488ffe22b46c795d0bc95aa062bcf08f414c4655a669bfe047c0962dc3ba330b1fb1a83c5cb5262c964fda49b61e9f98a8c759c4f", + "0x2aeddc77fe58c98d50bd37f1b90840f96ee5a0b09e7e9a96219dd66f0f74c37ea59acabf7cc5c2db3a0b67c6e4b35133a18ff9c3b56d6cd28662f9e47f38afbfc508543087966870": "0x0000000000000000000000000000000004cacacf100cec1782c4f9342566de5b4132a012335481dc83fb4d42bcdfcca853", + "0x2aeddc77fe58c98d50bd37f1b90840f96ee5a0b09e7e9a96219dd66f0f74c37ea5db7a2686e7ec402cbac2d6ac81d2169fa6e455b0497cf0389bd5dd2a11b24a53e6d94053765a77": "0x00000000000000000000000000000000042cbc13e6be77e7af272d495780c1b51130e27e41e95d8d651733b53630b3900e", + "0x2aeddc77fe58c98d50bd37f1b90840f96ee5a0b09e7e9a96219dd66f0f74c37ea60dad8905663a8126acb4e6372fd11f9cf419b845964385848977d6e37b6221ea9d69d58d27d623": "0x000000000000000000000000000000000826acb4e6372fd11f9cf419b845964385848977d6e37b6221ea9d69d58d27d62326acb4e6372fd11f9cf419b845964385848977d6e37b6221ea9d69d58d27d623", + "0x2aeddc77fe58c98d50bd37f1b90840f96ee5a0b09e7e9a96219dd66f0f74c37ea64992f36040c17f4866f45ae7b07019c03464e3c8c1324e96d3f05a2c5205e889fe597b0af2a70c": "0x00000000000000000000000000000000082add23627ef63d51a47ec9d5f0fa0d06fc3dbfb0e84183b90a13f072cf735300769bde86b6f4610d3b75a775d3cc411da01222b117e84073f9fb18e5a89de715", + "0x2aeddc77fe58c98d50bd37f1b90840f96ee5a0b09e7e9a96219dd66f0f74c37ea64c3dcbca109f3eac1d2d82c4a69b16c3ce9eb5d0b6f34f948a34efe62488879a514bbc837e0e50": "0x0000000000000000000000000000000004502d8f8870937f44fb43dbda57dea5b07eead72982b0712bd52a5e033be3b031", + "0x2aeddc77fe58c98d50bd37f1b90840f96ee5a0b09e7e9a96219dd66f0f74c37ea708d9865081ec8abe4bc35b26cdc006c69c1f827d4bfa75e4bfd4ac0094ceaeec8ac70469cac51f": "0x000000000000000000000000000000000462ef7ddde3d6fa33e5b617265ea9af26a64e1248c80b7ac1cf2df7b171889b6e", + "0x2aeddc77fe58c98d50bd37f1b90840f96ee5a0b09e7e9a96219dd66f0f74c37ea88877471b8c0203f6944b2b5f590f132203e5dd4f04c56e594f43b5681a48b210899382c3880b4e": "0x000000000000000000000000000000000482f53c176ea7abea9092ab9b7ccb5506dd3c81de6fe0a5d2b29068f53dd3706c", + "0x2aeddc77fe58c98d50bd37f1b90840f96ee5a0b09e7e9a96219dd66f0f74c37ea93c6e207f351cebc5c184f0565e2192d6aedae584ee736cef875f0e1c558ee3ede26869acd0b4d6": "0x000000000000000000000000000000001831918cb9b9c9414a2cd4dd7f720cb98fe98cf852636fc4860845767989127e7d6621dd4e5cdd0ba737c572710c13df35b316d39ecd12c1ae1320bd6db069a07adc0ac1271ef05bf490a482a38512b68548cc3c244285635c32ed242b33d79dd2b18c6f19f15297b4a80fb9f6f29a37e06bc31c723be672d54b45ed42feba74c0ebeb68d26988495f05130309042532d32304be1b171fba3f5f2ac94ef7d33dcd1907bcf63ee4c58723b0457cc8207bbb53841e33ce3d2876f8cef269c5d4d3af", + "0x2aeddc77fe58c98d50bd37f1b90840f96ee5a0b09e7e9a96219dd66f0f74c37eaa66c809e7c7caee244a202cd6b29e2026b65a07c3fb32422138a122e581a627e35791da331bc905": "0x00000000000000000000000000000000049083308a14f56003ddeeadcf3e12c5f3685f05393380a47adc6be23c88d8b40a", + "0x2aeddc77fe58c98d50bd37f1b90840f96ee5a0b09e7e9a96219dd66f0f74c37eaa92eeacb2f4017c0a409ce1eed912358015a8139383b02292284b392bf23ef9eb89c7f31ed7e10b": "0x00000000000000000000000000000000043c667aac50304fdae4ba9932ebe5628ff1e133986bb2e1ce686f28c6a5d4ac27", + "0x2aeddc77fe58c98d50bd37f1b90840f96ee5a0b09e7e9a96219dd66f0f74c37eaa96f99f2185e3646069548e7913a106991a40988bd63d25996d6788f9302ef0a86ec40b4e6bd36f": "0x00000000000000000000000000000000044ed4af096401134ae34367a42cf8bb5da1d3c878fe08b512baf5e9a4f7e9bf43", + "0x2aeddc77fe58c98d50bd37f1b90840f96ee5a0b09e7e9a96219dd66f0f74c37eaaa3cef8c09f417f2a807fc9b3748a0d6b964bff11360e00040fb5fc569a9595532f935286a45f47": "0x00000000000000000000000000000000047cca5de8c58ec8fd1a269c3e51acf6ad45a8b9b32e4a65a4d4c481c5c449d826", + "0x2aeddc77fe58c98d50bd37f1b90840f96ee5a0b09e7e9a96219dd66f0f74c37eaaff4d5a3b6c0d71aa7880fe9ca2bbf331fc13e40525dcb0da661f143df506fed76d8ada3db8f551": "0x000000000000000000000000000000000c5ad7885e61fefa8373066bbb08ffe85c08ecd11bafb3a9f85af75a4eabffaeae3f25ee912fc878195d9904d4474bf1ffa58d1570bdc39af3f8fdd88829b15655a01f4cca8129d5e282faedcd6547e6676e91c46067489a28711f89da641b1737", + "0x2aeddc77fe58c98d50bd37f1b90840f96ee5a0b09e7e9a96219dd66f0f74c37eab7e3e98c718729f7a895955042cb3fe863f3564e7b30e9130e37b6d905be11c0cf91064de1cd83a": "0x000000000000000000000000000000001c8ff2fd995727bb6c776dce0c1e127955c1f191db6aff56c434a6738fc83d4eb8ae47a2ee72d479b5ae8c2237b156a6c584d82884c37be50958ea32c1aaef7832d8151ecb8e8d11e6c6bd81ae49216b9ef92d2b83b3ae39702a397922f14777680aed675c9de132c2b598f6fe8d256c8057b2d2cd28b2ae3fe6fad5475b407324bcbb3c28aa69648bcb3eb9b493c06256abecc144fca20c90144dc4dc920bff767cf5689832c7f3a596de7cf58e6d764884c33fa5bcadc7038e65e9361108b10fb2f9413214ee983786be59b316ce9fe3848ca7cf5cb20f109b3e31d09f213274", + "0x2aeddc77fe58c98d50bd37f1b90840f96ee5a0b09e7e9a96219dd66f0f74c37eac3727c0a32917e62c5bca9fd4c92b051e35c47617175d8f28aba000ccf921cb24bdf555662f2d41": "0x00000000000000000000000000000000104662cd48d69f8c1441434bc2c80a825ded8eb41d2c360f6ced694798678af7ab3cdf73c789cb02811fadd2fc2fad69647e6a22e18ff3b20c03cb9ed07ca0e69e3ab6cfff71e91eea05d195a10fc0a03a78667a6ee5a915fcfbb25e90bc258f088bfca4af1ecfc9a8af84f239f3f3198d12a666452d0658069c451723e7d922a8", + "0x2aeddc77fe58c98d50bd37f1b90840f96ee5a0b09e7e9a96219dd66f0f74c37eac6f1c6373257f1a4284fa7c290fb6052b9437610cfb2e19b3b37081fc72140e444d5b57ca01924d": "0x0000000000000000000000000000000008e6f485794ef2701691b1508c90cb2d3bbf6186bff0716c43915936439e0645a9c0ffc934cf4bfe0fd0cbb0153cc1f8c1f784ae59bc53da0e1833056c63b157a2", + "0x2aeddc77fe58c98d50bd37f1b90840f96ee5a0b09e7e9a96219dd66f0f74c37ead35c1615f01572956d629a2c80762d412fad9c15d8cc973b463f600895170d43a10ca504b4f454e": "0x00000000000000000000000000000000544ad16debf0db0329b8fa6806c88a774c6d4873579225919e24c856728b575d4de62e1df098a40f24df7e2359de24775b28736ded030da69a7ec3c809b10b6e5c66f3189c8351e824c55ea40817590b776431599273c4bd4c853b255e8cfb1b100071d7ea9d85cf0a22365cd41cca3f63121fbef0e1eea72109db9b12af8d4860649bd677aa43958fdeedca2f9159ce5de8d5a278c08e73c4ab9a713a24d0d47f1240c5bddabe0326741d3653bff06d6fcac311846cede93f8aa44a86a971924f42d7c710711e3f6a4d282c46bdc093a1796b6878a45c805827b838756ef78e18ceda44cb74eae64cceb6393fea849c84b6e7c0c00278b6339b14f882fabae15f1cc49a4b3adb82193695b2dc7507d28e72567060373e1e82206a0430005b694af02cd6695698754c7d8a82ef80e87a7c753c95c028557d15c393b9955fe74151048bc4da5e4289eeb52244056c70c535f165d37ad921c08b9d00466a1fbfe442589d797b259ba12d5f74d118a2f63fdd5b519b69003821b9da81614225776a2a9801988b622814386aa36c7aeb697cc35596ede2bcc7e3c7f7c83d99192c611e046511c11fc56b5492bf9fdb92b3ecf551ebb98b73241db611b2a44decbeb85618b8c0db8e0d79d681abc2cde9bcdf73e8b84b9e893952d5528d849a465f9a25c234c72214c38e8cb025a2b0995370d26b4113bec935efcedeca89dd30d21275ce384d806d03a4618c1365850015bacaab7b19a86849f627743dc2b1b6c90573ac5912fc44a3f886271bf2e8f0dd2d5f102f7bc313f1009b771526114fdc2d70007b26343e6ebaed9459ffaae9358c5b2460902c2a0d63d68a748e1d8eb1503364c23bf3c5f9b5c2b83e9bf6722b1a6c15671dd610c63009b0f67d4daa521b4d049590cf81393b2630cb72573fff37feee32bc143021d79faf80abf0356d5450", + "0x2aeddc77fe58c98d50bd37f1b90840f96ee5a0b09e7e9a96219dd66f0f74c37eadb4fe3a15170520a6659e4c3f22c2aa97d54a36e31ab57a617af62bd43ec62ed570771492069270": "0x00000000000000000000000000000000048c21fb36ae0d9d838e3e635f7d867a4eb44fcedbfc8f3d03f22f342f2a64b38a", + "0x2aeddc77fe58c98d50bd37f1b90840f96ee5a0b09e7e9a96219dd66f0f74c37eaeb7ceb911a5fe458c2f8f1570391214b89f82df1e2e0c12f9e2e814cc8e38b3d8baf3692724a311": "0x0000000000000000000000000000000004c2b69f99b0ddfb88c8fa9df62c4865ca4e69515a21c16bde93c726b1e678a156", + "0x2aeddc77fe58c98d50bd37f1b90840f96ee5a0b09e7e9a96219dd66f0f74c37eafa63c93073adc978e06bfc989509d6d625c085209adb405867bdbe4f167ded7e61ec126c683165d": "0x000000000000000000000000000000000850d1a6eb9d16f107a16aedb586c8d08259b212a3c54563f183dae7e1964d931e600456bf4a3edc3d8ce8fc483ea6b102c620264661f24c3f33b4b41ca8e54450", + "0x2aeddc77fe58c98d50bd37f1b90840f96ee5a0b09e7e9a96219dd66f0f74c37eafab87883b2986dc6ee5ad3ea0da40510f11f42c3281fd543f5a6bfad54ebef7381a7320bb509a0d": "0x0000000000000000000000000000000008524c4404c14e7fbda3e893815a3eca9a05f453ff0f73212319201a2f46d5382a06bd7c7a1535c6be092a798d558a5757ce89567f7cd939fe203163a8c4264e6a", + "0x2aeddc77fe58c98d50bd37f1b90840f96ee5a0b09e7e9a96219dd66f0f74c37eafdded1663a63773142eba87db082b693b5f35e88d7a70409b0ddb61d430abf218884d4467af1024": "0x000000000000000000000000000000000497d5a706146081fdd5ce77ad4ee232f351c4bbbce94596c12d300efae588ce9e", + "0x2aeddc77fe58c98d50bd37f1b90840f96ee5a0b09e7e9a96219dd66f0f74c37eb0c27f90ac9d10a58adc4e19e79b3d2c744f88fa5aca47ef05ccaae141f6435c2d50df824433ae48": "0x000000000000000000000000000000004840e877da5560adb4bb476e067659f4446675875a5e49cac2d3a4ad207adf450a346c4cf9a3d4e2bbeeb47694406ec7bb64e9c25e695f5a9051cb8119ca8e216d0ede8b484ae583e43b011ee69f561cc3d145aa542269304d76b034ec0df99f3f3e94cee09a8718b5957b697f388b7300815ae76c15d0ca5c0b0cefc84d5a7d4b980e50eb048a8102b537fad10ac389068a37e29e93ed6cdb700ee571eb98811626e1393aaa4e42b5d40f234eeeff068825d5cc50a3802e8e2e488694527b5e7cc0c6960f5ed4ae55f47327fec246d858b57f0d4baafbb54920e0bd47e1dd721e58a72e119fd6922255ddcb1b3f89bab2286d43b9bb3f5b3fd1d3df6a6fb727676cd55c3ecbc354fceb81b0ac3ae860ef4a3794e1aa9e31477de7c2cd36ccf11d9a3bd9c292ba18b98cdfeddc8e45fc0a4eb962baa86c5d839ff3e433de19944ad8900a50ea497ab51afd5227503f91b03a91584b72146c2e485d149cf67f543f8e2ca3235e29d530a16e44fdc3a6ce04c42aaff4ed9b7c275bb9ced877bde9790033f9ee5f550181bf234c12c2e07ef74652d9323c13ab31ea9c2b053eac74580036d9a09a0a63e987a6c67a59b52f9eedf6215852cdb4fd034ec99475a17f1e0208bf1b4851b0e3013141e274ea24d6a498412f2703e598e87b7fbdfbc2a72d1015f23420ba4e90023e3df81d423db7fe2b2691657d45e98f02816e5a832b10a872a2b4f736ef9a7242e0a0d8e64d616ed4c2da9a103707e9ac7807a764292f86434ea1ed238bc9c3106178b9371fda26e3d4333adc04513d188844a789c844", + "0x2aeddc77fe58c98d50bd37f1b90840f96ee5a0b09e7e9a96219dd66f0f74c37eb0f0b3ac307cd751749ddc93a65dfec3af27cc7478212cb7d4b0c0357fef35a0163966ab5333b757": "0x00000000000000000000000000000000187c7c8105064a32c52de4d09d9b9dc358756f37ccae41c1ae71178ce302ff5374b2f0176465f8cf99c213696538dac784ba8c59e4f577c6fa88555bb5f28ecd35f69f5924c239023e8555b80a7323494f03c76357fac283664c131a90d13bf9719a7994a63250d77c7cf6ea9f364f136dfd163cf4ee30d1fbf5de6808e443f25cc8ceb3b9d38e7a25f5016eba5e885ade09042c214623524d78c73f6ce9bcf95fbc97eeb4ec96658e0ec1d15b07524376ed7e1444bd35f3c4fc21526176f4c979", + "0x2aeddc77fe58c98d50bd37f1b90840f96ee5a0b09e7e9a96219dd66f0f74c37eb0fe6b98334d7d6cc4516751df2e5803bac3bf9cf7b6d55cf4acbd76f861ad0a2a2b71b7a5ed8054": "0x0000000000000000000000000000000040668103daef522e6916064ee8e27db33ab950e2d4f065276f7c9d86efbdab3b7d0cbb4adb01af79c560636910430458ac44cf5fb9e24482279191e6ad8aa33148bcc2112d8a9de4645c4ff651aa6efa2f301c9d6a2355f1bf0e6a80826f50016e72f10843313abdcc3fe2ab623e213c561d68539db6f9b47f72a41f2946c7fc45b64bfb076e6685695cbb09316f448529f41964fbbc9520059a0aeed64d63761bfe0dcc8db8a90eed611a4510a8131240174ca310a563a343fdac7fc1060b0b04166a40c58fac1476b58784d0ed59ae59fc516a4b072ba8daeda31d638a53023a5e5167d2749eb21e8d257aca0e738ebdf309e9e0ef503e1184463de7db3d0b28ec194255613dc072122c8330dc7c18e15b12e5eb3093a442224e91e50cba7d3dc68dc89f99b0b46b9e3a10f9b115283e27b7f6fd591a9f6cf53fbaf1b1a4685f90f218ede5ef0e08fcde53a9913c8c01d7cc28d31d21d89071b6a8d9262d8376deaefd68c861d01a4472a1c518bdacd7f99b6c4a0b64ba32d74995a21405797a4caba24b45e5bb6eda6ae45de9e1fd6aa64fb43bd9086694c4935d21872a5502866f40b96e6ca6405ed0c44747726b3972ca4773aac5273dcc25ffbb5003b07536a8ff1b35d2750c1d8482b5f8290d835f5e497bcb9ebf11928d9de622fc30532c21eb7992f79d2d844f3006382236000c2b1eeb4c8985c6ed6db26734ec2e70", + "0x2aeddc77fe58c98d50bd37f1b90840f96ee5a0b09e7e9a96219dd66f0f74c37eb19b71d671b6baa2aad8e905d4c09ac501fc3f74833019107288077bdaa77291588b5e021330657c": "0x0000000000000000000000000000000004fc2dda4a648f70d73746458b1109134bbda7b43b46ab3546d310823e36966d76", + "0x2aeddc77fe58c98d50bd37f1b90840f96ee5a0b09e7e9a96219dd66f0f74c37eb2f651117e3fd34c84bda1949a2b78bfc3b12dcc8f2c8e8822912efe0c693a23effaf7f3b54e9a5c": "0x00000000000000000000000000000000049257672efbce6327e97783808a8feb2ef8dfa71bdff401f06700337dae17a253", + "0x2aeddc77fe58c98d50bd37f1b90840f96ee5a0b09e7e9a96219dd66f0f74c37eb30a0d7012b77142a86620314a174486a9938856e3b939de3bcd73458780f542388be0cd66379e28": "0x00000000000000000000000000000000049fb287e33d2e6433438c3584150a857912afdca0c065f86275b53fe95d3f8192", + "0x2aeddc77fe58c98d50bd37f1b90840f96ee5a0b09e7e9a96219dd66f0f74c37eb357e4ead78873ac2aa53f55efa82a9820f3c2569d4e52dc467475a1a11cfc9861ce5440316edb7a": "0x000000000000000000000000000000000c3789e73dd3cb036f57dda3ed96e000aa87721b8e19205610d2625e3847f1a06bba7e6ae859516ab7792519d1ccc7781409bc58e534f54f4edd0981118d53405a30ed0348562c1ed74187bf91ab00d4f734ce2505a6d6f5d189ca1f8dc966e665", + "0x2aeddc77fe58c98d50bd37f1b90840f96ee5a0b09e7e9a96219dd66f0f74c37eb4736827e2622569824651190f1d20237fea2d5953bb53ec59df25d581e54f291d6978c9a8017741": "0x0000000000000000000000000000000004f4ecfa7baadacf1a3aa65baba89f28312db782c43e750e677dc40fca086f7b01", + "0x2aeddc77fe58c98d50bd37f1b90840f96ee5a0b09e7e9a96219dd66f0f74c37eb48b1b8f79a7433f88b9f3a722747e8f637b2583963ea7f1215adc8c75c3957554fdf92fcbfa5034": "0x00000000000000000000000000000000048c6211892518630b6e583e09dd395211035a508358a80322614f9894bdceb605", + "0x2aeddc77fe58c98d50bd37f1b90840f96ee5a0b09e7e9a96219dd66f0f74c37eb5421b6506f7f790ac59122f8bc8c527a8efde87156403558ea66ca0ef049cf3fa4f671f98517d61": "0x000000000000000000000000000000000436ea3b4376625f8f5ac0cf7b48b7a186f96bc215f34976f9eb692eadb46ce29a", + "0x2aeddc77fe58c98d50bd37f1b90840f96ee5a0b09e7e9a96219dd66f0f74c37eb5c8f247935e6ce99e0bb283b2d2522a090d71d9c8fb484c7966d3e28b21bc513419ef7f70d6a563": "0x0000000000000000000000000000000004da466dea606e6a603356cbfece746254c6585b90647714222fb59e42ce45c601", + "0x2aeddc77fe58c98d50bd37f1b90840f96ee5a0b09e7e9a96219dd66f0f74c37eb5cbc9967f19afa3e295650fdd71d7046633b1fafd0881a3207719c573f17725fccddf854a8b5628": "0x000000000000000000000000000000000458b16e3eabd2cb50029bde70c7a7ec0123d1e710bbf45322f50be3f21ebf8747", + "0x2aeddc77fe58c98d50bd37f1b90840f96ee5a0b09e7e9a96219dd66f0f74c37eb5dece0984444d31a0c077265fa8ebb05329c968fe13efc415460cc5c379fb392a652ac07c9c2f7d": "0x0000000000000000000000000000000004cc710cc1444b51d4cb4d22fc47a446df6d8371a8831a515040a52d7cea1fe70d", + "0x2aeddc77fe58c98d50bd37f1b90840f96ee5a0b09e7e9a96219dd66f0f74c37eb62acaa32f7e218efcc5b90bc1891b7d905423f7a00ffb4e8f3d59aa97491b5a1d45b82548639936": "0x0000000000000000000000000000000004d85148f0fd5fe1eae1bcafc4f9d970f692415245ce7bb7988bbd76b8dffdf02d", + "0x2aeddc77fe58c98d50bd37f1b90840f96ee5a0b09e7e9a96219dd66f0f74c37eb67386b3a2bca62fa6805c6dc7757cea227e11839257d4e24ad39520621e99e6016ee0e1907c3315": "0x0000000000000000000000000000000004663b801c02f2b76565f5b60d817e7dd805babdc276b53d20e19cebd199c88555", + "0x2aeddc77fe58c98d50bd37f1b90840f96ee5a0b09e7e9a96219dd66f0f74c37eb6cfd687de7a23b4d60cf655685824e9966b0a10c01dc8b17b37e24944fdd760e4dd73ff1dd4ac14": "0x00000000000000000000000000000000089801bdf93fc1d4b0186e1295d517b03a5749b90c94a5468d74331a6ff529a953a830e5f0091c9f1c5da8a2a9a1a7a0de5802c6bdd3d9e23175d8c116ef226251", + "0x2aeddc77fe58c98d50bd37f1b90840f96ee5a0b09e7e9a96219dd66f0f74c37eb76acca59a92ef07ce072084c159fb3547381b718ac1660d14030e7bcbe9db68eef0f7c0e340f33b": "0x0000000000000000000000000000000004a620a613e0049a85c71fab0328f7449b0a9963195eab763760e1ff50a10d4404", + "0x2aeddc77fe58c98d50bd37f1b90840f96ee5a0b09e7e9a96219dd66f0f74c37eb82ca38b993a4d8b5a7aaed28c23b0b10d2fc6a0a914c93ce965749d67d7f657facb010255e4852e": "0x0000000000000000000000000000000004009ea4dab5c62d5da4b72e17b5ee5932a3098fa728b996bc7ed07f112702d32f", + "0x2aeddc77fe58c98d50bd37f1b90840f96ee5a0b09e7e9a96219dd66f0f74c37eb8ed6b693822d4a77825b33ec8baf2d437c19856a6ce74f09bbf49c284602a18ecc0683874dd596e": "0x000000000000000000000000000000000876b2a1db526de647dd7aeeebd328bc037be6795e79e7235a23f74198387be12aeabaedff8f91f5afd170b1c8252522e76584565bda69f49ca2e223fdec4b5529", + "0x2aeddc77fe58c98d50bd37f1b90840f96ee5a0b09e7e9a96219dd66f0f74c37eb9206afde78e38223a154cb2e55ed80b9b671b240ccf20a8e2a47a7097a61f156eaebdc98fe4780a": "0x0000000000000000000000000000000004403c772cc5a0320a23db863c40b5780a9390665df1e3b4255f32df1a0afc396e", + "0x2aeddc77fe58c98d50bd37f1b90840f96ee5a0b09e7e9a96219dd66f0f74c37eb9f65131235fe195ce5c65fecd7bb733ee636a381fa9dd916f8cca91e2e403c8aea2f7ed32b31d68": "0x00000000000000000000000000000000f0720436c87f73ebfaadd5ff7748bac986ab74277d57e5b946066d922884a5d80dc88752d6f18f0d5c804929cb727ce8999603dae997b121267ed59d5bb229af3b1ac5cc7855b95a4ea69568546a9e38214f4b6dc5de6cf1351649afd6b0bc800b106b2d295a9a3de6efade304e1efcd123cc66ec27ec92a075964ecac7229f54b26eb2cbbeb40e98cf9d5f39918fe54290600520ccfc9e519efb5779ddf48225f803f3ff57158c1e5483e88d4dd5d04f7f8ca3c5203c6ac29344f314099f96a314ab3e893de103d05f3e6e5f210faf6fb40fddb03be173eb3723cb33a074faf34feb86644e89b8c9daf871b44f7111264cc15bfd8efa38a255124412b9bcc58699e98a7c353052e4ff27d50ee1dea0f7379ccdbdaad823c457b755413243e967fa28ef91b1509ab5a2d494b230780761fb5e5ea00e01f7ce4296907b8b97f4c1e6e5bea81107431deda89d3b05e7e1656354c48d0a5cb767851726ed359371f7d70cfc338f687e55d944e8e6867f90a05085cfb5e15e2f0d5315ca27026d0aa5d6cd8d0f1e2161523b73cdde28b857e8d4c281ee0825d88c3658675561a2bda1d04961a29fdfab26086e085f26198e4839826299adf5158e0de4d266528642b5a22b6c1ab9ef945b7279a730423cf50ca4e25feeefd4953abdc0fc8caa403f70e8219020203f8d92b4c8ae0dc2a5a9c7c5641486ac27a4b591d3560b434650658386d313e669622ba62d89b48b2d4e7be50308ca20ec56fdb89ca5844952b3953a4242b97bcc4600c1de9c6f1a6ddb74b69d9521127a377d2717f6d9fed5ddf4ed47e15ef535a26d9ee0e3199ea99baf7cae9d94a05581316885d0b21549ddd4ecaad545c5c3d4c99b7866e2bcf2483dd7cc7cf578886586663aa25a96bc64205063e0fa2cd4f4b448d507f9d5b2ea8c85e8947a93d92d214be8f4b752807886e02a6ed2142a394d0f42a51281478530276f88d15657aa277b62c54bd1576f322ba91845c6ce9f14ebbb24f008964bd395a2c1f92149810d6f6133a905706000ec282b526ff533bee49db3c9c7ecba02b951f63f8442cc33443a78679d5246829fedd35f51de7e439bf432926351c41500f30fe78941f325c69dbb642f35095479c4151f0860839590586185a1dd97ef4f3fa86a6c0ad4eeb24addd8bca2aa758f60f07a15346b938937e245a9bc5f757c0a516b249d11c40ba8b0742109d573d148152531de95b53fa605b79b786c7f16397d3226ccc2f0beae85e2d7377093726053f965308328e14c097fbfc2b09b6b97256bd6a14ca1459ff9c1e8dec3556f8df53c69120d27f523d11d1704a4dba9448aee78ea4f1481cee14fa15124511a61366bf4c8e9f8fa63bdf70263753a1d34a66a616dca43b48c9f99d2c641c7e20912c81e6895f7b27bb4be5f6cb4750a326d3deeaba95ccce9a6bf6d1b9fd29661712f60a13d05e0c478d73f3a2dea9766c5d4b54a84895ed8b7f6a3f9506146c4d3e81cd1909e980648a1d2b7820cc93eafdf0151002f481c0b874502db473e45d4839be5ec40b585c1f08ac284e656075327d7038aaf795d35789ab10f15a5e26900b9067da461527acdd9856b0934eef5f0c099a2acdce01b51f02be2351c24dc5f34db1ba52471ff7e38158a4dcc3a19b6137b8e6023b72f889cacfe535240246fc1579b9f65b2c83cfa020ea61e54330741399b8acbc8b7215b8dbcf425e0a33a0fede6d4995303cad923ea9cb39de708069630184e76f3c276b76c772bca1d58132476c8e285668c7c1505e248d79821cc2244724f026d438a27d470ffc8d39aafef0cd3cc978a3b1354b65853a12b9f4ee0a55af14311a4de76b7b169061deeb89b61291cb59efc126c4add37ce655a7954f8e2b246fdad18c07d358fa0f5c211f7844143928941e88780961c972b189e6269ca6e0ad98fdae5c994d461021bfbc5b35676c92f37d8cc0205b39ca70fe448ddf0fdcf203e2b4ac4d070c2fb774bdca7e1b4627e9af2a9a66a0b67e7164af0fa26f20781e4b5fa2dc42489553ecd89d7eda44e51d14dd217fcd4e8f183036ebc916ebb32844bffa991574a0fe5948a9e16263adeced4ac5592a4e15ec77d223be684d9229ab3659fc702c34b3c3d2a9e4c126b3e6152b8ceeeb75c43d7530aa56ca6f41de5a5e76a2708e21a74a8d65c99c228e22e79b3e016bab0eb656a5235af8132c2a9a818c7a2cb43e9512a0b56f6e9080b36543163cd843c3816854a331c48cb107c63ee42f210cfd5ba5a03ebfcf979f3bb7d68fd694bfc64d37bf04ca7b2e87d4e38827f94c86b81e36ea46dc1b355c79bf38968367ed63d58e7b61e9aa5c97fb6fd94dcc3a8ccd612df568bb9b459480879224e360d0d8c3caf9365f1fe7d54b458b010b5084c45682961f27cba9bc64fceecf20016338daf42fef5cac7fd229d7727db1685c7c97a0165263b9287982692ec2845cdf8ea293108d3cf51f598b6e98da1f7d2cc63957be519774cb72783eef49a4a1dd53905dbf49a4a6f180a957e05630211ac452bda8e177f52bae23195e506bee27b7007bfbeda4f2010fa6220e029940b89b1a8c5532845c171dcfc78c4bd5c42c634e7d6548d6646c83fdc25bd4737b5a3b1634ed187e0ff740fa52e33f2748d0e88a19cec4e5c185cb00408a89b60578054da56ab2c696de80350f00924db18c896c3b9d66c26750628082750b332c", + "0x2aeddc77fe58c98d50bd37f1b90840f96ee5a0b09e7e9a96219dd66f0f74c37eba594f7276ff200c4e531ab22f712634089201978511b49aa987322314dcd8f16fa241f0055e3737": "0x00000000000000000000000000000000042c1800d8039258f2722009625f77a8203729e8770d6ea72358f165350233ec25", + "0x2aeddc77fe58c98d50bd37f1b90840f96ee5a0b09e7e9a96219dd66f0f74c37eba6839973e6e9ad1e2a0a933d2b1e2dfd0c06baf42557bf4aa2ad84866859e6c869733d6baadf152": "0x00000000000000000000000000000000043eeebded302e53d488d9b063922447cf63e7638e60abdce4259c72dec9126a35", + "0x2aeddc77fe58c98d50bd37f1b90840f96ee5a0b09e7e9a96219dd66f0f74c37ebadc22310930427ba763de880dfe6c4bbdad18fab60e27002f648c221df5248b7d44a575b4bc7342": "0x0000000000000000000000000000000008b5adad0de4385f3ad6516e39fd6479b85c22886cb0cb9fd91ce52919fec98bbe6d192ca910ffc54858d1b7f553cae619803b55c69af50ee3bb1846f1715e6db6", + "0x2aeddc77fe58c98d50bd37f1b90840f96ee5a0b09e7e9a96219dd66f0f74c37ebbdd44aa00ffeb9790174218ad9d5531fc97c3b347e073d347d157cc40a470ad89b75604b0d9dc33": "0x00000000000000000000000000000000048056875c26b0b99303e102f56af5b7cd6494578bfaf7eebc0f251a93a98c0710", + "0x2aeddc77fe58c98d50bd37f1b90840f96ee5a0b09e7e9a96219dd66f0f74c37ebca4e93e46a1ee7a83c75b56557a84fe8261cadc0c308577b0709cdc54311afc5ec8d348b939f589": "0x00000000000000000000000000000000104e8c56b618a0c3750e9f005d58590bbd6b088c326a1fdb075294a8565b4192e8eaa9db4e448cc0b93c4cc1d5059f9bb7e017c51964e21916f2106cf56b702f646d3ffc8efc1d719ddf99d29c8a1b285ff855969c4fff0668f9985a6b41c4b49992b53a95c31152cb0d95a968db4dc8e14cb7f4495f4b3215db38d0fb6b8a8287", + "0x2aeddc77fe58c98d50bd37f1b90840f96ee5a0b09e7e9a96219dd66f0f74c37ebce3132e4ef55facd425daddf60b2545e07c695d32d6bea2b9343f1528052b4edd1a777e93058565": "0x000000000000000000000000000000000464aa224ccde37501e8661ac74a75eb9c2a6793b13e40828860deae744d806346", + "0x2aeddc77fe58c98d50bd37f1b90840f96ee5a0b09e7e9a96219dd66f0f74c37ebe092d7e5aeb9a7802948b18cd5001e68a33499343bd8ed974fc8398bbfdc3dfafbc7c478544f67d": "0x00000000000000000000000000000000045c899bdf0bebcb57f0f68da86b80f8840407e7388ee52cbbc1a60f18a7a2eb58", + "0x2aeddc77fe58c98d50bd37f1b90840f96ee5a0b09e7e9a96219dd66f0f74c37ebe3990dcba28e51a80dea82a6a4704d208bd43d1ea1d5a0bd97a9d20c5237beb348be8c82f37d93c": "0x0000000000000000000000000000000004eea34392724db7a397808df783a7fe52ae6436bd9c2d86af32abe8dd81f43c33", + "0x2aeddc77fe58c98d50bd37f1b90840f96ee5a0b09e7e9a96219dd66f0f74c37ebe3a70de3dc8981a02098b5f718885f0d6f0f18359a7d16b44c9229857934efe66daf4d9f0eb7a43": "0x0000000000000000000000000000000004ee9862cf3f7401d7c82461127102626135ac670ea079780708e1ad2c537d9c2b", + "0x2aeddc77fe58c98d50bd37f1b90840f96ee5a0b09e7e9a96219dd66f0f74c37ebe6eb4fcd98b5e48225f2459239641fc50300041f8980fa044cb07705db61fefb340804172b1c25d": "0x00000000000000000000000000000000041884855fe5ccb84c814252cb959d599ee9f90de9d3b7c65058b75c39f21b2802", + "0x2aeddc77fe58c98d50bd37f1b90840f96ee5a0b09e7e9a96219dd66f0f74c37ebe87f9c4b210b250122ff96f07bd9c9b3961c4387d71362315d05addda58f1dcce642888a643f930": "0x0000000000000000000000000000000004bb3daa994e809e4484afce1c63b8737a9adb8a91ccb78d7002386a087b382de7", + "0x2aeddc77fe58c98d50bd37f1b90840f96ee5a0b09e7e9a96219dd66f0f74c37ebef054a6e8d99eba983c5a0d1f1e697c1a0f9798bc25543603751b41102d41c3b0e23cbc6e3fdc0b": "0x000000000000000000000000000000000c5edf939d9f238bce8f74fdb215d853697a5a515b0f8b3a9a9d64390265f2cad9ec46a834c9d9bad9de24c9d4c6c85d4f942e2c52134f408e7fef2381bcdf2dc2941acddb878c9380546d8e08a2c94431dd6943d8c238428364d4eaf95218075e", + "0x2aeddc77fe58c98d50bd37f1b90840f96ee5a0b09e7e9a96219dd66f0f74c37ebf8e0379b44b6804dcf2917d37c64e3d60416e47b5185b4d6c3965ca531ecbe29e1d2cf759f5f871": "0x00000000000000000000000000000000041adfba8c2b21414451ce19bd06d2e9ab7541214eb3285ae73da678a755432237", + "0x2aeddc77fe58c98d50bd37f1b90840f96ee5a0b09e7e9a96219dd66f0f74c37ebfd1adb8160d3d9cec8c97edfab0a07c37625d53be2075b8ea64a00ca71d80cffe94edb44d215e00": "0x0000000000000000000000000000000004f67e4658ee318d7985399480025fa332958346cd623a025948cae8a7db36a81a", + "0x2aeddc77fe58c98d50bd37f1b90840f96ee5a0b09e7e9a96219dd66f0f74c37ec0e968a177335220aa220871834d1f214169691dfd97c70823d90d192b246378dc01a59daafffe0d": "0x0000000000000000000000000000000014c8c3dee0510e7e05a5ac3e8ab4e13befdeb0366408b0c47c5a41c887d7dfdd58206c097fd6569064a918b1fe42c9a302ee3762daa035b0c44eb771d6c34d1d08b4f54529b00e5295e6efaacfad2de17a22cfe1466f2ef142caf1328b5a701005e2c726e24b6fd7c2bf7bd253448f03cbe350cd0e36bcd621a82fd2732bf9c2069ac3a89771d2fc8c62e9d37bc6548f67306caeeb4ba49e7aef7c09b68a260665", + "0x2aeddc77fe58c98d50bd37f1b90840f96ee5a0b09e7e9a96219dd66f0f74c37ec11b1c3f82b75014e4d733aa6e16d24e220efa69687f6ff198317062ab5ee12a059d47b732c27624": "0x000000000000000000000000000000000428e3a8ec56f21d20789923fc326898987dbae48643c059d5ba9a8afe843a6f45", + "0x2aeddc77fe58c98d50bd37f1b90840f96ee5a0b09e7e9a96219dd66f0f74c37ec2531fceab22368da26c51051a9031ebcc5ae2a4eb9a72e444a5bff59b995ce4612ed8cabe8a2a70": "0x000000000000000000000000000000000472020fdf0cdf3cd952082b52fd11ac0df4cb360850efbe0d096126efeefbb6ca", + "0x2aeddc77fe58c98d50bd37f1b90840f96ee5a0b09e7e9a96219dd66f0f74c37ec3125cbfe931ee052c08cfa5b2dbfcf6850a3b836596d82a9ed7d2d743b42aa5c69798b502b29b57": "0x00000000000000000000000000000000044b514120fe1efd6da4118dab0e2b1fa66ff2eeaab54af205b2ec6c506b52fb76", + "0x2aeddc77fe58c98d50bd37f1b90840f96ee5a0b09e7e9a96219dd66f0f74c37ec39daa94631294ae14ce4e09b999c54351c75b74d0bafdd17d86d98b6aab5176b9068e1be13e096f": "0x000000000000000000000000000000000c55a7b1fbf19d76a12b4cefc4009405905cbea3fc16452627e6a01ff866e9b6f1bd19630ce7a6e94431c5f771e66232e46a034f3cd18006febacf02baad8311323ac5201c3a4b0b032e701e34988ca6a06831b69aadaf9a388dbd33d85ac85f6d", + "0x2aeddc77fe58c98d50bd37f1b90840f96ee5a0b09e7e9a96219dd66f0f74c37ec3f2c1579fa4e27478baec43fd49badfce811cbba08b3f0ccf758b5e22f0c4d745452f5dad6eee07": "0x0000000000000000000000000000000020003afd6023b1888ca027ee106726fced92608aa111486ac2b82717744009ea04deea74425ab90f984007c4324ff21437aaacd212a1a5f349d31f03f735cce907d8ccc709448e61b19bc01bbe3be7d7e74c2303883ac6d06c19393f9c1140840f24177bf6f8ef353988a83494a9fd6a8ed1f89ce97daba4d8448c48035b646960a849df65d3f404d80ceae8a840ec60cdfef83ae70df3a6d681870c87d5a78f3110a89404fc6e546945ce58e433c4e88a17167caf4e763793cd3b048e4b0b594010a89401749948f217611353ab25e1789474699fc06ed1dbbcf44b7035f488759a7f00455c8ddda3532450ad2eae9a5405522b11b320e52851ac6fd870b12d12", + "0x2aeddc77fe58c98d50bd37f1b90840f96ee5a0b09e7e9a96219dd66f0f74c37ec46ba4a0042e414d9ee1fa0d8d4e022ed5680b5925d19718a7ecc9f8f2ff77de54f0822978d27755": "0x0000000000000000000000000000000010ca0ed2d57f858e89592c76cad4ac00258041aaccb971171ea43b6fc39a4c4c1ac34542e51274a1c23c1293574ed5da6a1c28d092ae4362cec0eca403c02244d040d1c7929a103e88681731f954862765bb66d96c36e22f82a35fe75cf7a72c205a3116fd94d5f079378c4b1f2066ff567078ae68d97100fa408185a98ee92fb2", + "0x2aeddc77fe58c98d50bd37f1b90840f96ee5a0b09e7e9a96219dd66f0f74c37ec4b6532d1c37b711aa18b3cf52cb27fd19d5b80fe7982ff955e0d5124dae26ac360056f401dad846": "0x000000000000000000000000000000000ca6ef8a1f259f84d8e435d119d7c0b8f4d91c7ef95bef739c81ff66a2cad2cc45cc2797a71c48e7e7f6defcf2dfe8c379a521c8500c9bbfbc13c8513cd5cdfa3bb06e4c7fa18e7887887e5b7424e8e2131e2a244163d4a70829f311a571d57c2e", + "0x2aeddc77fe58c98d50bd37f1b90840f96ee5a0b09e7e9a96219dd66f0f74c37ec560adb2f53e7fdbba0518b2408a0883ce26ff4ea90f8639ac05332bf82260fc45033d7b5baa0a20": "0x0000000000000000000000000000000004d2ec0a695435c6324bfc9b27dff217e5092e2972b0123529514006e278914c7c", + "0x2aeddc77fe58c98d50bd37f1b90840f96ee5a0b09e7e9a96219dd66f0f74c37ec56c778db308e44b8e32641448f9a5ec78ad04a33b7874a2942ca7ad4c7e8ee2e45409cee1883e06": "0x0000000000000000000000000000000004681559f05e3544030950899e305d923d8e11e244943c1520c35e801253d28008", + "0x2aeddc77fe58c98d50bd37f1b90840f96ee5a0b09e7e9a96219dd66f0f74c37ec59c65c996cb7128c8d887817cd801c256ae0adad712737a18a89e23eb061b7002839d16530fa0d8": "0x0000000000000000000000000000000008e2612e76480388dcc8dfc46219130946f276496403ecbdd37a6d1a14c35701aad7a7116db2d1bd9dd4c7b37c204dc775888f9310a1a18877ee913901bc95281d", + "0x2aeddc77fe58c98d50bd37f1b90840f96ee5a0b09e7e9a96219dd66f0f74c37ec5a064463897ec28ba98d1704adcb69b1d50aebfab39709c03713555e3d49e75690492b0a02f547c": "0x0000000000000000000000000000000004c1c0081353c756023d47df0da1d4c1b9eee95b9bb90058215e6b42ec5b00d525", + "0x2aeddc77fe58c98d50bd37f1b90840f96ee5a0b09e7e9a96219dd66f0f74c37ec62d71f1d9e80b5e284eb76f4116f4b75a718fd1a374cc5b6e02fc18f37e02deb3054e57539c5328": "0x0000000000000000000000000000000004284e0442b44363d362b1194b107f46ec28e76932170fdbbf8077dbe87aa26001", + "0x2aeddc77fe58c98d50bd37f1b90840f96ee5a0b09e7e9a96219dd66f0f74c37ec637b13dd6b9ed4474c76b2bb6e2e4b16fec1849aefadeae913aed26e72e2101a4dc34abb3e40776": "0x000000000000000000000000000000000846911250513cf4880a89dd8ee3e32cd8363d0f3a064767a4fd19635f2605475eb06c021615bf00ced6ccd77c0bc8c820a71e819bfc48dff36ffb12d7ba044338", + "0x2aeddc77fe58c98d50bd37f1b90840f96ee5a0b09e7e9a96219dd66f0f74c37ec67401b1f25d1590b45b073f1e692d18c2dcebae861b2f166a4dbfd95d9780ffef603c9e61d00935": "0x00000000000000000000000000000000082dc4deb5830a5e765042800fdbf03927e72ad3d40644360b07cf9ac241638701d76236f0c5d432f6e6b99845a7eada1491dfa6288c36dbafe21b45a0d90488d0", + "0x2aeddc77fe58c98d50bd37f1b90840f96ee5a0b09e7e9a96219dd66f0f74c37ec6bbf3f9dd9143a5fe6c31fcff28694469c3d4c1681270bdacf6edf7ec39bda6c68cf25738268b79": "0x0000000000000000000000000000000008a2fa6c11ee56da6d5e51439a0d0ee776c8b4f0f6a914cf6bd9ed8af27db80252164f70bb86b671d46c1748f38329f50db8fc5461a4ba4dbbfaca7a47bd063962", + "0x2aeddc77fe58c98d50bd37f1b90840f96ee5a0b09e7e9a96219dd66f0f74c37ec6c6796a808b7f32a8a99a7f49f1d3d72656674fea67bc18454325f00c9a5921ec6010c43409d43e": "0x00000000000000000000000000000000045263f205d321ac0063c4275a7daec9c6b5a34b3f0cb835ca2f4fb22bd9e55e5d", + "0x2aeddc77fe58c98d50bd37f1b90840f96ee5a0b09e7e9a96219dd66f0f74c37ec7e9bc04cc0841dad6030dd61ad78ca1900865d2b53dd163bbbb5b40c82f94d25cb6ecc750a93c25": "0x0000000000000000000000000000000010e6ba74e93df6c3e3cd1615c99708e867e1f3160e324fdcce53be8e3b733e663a4462badaa1c9c6bf3e368c5de7a206c0e8c1ec70ff0c8c5d2a51545e0514ae309810e91f40b4c50ff66c7d228a9e4109e677c406cd6d2417bfb11f0899345e00c44a96f5d752d040b443a98592bb0d42719b2cf3ebe538fc10f76637bc054e7a", + "0x2aeddc77fe58c98d50bd37f1b90840f96ee5a0b09e7e9a96219dd66f0f74c37ec9c02a3bfc8b9747e2b3d30136a5bf1ad99ed78efc1c0cfdc6a2c65d3e30d86b3303f3533e155032": "0x0000000000000000000000000000000004894b90350435a6f04536b6a1c0f50e83344ac230902f07fd5e69953e8824d63f", + "0x2aeddc77fe58c98d50bd37f1b90840f96ee5a0b09e7e9a96219dd66f0f74c37eca8ae099693f9dabd8004911e882a05affdcf81aea45f611077f07a29dacf6b754bb69ab118ae067": "0x00000000000000000000000000000000042d3568072e73e8e73a9a8cab58e10779bcca9cc9d3da70ee41af6b5682fa1170", + "0x2aeddc77fe58c98d50bd37f1b90840f96ee5a0b09e7e9a96219dd66f0f74c37ecaa21989ef628ddcbc63ced3f8fec642128f2aa9c37e989a9313a67e9635dd85e8bd689ae8d0ce1d": "0x000000000000000000000000000000000c486e705093cbe54e60dbb3e63ecf3ffbc84bbfa2a1efd0a3a9282585e2f50772a82cd9ba02bdf8241a35d6a434c019a6078547e238df7a55c6dde5c4deb2f12c8011fa4c76d86408e873beeae9385075b1f735e05b59dca7fee6147c14952770", + "0x2aeddc77fe58c98d50bd37f1b90840f96ee5a0b09e7e9a96219dd66f0f74c37ecb3200a490ec72062033f1e89095d22a9c51162dbcce5e28a6b12957fdcb4c3cf11ea8def5ea1e22": "0x00000000000000000000000000000000049862f63cee080f43d1d4de935b51b615cd7a15682e28e41f0bdf6565deaadc06", + "0x2aeddc77fe58c98d50bd37f1b90840f96ee5a0b09e7e9a96219dd66f0f74c37ecbc819e175aad208ac2709eb9569c861e63940eefaec1f51ccb76eaa84544e56331adfcdec859911": "0x0000000000000000000000000000000004460fbb15abc6a11bacac5accdd7a64ac63bf649e22c4efb879ff0cb0446b7e8f", + "0x2aeddc77fe58c98d50bd37f1b90840f96ee5a0b09e7e9a96219dd66f0f74c37ecc718a6b9e9964318ef5289702f6b8c7d22b3562ffda7d5593a5f6414226925e72097efbf9b25720": "0x0000000000000000000000000000000004e35a5bb9f11f2d71940593c4ff87fba89a7ab269825da6282025c43bf0b4c07c", + "0x2aeddc77fe58c98d50bd37f1b90840f96ee5a0b09e7e9a96219dd66f0f74c37ecc9822c9da4c837c86b7409a11700afb027924cb40fa43889d98709ea35319d48fea85dd35004e64": "0x000000000000000000000000000000000cf826721deb8c5d5f99d57fab56da2e28286fb7ad92f148b05d1aa353fea2b26ace10c51e89ab2907983cc8b846d9d1afa2f9700db18e176c7fcfe709d0406339de4a3a5ffb49ce7652bd6a9f98cb78bc68c2360c6e55fcbd6d6d5aa6b0f2347e", + "0x2aeddc77fe58c98d50bd37f1b90840f96ee5a0b09e7e9a96219dd66f0f74c37eccf50f8320382ca644da8d011a0f821b2e39d6151f8e17c417c0e09b664587dfe2021a194ee95d74": "0x000000000000000000000000000000000441593cf289a037eaf22bfa42c5f10c5325340bd4f488cb37fc72f65cb83f51cf", + "0x2aeddc77fe58c98d50bd37f1b90840f96ee5a0b09e7e9a96219dd66f0f74c37ecd07125b43213e171c82102e4554587f23cbd4bfdb0f43c9d2879d18feb6102bbed977930f695f22": "0x0000000000000000000000000000000008f6f9a8d8e0eb8f9113107b5f2bc4c3bf64a31c6ce51913433873e4357bd35524e64a8c8a0cd5301afb20483923ad8427c597ba471a6fa868947270768bdd2713", + "0x2aeddc77fe58c98d50bd37f1b90840f96ee5a0b09e7e9a96219dd66f0f74c37ecd367e518a4206c79653ea6fa2a3e4072178c4de671464a69d9c72c7ff7170bc76697b46b3947b0f": "0x0000000000000000000000000000000004f204ee949a256b7e81637b358f1d8519458e9b79cec9f1e345ff9d2ad4516370", + "0x2aeddc77fe58c98d50bd37f1b90840f96ee5a0b09e7e9a96219dd66f0f74c37ecd4a30ce889e7a55c04f1633da0ab6cb71f71ece4d1a5c32926d3f707d250f66ab712d65eb374b2d": "0x0000000000000000000000000000000004407ffe0ae098321e72b2b6fe6ba331285a2967a27430f04375910007010589c2", + "0x2aeddc77fe58c98d50bd37f1b90840f96ee5a0b09e7e9a96219dd66f0f74c37ecda070697bb44382d2cfdfb80cb90a4a5826c98846a367489fd25d3a2561838fa372f39f3f7fb138": "0x000000000000000000000000000000000897a78ac6bd50295c46bc350d252714c70dffccdaa6c1740dce1da940acbec1d19b1e47be56602b6fd57d873573f8e1cf67e97ee448fabff165be2cd9b7b6a777", + "0x2aeddc77fe58c98d50bd37f1b90840f96ee5a0b09e7e9a96219dd66f0f74c37ecde110fa4c51bbb438a48b1b98077c557c474ad091c854286fdf929b0e710299b16daae9e0ae4a77": "0x0000000000000000000000000000000004f2e0c893582b2b34b415274bf95b65f52ab82079a097a9ed28349eb9a7bae745", + "0x2aeddc77fe58c98d50bd37f1b90840f96ee5a0b09e7e9a96219dd66f0f74c37ece0fc9b4caf7f03d56923fcb0c362b333a2833175025883860f6b93996233319503a4ac478b7b115": "0x0000000000000000000000000000000014506014a02fa72b89b1b4ce899d40e369b2ab4d06fc1ead4663c856bae3d9db60d05bd77a93988e8d68d67733df1c5c149fcaf773e6a74e70428b2aaedb018ac93c0579545b855f0070c2ca5c79342e333fe698081f709b7da3c9117b0b6b3e66ad37814b38fe39243c36ec13d832f06e178267058a03d5011f4e06ab78f67e0d9a73a50c79a8b6552ac4628486f70e2efdc87020ce5460f6c7c5153429a61f58", + "0x2aeddc77fe58c98d50bd37f1b90840f96ee5a0b09e7e9a96219dd66f0f74c37ece591cccc3c347d0fc90e922a45ef6a5dc3c8abed38bb0aae5b9aa7efcd388fab60e329fe9c2d945": "0x00000000000000000000000000000000049a48686506ea99e3f79e0643854fd07392d8e59f7249b61557e1662de58ee059", + "0x2aeddc77fe58c98d50bd37f1b90840f96ee5a0b09e7e9a96219dd66f0f74c37ecea9b7b0be6d4be2f0e5ac8e356d7a3867e9919b8cb1984ee5a070b1659b6195deb85039a3b69928": "0x00000000000000000000000000000000041ccc2a2abfdd492dc72fddeaae0b32888f3397860a31b3fcc88430f7c5338c40", + "0x2aeddc77fe58c98d50bd37f1b90840f96ee5a0b09e7e9a96219dd66f0f74c37ecf1172ac1fb91b86c07040b1be7aedb10ffc0f136b7e147e4a1ad56944c1c76d6c2f6ca089cf316b": "0x0000000000000000000000000000000004faeef086f38d55942fa48bacc018724b488f46ecfc2828d879c7b780c8f57b0e", + "0x2aeddc77fe58c98d50bd37f1b90840f96ee5a0b09e7e9a96219dd66f0f74c37ed0524a63ed8afdc650df6ec6f3dbb1134df6fd1d572d4dfdbe1058fca0e7197ef8d0f3d05a720f5e": "0x000000000000000000000000000000000422dd0bd944bf21712d577daa894b5d2def3b907ed1ce8cb334dff3c8216e1a59", + "0x2aeddc77fe58c98d50bd37f1b90840f96ee5a0b09e7e9a96219dd66f0f74c37ed0fb318e6895ef127add073714bbf9da81fe49db63778e918217e56c55e4f81f68e7d2e7d0e59d0e": "0x0000000000000000000000000000000004820f781b839533ebb3f3606d6bdb794136b3da9a8eab8ddb2f4b2c29cefb515a", + "0x2aeddc77fe58c98d50bd37f1b90840f96ee5a0b09e7e9a96219dd66f0f74c37ed13778bef3c90858128b1857f835ab1569c06a71e4de49df3154a9d5a5fabfa2a4f1ab1c458bc140": "0x00000000000000000000000000000000044445d3cb2872e596cdcab7e8ac9815a369a6d4277f831287523ad9da7e60a53e", + "0x2aeddc77fe58c98d50bd37f1b90840f96ee5a0b09e7e9a96219dd66f0f74c37ed164f9f8d9b541902e69ac91dc2b3e54afd2d74736e7dfd95faa1e738dab066c80328980c7c9076e": "0x000000000000000000000000000000000c0ad8b4f94dc8e6229e2c448d995094cdc1bd356dc14c6155467ac07ede18b8720f6987ec94f7c186a7c76fd7792be048d9e73494daaf0f86245f2f68cef20b2a6e63e1f89c023383484d1f16ea1d9fd66d46387f929dcdada62f8e5dcfcc9221", + "0x2aeddc77fe58c98d50bd37f1b90840f96ee5a0b09e7e9a96219dd66f0f74c37ed21b6f71d23b15bb1ea86f3c82538c486a25d8abca26760e57e76a01212419c7f1c8b510121fca73": "0x000000000000000000000000000000000815a946a44e88eac4fe2568b67d675983e9617e83d70d3ad6d9ec28707203be7eff07f170fb1e51a81ed96a4ca36d82decd18c5aefabae24a03d36ec5f8ffb257", + "0x2aeddc77fe58c98d50bd37f1b90840f96ee5a0b09e7e9a96219dd66f0f74c37ed25b2b83caf5ac06d857fcac7bd9bb03551d70b9743895a98b74b06e54bdc34f1b27ab240356857d": "0x0000000000000000000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f96ee5a0b09e7e9a96219dd66f0f74c37ed2f1f3681fa9bb4720112dff656489548b0a7815a06d3a59f93880ea46ee2662a6439bb431bab046": "0x0000000000000000000000000000000004367c5a125977696926fd9820f8282c73f7a2cc8fa0dff0f0153cd7519d6ff316", + "0x2aeddc77fe58c98d50bd37f1b90840f96ee5a0b09e7e9a96219dd66f0f74c37ed3b4bb9b7ce70c8d4e3711ff0fdcfc953c9ff93355ed42146e442c256b6010ddd5b5fe0ee8b8ac1c": "0x00000000000000000000000000000000083012b3f9f22dfe0f9f29a97eb2fbcd227e5bd4f9c27df3a24816f9fd3a4b17130d3fb75084e9d91405dffa8b3f1396968dd935308d4dddc0e119fbd6be444482", + "0x2aeddc77fe58c98d50bd37f1b90840f96ee5a0b09e7e9a96219dd66f0f74c37ed3ede878555e1dcebebf5aa73bf19935376f19460dacf00bf0dcd021ca37d6a2284cc6347dfbb13b": "0x00000000000000000000000000000000089a3e193ef4ff85f45060902986dd3ba10afd3e4a0749b6718119298be183bfde7cc30da54f59bf041de60af0a1eeaea965edff0ba95e43be290b08ff15f91716", + "0x2aeddc77fe58c98d50bd37f1b90840f96ee5a0b09e7e9a96219dd66f0f74c37ed4351e7307bc37c8d82318297ca7af51ac2546ea6bd24acca272e1627db952e2ca35df527a3cf257": "0x00000000000000000000000000000000048c6d54d22c18c9072a83594d805c1a6c4a06940528eac4c3cd44359dcf9aee4a", + "0x2aeddc77fe58c98d50bd37f1b90840f96ee5a0b09e7e9a96219dd66f0f74c37ed435a9777e7ecc393c5862ed65c524b7bb3564776a81904218f44f3d7c35162a608e39dbadbcda05": "0x00000000000000000000000000000000043c5862ed65c524b7bb3564776a81904218f44f3d7c35162a608e39dbadbcda05", + "0x2aeddc77fe58c98d50bd37f1b90840f96ee5a0b09e7e9a96219dd66f0f74c37ed4ed4dd340a2cebbbc486ed2f394da6e6b58b130687b48d3d19f756ba6d0655d37bf58ff0f59f974": "0x000000000000000000000000000000000c64563004d7fde7f69c99e461d43e799f2b8bc69c9c6941a265f5fe1e7e50c4646268664daaa26e11b1691bbada389dcefe14898f05214f50027c797d8004f777513b35b8d169fb8f713504d252be09827c6e9fa2197df14bbe563efe67af51d6", + "0x2aeddc77fe58c98d50bd37f1b90840f96ee5a0b09e7e9a96219dd66f0f74c37ed509c5c59195b1ec5c3739d60301126756a7510e34f9d656d4435cd4fe64bbd001f1f3473bc9c333": "0x0000000000000000000000000000000004a08c23158a93a3aa7de94d3ced1c9e1b4ed1efbb1e29dab0363b1c8ca4904e06", + "0x2aeddc77fe58c98d50bd37f1b90840f96ee5a0b09e7e9a96219dd66f0f74c37ed5ce1fd9020fbeba60b791f8467410a5ce2e880cc222933ad50705664917bc9d190a52596b987121": "0x0000000000000000000000000000000004982f4a55b705be63aaa88e069f4f93a955cc2e1c7dab295388d4a739ef6cb34b", + "0x2aeddc77fe58c98d50bd37f1b90840f96ee5a0b09e7e9a96219dd66f0f74c37ed87333d9765befa4e643e4515fa656d6d830c088ec251ab76ba6cebd85be7e7d6362eafff654e222": "0x00000000000000000000000000000000045c9d4bed4df1d87e33b03c63aef108b00b23253cc0cda93b528ea9f95c33f522", + "0x2aeddc77fe58c98d50bd37f1b90840f96ee5a0b09e7e9a96219dd66f0f74c37ed87f50ab0b5f9643ec5909db1fe8581fbe80eaf39b4577c12a99d5abc87131bc3d4363f623412f42": "0x00000000000000000000000000000000042e0c76ebaeb0ca61c682a80271d95abff7bd6249acb3f90cd702df6f23368b16", + "0x2aeddc77fe58c98d50bd37f1b90840f96ee5a0b09e7e9a96219dd66f0f74c37ed8c344e11655410c54fda5a0e241e5497283afebd81b53f6a0235abf62a9bd39594be3f42d291e7f": "0x0000000000000000000000000000000004867c63888fb81ef44bb0d5b761d8b536abaaaf5dae3b5d23891554e924049a4a", + "0x2aeddc77fe58c98d50bd37f1b90840f96ee5a0b09e7e9a96219dd66f0f74c37ed97b21772959b4b83870abfd18505f673c1808b61dd0d7067a810a9719c2ddee18f9b879752f4c50": "0x0000000000000000000000000000000004ca4acfb773d3f44cb7ddeef0caf203eb82d3366bef8d775a0533ef152431b633", + "0x2aeddc77fe58c98d50bd37f1b90840f96ee5a0b09e7e9a96219dd66f0f74c37ed994ff06d05e1d5898989f74514aeaf57d4f41069770242a83d619c9ae5d46cc05b85136edd53776": "0x000000000000000000000000000000000424edcf58959173bb907319517828c0e5949a178917099537bfa4895695e5d00f", + "0x2aeddc77fe58c98d50bd37f1b90840f96ee5a0b09e7e9a96219dd66f0f74c37eda1658728cb5fb3c82299cce0c148ac684639df678476effcae36c4eb8cf15592c511512a857e745": "0x000000000000000000000000000000001438f0ee79e61dd2bd100c13719c468038ec4d722104b0a95fc38af7057c28fa502ab862c753d2f6331a4403f28cdd60a942d5611882e934c079a55145f49f9659b8296804203c1734a4dd445fde8f702f106965c6a6b33e44896af15ad093c0697618f7a742a744daaea9f6761f81fc54933a584cc5b4870a47e9525f42cb176096413aaaa130817e645a00e8f380264161aa37a6ef35c2328f4c79565ae9e408", + "0x2aeddc77fe58c98d50bd37f1b90840f96ee5a0b09e7e9a96219dd66f0f74c37eda569c826c2fd86b76739ac0320c03658b64366855bd6ab037488fb23fa0d183f53b989106e25a2d": "0x0000000000000000000000000000000004203fade9dcd70e45da97d67ec48f8c5d8176be2e27cf3a612b6d6d7473c05577", + "0x2aeddc77fe58c98d50bd37f1b90840f96ee5a0b09e7e9a96219dd66f0f74c37edaf69a211b7a8ea508a23d4b915d29be5d2aa20f36649e004c6ee8df393064edad697934281bd51f": "0x000000000000000000000000000000001c1bb5e480e154b39b0e8e272ba015da6daf3f9f634fd357cd5f8611b29b7d4e51e2e0c7c189cf04f3600624f5fed3a2107ab6ccf9625663babd571b492bb27cf942091485cb911996df13bf18b2ced631569a74c5e43790f285fa4ec64142d5030d32b36853f65bf42ac0bdd182edd4601c8503e927fcbbd1f34f1f74048cee6ac2b0f22e091372190ee2f4f79357f9084e1a9d3bc9af30e41db16a3fb31fd3d192def6fae3d1c6c1598aaaa7dfbd7038c3e047da285f993929e25bfea8d04b40a618dac7de8bd9fe8561c672d303c542f356e8f27be541bb6e54e80141d8187e", + "0x2aeddc77fe58c98d50bd37f1b90840f96ee5a0b09e7e9a96219dd66f0f74c37edb564ac3abd62540844152eccf08725bea8ce898d6fc5362ff2d0bc9dfc21ed15fd138438d160622": "0x0000000000000000000000000000000008c419b5e959b021c52f9afc64d96ab1130da2a03f08f820789a20faa24a206163e4f861ee16e48158f3a84e6e04f1959495fa8b39f13b39c2d3a9a464151f595e", + "0x2aeddc77fe58c98d50bd37f1b90840f96ee5a0b09e7e9a96219dd66f0f74c37edb70f2601c34332880a135db57d4d35273d9a4f661d3dad8f153a1b5bad478f9b0e5223657aabc0b": "0x0000000000000000000000000000000004d6c6649ddfbc12a755845a05072148efc0d82ff7cf4491ba4e63cc97495b3735", + "0x2aeddc77fe58c98d50bd37f1b90840f96ee5a0b09e7e9a96219dd66f0f74c37edbc1bb2de0590492cca2a0719fad006090aad6536ca8b7d8c527589be01b0012564dbdd36d9a4923": "0x00000000000000000000000000000000083f9bd8000dedbde0a47dbd7bf089dee1fa558ac28796942a5883af07ea59fce1c0266f91841edb77e30346c6da3975b5c3ffce4a2b1ddeb696527bcc0279f3ce", + "0x2aeddc77fe58c98d50bd37f1b90840f96ee5a0b09e7e9a96219dd66f0f74c37edcacdfdedda85ff952e73898bf4601f9c9a7fa052de0cc313b159dd368d458f4cb0341eedcd6d818": "0x000000000000000000000000000000002c4a4ad21f7448e3183c18b8314ffecf0b382098635efdd056e0af7c53228ba4262a5a25fb22ae60a8a24177845715bb880e16ad84344e91d1269ea6940e929f5b920799b25e259ab600be83eedfa7807ac27a842f005dea4a2bd49799840f4b3a449e6184747b236ba5577c3560b7739e35718c65039b8997b7e723722512b310fc53b8a54a21149380351cadce380bcd0028cec8145c34fbb67db6176dbcd31c6c8bfefb8ac4b47696a47ba939ccc48415c02fe947afd32437190cf5a36440024e9807808e2487f1a38ae21d64de700342dd7feac9c23a7293da4687e668e71d109507526c7136932a5129122ab622dd17ca59db69ebb7ab94ede6f7992fe854ee67b25f8646b574d06dda6da0b74ececa842c48cdc5bd8fabb48276f28a6043f444730a05ea7fe71e53277384e8e78bc1c8b8c6858d2b177e16d6d1b05c12654e8b6fcf0dee98dcb0d710fab325fdc6b158964c7011e9a43be877bae760717f", + "0x2aeddc77fe58c98d50bd37f1b90840f96ee5a0b09e7e9a96219dd66f0f74c37edda1f8e340e37b261c39ef78e57f239200072aa865312f87edfcb4d4133c6ccc0a7e33f5c799e201": "0x0000000000000000000000000000000004d45b3d8d71f6ca469454a375a951d272db9426e3712e172272f951d8b289d300", + "0x2aeddc77fe58c98d50bd37f1b90840f96ee5a0b09e7e9a96219dd66f0f74c37ede17584cd268e75b0277ce02b2ac78ceeb9ae4fa0a595005489bf3f5f77898415e32a3e9504a5314": "0x000000000000000000000000000000000c544e2e588c90a2e53e051d2f87d40e222e1f034913a30f95a9a2f39114e5be3810230b53a6fbe58eb3eacc65cd3ef675e0456529cfb02a97eb43ff93bb6f8064cadcba686c8bd7b8579cacb9e1233fee5eba81db5e7c25328b724198bc499b2b", + "0x2aeddc77fe58c98d50bd37f1b90840f96ee5a0b09e7e9a96219dd66f0f74c37edea8918004244b5bae0ce04d8021516cbf0a10c00c4e721319c1e91c729402b232942f9e2c152320": "0x0000000000000000000000000000000004c4ceb4225a9a168528d1264733d5b6bb5176c0eb31bb4ca3c962be4cdcbacf71", + "0x2aeddc77fe58c98d50bd37f1b90840f96ee5a0b09e7e9a96219dd66f0f74c37edecae94c7ca0c861584d715bcb7a2d3b6a3120891dba91b19b12df42cd50f1c76103e2581d5b4274": "0x0000000000000000000000000000000008c2bf131a9bc49208383fce6b0ebd78517ff563ff812f146c441d917dbe726c4dc2bf131a9bc49208383fce6b0ebd78517ff563ff812f146c441d917dbe726c4d", + "0x2aeddc77fe58c98d50bd37f1b90840f96ee5a0b09e7e9a96219dd66f0f74c37edfda9759c850e63fcad4349f82754f223d99182a3f9de949c41ff94e672f7f548e7f4e66c04b5c1b": "0x000000000000000000000000000000000486cb4a7d71b52b87a0ba07d245f92cc52dd40259d14190cd15f36b509f7ff511", + "0x2aeddc77fe58c98d50bd37f1b90840f96ee5a0b09e7e9a96219dd66f0f74c37edff9d344c62cc1a2a89a9920a98f3591ccc0a1a4bc827a0adfba37b75fcc108ae3c7191bb9a32750": "0x0000000000000000000000000000000004cefcdee5940f8e74338264c625fd7fe4c671ce205773f69e8bf4cf1b372f8e26", + "0x2aeddc77fe58c98d50bd37f1b90840f96ee5a0b09e7e9a96219dd66f0f74c37ee0e206491404b059c229d8ccc5e5650d17760ce2b7c42bdae5f6afc6e8bab249ec77f3f779ee5a65": "0x0000000000000000000000000000000040b046bbfb0ab2a461c916bd646f879787adaed72992ff0182233cc798fc9a2c314c9f8b6c9bbd518b19a4fe57cb38df839f9d893c577a9106579de22ab1ebbb36de670277a4ec31a0664f1d47eb01a7fc351952d63980ac1246ae1e6751f615041883cb0c880e437370dbe0ab6747e1d6fc6decf1e0ef4f423b815f14e3ffc00956c33c3e6261199d162ed7e756297752416cc7f7dc0eec30460a12a0a7e0c577c08ef34fd7c513a00cc447d3a01368dfb0df9d3c84ee52182b8749e18573e14d80de9a994f4ebfe1053baf13182362e06fe78b159c319be596fbbd8d027db5768a51fcf7cd53d24e15d85b8180f31d5f9b295af7841f9448f80b7264f381875222caae65e7ded01a955d36299f613aa1636767c9944621bf5eb149290339b97bd047791087bdd0caca708a478371eb8dfc056a36028504ea64f4cc43713fa9180069c3ebd00f7ee39c7f8affd0d14205768535bf95633e60e26f8c8006c27f5366e499f4ab6510c9b071eb403111b1d51b97195af9cc2aa65db79f3b84f0976298735853f4d1ce4c0e545e53dbbd8c65fe5f89385fecbb646a26fe00cad7795952e2931449f8d897dd10fe7f753414821fc90698d940050169a863db5093bc3bfaf6136c1b5c48e96fa266bedbb262f30748b53d9da7a435423272e1e67ede7968ae914b1cddf602f7e775099eb62db646dcdabf6c32fc0bb1b951e94130503d", + "0x2aeddc77fe58c98d50bd37f1b90840f96ee5a0b09e7e9a96219dd66f0f74c37ee26aa6ab4f40124e083f39607241c8ebb62919ab2ed816cb6b20c7d0abad78a92570030d2f96c63c": "0x00000000000000000000000000000000040119766bce9e7ccb7adf4b74870a29b352995478848ad500f46166c797f1c326", + "0x2aeddc77fe58c98d50bd37f1b90840f96ee5a0b09e7e9a96219dd66f0f74c37ee31e32af7d282fd42cf0838b05fb182718de859525fa1e6d53d557e5fcf631ee9ff44c619810d43b": "0x0000000000000000000000000000000008426cf52dc5549d7f8fee37c20ba68afd3443973a05bf692185cb913fac80887320430a70d2db1bf57c424e5e81de47ade7f1f0ceae2b568b9182ecf9b025aa35", + "0x2aeddc77fe58c98d50bd37f1b90840f96ee5a0b09e7e9a96219dd66f0f74c37ee3e9a46b476478204c4769cc1bf4774f19c7433e31a5b8cb686944cdd758e193d264410d4918b120": "0x0000000000000000000000000000000008742e6def792a15d4b2518cd2a957f9bb7f75525308355f9217a2df17a701128a4729298bb2a53d0e5974d34d14932af4d4905334d5f9a57d7931ed1eb04eae67", + "0x2aeddc77fe58c98d50bd37f1b90840f96ee5a0b09e7e9a96219dd66f0f74c37ee424960c1224933864e05e73625f3f0991e3062733ad8480c5589a710a24beacbaa555f1c4a7f064": "0x00000000000000000000000000000000040ac2e966527ec0e3076ac6ae05402fe763d6cae60a8c01e108dfbb6e92d0863e", + "0x2aeddc77fe58c98d50bd37f1b90840f96ee5a0b09e7e9a96219dd66f0f74c37ee4a7b18b604b590ebe4b9973a7f6a5586a38fa295ec8e64d4026aa878c840630a7ccfa7f3914d162": "0x000000000000000000000000000000000428e219b7c6307a185ea3d7d203fcbf5b78176fc0601cd62b1a3ab95e81e06116", + "0x2aeddc77fe58c98d50bd37f1b90840f96ee5a0b09e7e9a96219dd66f0f74c37ee4b5facde9bf411dee16a0a68c6bb00ee88ee56a12ad67e778bbee540f868ead35fb6851fc522c0e": "0x00000000000000000000000000000000048e74741b4eab0c60f4b1621f8d244da79dc84785622e52ac8e4e5d3da9f9e512", + "0x2aeddc77fe58c98d50bd37f1b90840f96ee5a0b09e7e9a96219dd66f0f74c37ee4cea58d581e6c8f707c9246c1c227f1495885cb2f4c59297248ec5abeff2d0f68495075a16bc17a": "0x0000000000000000000000000000000008289fad9cb619fa9f9b77fd385d003476fdacaaac6ba7191bf5486aa09e1d83298224620901db3a08a236f1417e7f865c079b41c0b2e6cb0084109e4be3fb1d0f", + "0x2aeddc77fe58c98d50bd37f1b90840f96ee5a0b09e7e9a96219dd66f0f74c37ee5ec7a33cbbb8d9e04f3da939fa351c562c7e06e1e3716976b5e14230e83a45995cbad9086f49e17": "0x00000000000000000000000000000000046d6f646c70792f6e6f706c730012000000000000000000000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f96ee5a0b09e7e9a96219dd66f0f74c37ee6c2c15d71b57c80a8cc040d5d391967b6c50b54d81dbc18acf06fd13a704decc7df6f464679051b": "0x00000000000000000000000000000000042a646f536fec9eeb72210c0a5ae166e0b0853846f4d052ffaf438696921bd725", + "0x2aeddc77fe58c98d50bd37f1b90840f96ee5a0b09e7e9a96219dd66f0f74c37ee806de170873b7f5bc955504a40c50ded178a8082516a78a68f503348c16b106fb2a1aa2c594743e": "0x00000000000000000000000000000000045ff5a4655138350a17e2dbb4ed130642abbe12b52ed03867883f0af9a1ef0cc8", + "0x2aeddc77fe58c98d50bd37f1b90840f96ee5a0b09e7e9a96219dd66f0f74c37ee86ac2d54fd84df0f4914e62f037cdb798c40ea01fd56e555b77635e0e9b7175b98bc9514021756c": "0x0000000000000000000000000000000004d228fd275f3f92e8b6ccc56a9437582dc59db70153ab33cdd77562661adda60f", + "0x2aeddc77fe58c98d50bd37f1b90840f96ee5a0b09e7e9a96219dd66f0f74c37ee94531e277a1ad52dcb38c186bf97625f108b4832981d966ebed50d939349d4437a6f538d40d5676": "0x0000000000000000000000000000000008473d3b1ef58c6170dd0d8e4f61cdd1d594cd17280988b52a7333b3a98fed4269eccb809fabe7f585098c7e61345f71c2e651c9fb61f16ea74a5ed6279a644d74", + "0x2aeddc77fe58c98d50bd37f1b90840f96ee5a0b09e7e9a96219dd66f0f74c37ee9521ce485bf220366a4d150e1799ed9ffa721e7e95397c4484db801fb7f26fbc4f27e1d158ef839": "0x00000000000000000000000000000000043650aa13fb0f5a4c3a5ae264eb820463be11b8fdbe5fd09cb34df93c19430a22", + "0x2aeddc77fe58c98d50bd37f1b90840f96ee5a0b09e7e9a96219dd66f0f74c37ee991a1b779e8a17838ae9a751c06cfc8b4bfb06f4d0b8d88df80fc88317415ad6f1b9bb6ca114941": "0x0000000000000000000000000000000004f16a6e2b7183e7a10f701d357d224e9ca87bfbc49a663fbfa27426a8f5e9b1d7", + "0x2aeddc77fe58c98d50bd37f1b90840f96ee5a0b09e7e9a96219dd66f0f74c37ee9a6cafc1c447d4fc2a82d0740d343bbcf853665019f2afe81ddeb884f76dbb5c74533610f72a732": "0x00000000000000000000000000000000085eb5606f625995f4a16ab77fab23443b28b5ae51964638b6c6d1020f5cdf5d04568538b172c522826347235dd841d08c6512bbddf1fcf91a10c9bb9542b75ca3", + "0x2aeddc77fe58c98d50bd37f1b90840f96ee5a0b09e7e9a96219dd66f0f74c37ee9a938ca9a4abd3102b2b0de562a79b5ad9c666c3f9e7752955f3b2c2b4a17c71125b2668ea9ce5a": "0x000000000000000000000000000000000420188a2097650af57e7cba4be37d595ec1884b69aafc65961210f295467a5313", + "0x2aeddc77fe58c98d50bd37f1b90840f96ee5a0b09e7e9a96219dd66f0f74c37ee9a948cc19db68dda45d1343d565c182e0e1cd3da2d6c0b1ab5b17a77ca165457d9620db19439a64": "0x000000000000000000000000000000000443dde39c254993375b5d7905319e7700ebdbf57acd84e44b3025d869ba7d8e6b", + "0x2aeddc77fe58c98d50bd37f1b90840f96ee5a0b09e7e9a96219dd66f0f74c37eea41c7234ed3632dc50f089e43c19f3f4ce606cd994bbecc50bf8dc53e970c0c1c592304f651966f": "0x00000000000000000000000000000000049654bbc25d7891d49151110003c37da87fce6eb551768c02e47eae754b61b466", + "0x2aeddc77fe58c98d50bd37f1b90840f96ee5a0b09e7e9a96219dd66f0f74c37eea99648ce61b6d52d86dba437fa4388bc312e57328e808cb1d37cd49143b90c338714703867edd7a": "0x0000000000000000000000000000000004fca784faea5287b50efffea3b8ec2995d80648fcf5292f38deeb5bcec2d15e2b", + "0x2aeddc77fe58c98d50bd37f1b90840f96ee5a0b09e7e9a96219dd66f0f74c37eebb9d8077a7da3fe98672c4edf6d578c3151aa2e8d55431cc874360eff95c4592d917fb09a6b6316": "0x000000000000000000000000000000000898672c4edf6d578c3151aa2e8d55431cc874360eff95c4592d917fb09a6b6316d8c5a6bb60ac4bf7517a02c2612d122e389ef4684a34b5f7be058113e9e74c75", + "0x2aeddc77fe58c98d50bd37f1b90840f96ee5a0b09e7e9a96219dd66f0f74c37eebcbc6c0c66547df8c4c81f382ae2c201eed4b0b519f352aa9c0c8593122418b30ac9760844de2fa": "0x00000000000000000000000000000000103c53243e05c79ffbbc910d8df74e4d1ae0197db16b7f00662e2aac74c8ceb3021f81e872efaf12f97f5a40b31afbf874bde9c0225e89511734f749b4b1d680ae29c22701c5675f9a1d0c99c86c5bd43a5c781b5029d080077926cd3d3d17a81f15ece2a3d6a57419d76a4a66bfb72185e128e3abdd1e13345052f43f21548a9c", + "0x2aeddc77fe58c98d50bd37f1b90840f96ee5a0b09e7e9a96219dd66f0f74c37eec9971789d54b940607b422f959ab305856c1621be625a1776d2ffddfac9a03446da3052d7cd3a58": "0x0000000000000000000000000000000004607b422f959ab305856c1621be625a1776d2ffddfac9a03446da3052d7cd3a58", + "0x2aeddc77fe58c98d50bd37f1b90840f96ee5a0b09e7e9a96219dd66f0f74c37eed170e36fed4d7829c7c545141ea2dd84fe5ef7d567ea450f59967e7afa68e5f1ff7f7c46db19627": "0x000000000000000000000000000000008d0144ab70adf9b1a6402cf14b3c61f98acf5bccabaf0030d537510166a21ee44d1676c26a1fb9acbdd56be00d4c44901856929b9d2a879caad6119ad0417e9949495ac7f6af5aeb5364188840d02f0e74e813e6d9cc0398d6994b66727658a4fb306cf4b9ce8d60ca73a35f036cd58afbc52ecea4d691484586967ae1ed45a1c4235627b276d86cb8de65eb9b261907a0134f1eeca33e423eb357ed4cc339e68d1d2c61f078a240b295eb8d19db50e5b27b39225ede1cf718c0872c441cb7ac8d54aec16460ec51be05e01406f39af4e8adc9d400e511cac7aebc10c31d42540f46c0c86652faff45a0e4a86f5749bf813d9d40aac848b8c672123d7ee2503a6d5302c1151878ea5c35d75c7d4f879fb48ea7a4199e2d3ac9ed79d686a157384d2fc6a8eba5ee9f02ca31a31bf5de2dd406adc9c55df94001f6efa28370b154544d72c76dd7083bfe6b601d39dca6288bb8adaa0673c914f3b0c40ed812fa4b5429c2b18a21865fc3da2283153ebd44a5da61f33753f6f20eee1d8e41fcbaa0dc67c0d0a4ad7841c483d4cb7813af9550c9d7c1b182613bf27a900e5211d9b64d6898ab313fb0a6faf344c680e6afda715f41179d993ab86f25e481a6259c97634380ec6fb1ab57be7d791fa9bb7e711b2736c6422e0b66932b54f3e95f614b4b2de852fc4a048379bc123ee21bdeb4c6a4d94ee131b0920ad219d6cc280b0a09651e25c43583448b07d9e3ff3a2c67c1674ebc968258e42ac4ac000204f6298774063dfccb3cf16ab95e3af6fa877724d2ec90697596897ea59069aefe5c223f58e293a27231ba1550c3767df641d03102ad153acf8b4bdb7db7f180fa9d544d65faf6bf2c43d534d180a04d58c2838ebe73f3c98e0c3699f224ef0ac156c65e23322e857c9fc42bcd84f6f4e2d1f7f892baef31f1da5731d22796cfc40e4fdd5dd4c6173852da2969c43006a3806502c5f6bc23e1f3e8d5507baff2b5e2f1774ee040d1b984526d7e5222ffbec6cbe8bdaa73f9190a9e3d7244a54fc99cf37a6574b215d61cfbd296a81d6ead301607072d2bbf9dd308c3606eb1b795a62bcf2f68851551f073cdbb09116a1e5b1500042b1376b440f967b0ff961df638fae8675ef2424315d83ff1d4199b1151f91ad9c0e89306512b02f846f7acf17f00da67081c3d2269ab0253aa2d2c40fd37ab6e7304b0daf0bd6068d0d689fb51f1c40f3a365c988f1b8bf6c4574656c803938a4e0250e25837f74fa6046f0ccf225123345e9fdb6c477d50a5c7be50ff581405ec6c151ed4ca2c25cf21a510e6bc7e6b603d8b10a42a8be5f7e755820b0c4241732614384e039536c8e43d3b414430566cbed2071a6b6848b4d170409de00af2da5ce2245166c9a5c32ae79fcf44876f7e91f2c936482460b397eea5923867efeb2635679ca776cdfdc62bcea000250de6897f5eba9ec46ed569cb3c532d193f04bccc3971b065df4239a18a1e5e527cdc89c6865c029c1088fb27b41c1a715b0bb611b94e1d625fa0bb8a1294187454623ad4601b91806226421ebcc2af8a4e60b4292b52e9fa8bc1c57131da50480048636a9fc435413c12d7c7524f6c12110ff15938dff2da4dd92cbc87696c721a6c6ed8531e6c0b882af0a42f2f23ef0a102b5d49cb5f5a24ede72d53ffce83174c08de8a66557f63521d871087a9290cf8032705cab1ece83bc4e5a230f13020f29100ef06c7724dc32404caf185c03adcfe64e92a3a4885e08cdafab2594d2de635bb7c13379f6b759e79aa78b8852d750afe7da16ec7f01139fef08849147b645c0ded9084b8186ef4aa2d83ee1c5ab326757267c41c05444e15c657438424f4642a032339376577e3ff7f6d55a53fb6519c5a20633e30bea2bd4d2eac3a0540ad8a6c92b5be3305a78ec0ec67cc600e791fb2769b9cae21cad79c40f7c92c04f231f52cd2a234dd3a72a7c920ea6e10a7f85abede1a9b4062428bc303ad7d5a43b9d3a39997151c4d745c1513b73ea440fcd50aec480eb4ddbe65fe692477a4b5a3630311d5cf8919e20be535ded925f210724ef5c78f8e3754a32ed43841d21f6f288702a2646b5cec6d0cb5f77d48638af67cf77d6dee823e2959ccb967be03f2946dd310eb0212bd2c44122eb48cf77c834699f6bffa88e2697e7fe04f545513938fda2f111c89660c78998fe45547148b9c2c0891f28ccadc27313a4516c4a4dfdd6c04572aa9c3fbbce888451c65cb1a1c96f611aa638e609cb6f609007cf8c189e43ad7cc1eaabd0aeb82ae7d62e5ca915f6bb87c4a0d85bb8c3772ee75ab2836d2ddd324049b86b224542d6cf8a12b601045ec14c454fea4e9cd470e2515bd2e4ff6a32fed6306b3fc37095cf875c65f987c19c2b2691d8545fe51463b64f13f694e789b1c89d219210b4aaef27fcaf8621ce8103f88e3951d054ea00b6ded2d4d0101146c5f76452f6900532c39cfb36b911e38776c782cfcef5940e488d3a17720b2cc51ddc6cc6c4afb23ed4fcde97698aa2cf374fa7fadb37db0820d7db40e2a9fe96c7ef2e810cc51a7da195bc995f329ffde72fae04e7b3e2c85e23060a9c8b4598f2927a796f8062aa3843dab76f9eadd8b2f36179c263e1a765697eb319802107fc3eb312b686bc335cf4456be1c46d6482bba3e1eb038dc7a8f82a2faa5ec9326f6970edcd577f8ed603104845ad07ce5c5d8f4a49d551233533732bfa8bcf7a95e0dfca71309e49a1fdd70d43fd5c405505a6826ef725ae96556bd15eed67a54fe5f9191835994d94c18a764ea4280bd03faaba617740cb8ca7ceac36a246a8295a56068d2b532fa2c61affbb34bc5a80777d91f1805702ffebbe8d46bc7b2d33457e61ee616e16c56d726244a6ee549a2572345987348ff655461db0e896365cea6351beafb80b40f19a3c453fc27e6609f872e4238a42184be9cd7657a019c2624c045f4ef80df884576b0f2e1eece434410537a3708c74cb0df1d73c69a078a6dd56d80ea94e08a2f72cba07ce6c5b471fcca8976c89604d1a2388771784ef80c5577fad1e75bb2362d5d578a94e8dfb3d982e938b8774ed1e7c90fd0dbe40fe7c6a8d810484ec59624b59374a38a8bbf9d91ee1b54bcf53ff5d97b41b38a3a5ccda86b3a3b1d7090a20747e2bdfb2cc46a38d514eaa00abd5e6449dd46d8882c6024f26cb5247d26becbfbb4f57314d342b96a653a620493bb740849dc2f946560976cc5f8fc004b038cd61859f5be0b2ae3643f545e8064f8898a29d4811e09b207cf3302e5cefef16615f8580fcd8fa63a624e90549dacdddd5bba278515f623f95197c97a6a7793e1e350c7492a9436e4a90db0b7458638e3862d435924db213a27b64b5029bb2f06f68bd337b1c3de43fe44e816b1ea4928a0d642ee4b4fa99aecfb717bcd47086edb11316254c2e5844d2950bf01d23906f2dd19d8cd71dcbd3033af5fa1dd042dc4dc1f3f5f86c2e9ad5b50c63f86e505700906b9303be612c11427a137eee64475e048ca585562f79c50e8ce09ecba19cbfda0c26fd052cc50a5365b22ced871d32fb6a2eb1853d2bb7eaa672cf29483bc35d2991a17f143213bba4fdf81050113c483cd205f689032368aae19fba03bdb71cf735646aba2d56fa5b4b83aad3d96804d70e9559ed8071efc036538dd0a7335685f0b7f62f6745658ff16bc2d61a8830e70dad3e1749355129129bd5eb2ac144f5d28695aa11f2f14153863409d08656f7e34c2963dc1128866bf5337468c1c81b265c4d9f352ad6b0e50b7fe77c4a660fa9ce31e45154abec1f258092973881a9591a5f751a5ca2b305c6bac9f4500c0e56ba02dd8581d42e37b2268e7e97d6345f7611dba1f4f58baa27382b87cf536ebdaa23c3b811ffc0b298393d72240ea0a06586ea1227e8c84f786c7fa05879e1ff28422017370b65d8d7707042e22fbf2213c687b330cafa3a792598536cb5fef7aef40cdf07c1aa9d3c51f17264aea16d04dd1b899fd311853b2bb2944487ac2c43f1e3040482ab01782078bd1515a3027895439f31237792568ad0eded4af3d31cbf30d951756a88434d91c219575e30f91afe0ef870901772375a33f006fa82b7c743b49176804069db501a5d23ad862cb312892bdb603740707c1948b797d4d30dcd76d1bc83bf4af534e16af8aefbc56dcf58d3488c77601bb1abdebafc2fee50534af7facd6b218c883c8ecc7a71a6b22a74261f1c2394399818ad3f3939ef31e463e23687a846146ca3cae0d51993c0e186d6026b2134ca05e213562c0141a85b4ef5ce85a54ca5474be7ec4f0e149232199a19f1f962331e1ebd5be36cbb77d8b0c3e4c6a12b41192cb3355642a4de4fa55ae61387c23673f0e8c8637dd864eb0c443983a3e49a6aef7637adde845d561274ddf1d66ce267c81b3b0bac979ff79106f2c0f99b106126a14a19ed92af1bd9055ca4c39fd9ed5ed2305d18f6730ac5470", + "0x2aeddc77fe58c98d50bd37f1b90840f96ee5a0b09e7e9a96219dd66f0f74c37eee577071e47d1ba7b8a40f17f9fc62194fe1b12c10e8a2bfb5efc7057b119f4ca3b05ba96eb7da6b": "0x0000000000000000000000000000000004b08c0a54f1f153adae9df1b746cab08c40e3b949cf2458f80ac43ff256f2c17a", + "0x2aeddc77fe58c98d50bd37f1b90840f96ee5a0b09e7e9a96219dd66f0f74c37eee9be5f0b44a2889287e6f010e50f642775dab59f39ee4de313fe6325181ca603824399cf4d42c08": "0x0000000000000000000000000000000004787f2dc3f07598f255932ee1fd3cdfea934389c61a31473a87d270655f70811d", + "0x2aeddc77fe58c98d50bd37f1b90840f96ee5a0b09e7e9a96219dd66f0f74c37eeec11b5fca7cddef5270ec35ba01254d8bff046a1a58f16d3ae615c235efd6e99a35f233b2d9df2c": "0x000000000000000000000000000000001480c546b7e44391d7f7832d8cd5456f7ca1a76a73e73807544a4184bb59ce60481a2b2effb22453209445e66e170f7beeffb3b66c900fa8fd49cbe9efe9eb49423e4f57a212fd4403b083d956909c66b8e492e24c48095c3681a5a282088037445009e192ec169788c9c1f0202fe7c2bc79405ff8b6e1d1ac78fd6152006e606dd091cf86d04141b1c17c70826c08d074cae1b00d6f82de1b8a5406ea10ce723b", + "0x2aeddc77fe58c98d50bd37f1b90840f96ee5a0b09e7e9a96219dd66f0f74c37eeec1d763f95c70cb16eaf9666bd95a04bc6ed619c30a4809a43fd7265e414284c11b27b8c666fd23": "0x000000000000000000000000000000000894ee7175041f3293479d3abab6dd9fd5e5d463f539bf6eb18a2bfc85e6c5bc54c63d0c9d2b2f1b51dee3c65bb2714871c2913cf646efe3c775d5cfefd4e1bd89", + "0x2aeddc77fe58c98d50bd37f1b90840f96ee5a0b09e7e9a96219dd66f0f74c37ef035a0d786dbcf44868cd54faea1a0e45836635b2bf658733436ec69c5567d651be592392cbb69dc": "0x000000000000000000000000000000000c60857d3958e4e8809b36403726468f6b336e952d7cdee4a16c32126719dac4113472a370eb332c43576f14f315b219aac6f86795a580d50cf5454b4c293b811f300685aa838106c3737c9e6c6086481f3daedc1b1650b84cba9405389ade856c", + "0x2aeddc77fe58c98d50bd37f1b90840f96ee5a0b09e7e9a96219dd66f0f74c37ef04fc71c9051dc296467fd4e7038b925c2422357380d8cc0c5f17d272f639af8fcfd1f1156de7040": "0x0000000000000000000000000000000008bed497470a04ca4c13caccd69c7827e3ddc64473fd2d7c5d496c71061f452b05f6be65cc16c65708bb6a0e4b9958ffe23d1c56ee5683670a69dbbbb70c10d507", + "0x2aeddc77fe58c98d50bd37f1b90840f96ee5a0b09e7e9a96219dd66f0f74c37ef1352327dc3be8a0948223bb2e7bcc8a55be248add34b625c1c0826c58fe037fa5c8e4591440dc59": "0x0000000000000000000000000000000004587fc2461b55e47619ef522b4bd986f71f7adfd207166e6dd2ba381117a2dd08", + "0x2aeddc77fe58c98d50bd37f1b90840f96ee5a0b09e7e9a96219dd66f0f74c37ef1697a69799d08e44211b834beac4f35ff92e0dcbb0167f6ae7a0c43b186727d581d3f69f10fea34": "0x0000000000000000000000000000000008e68e209129894d176228151c41e67d96f9d8ed4da38338fab5c964f2cd2c61562860f5267cc37b8ac5cce7fc5e1e00aeff5c951ca71a7075e75e5be1136e8e3c", + "0x2aeddc77fe58c98d50bd37f1b90840f96ee5a0b09e7e9a96219dd66f0f74c37ef1fd5669b551e9dca43b2797bd4dd454d7fb0870a2a4edd62b39eea0801f6baaf09b05c8634b5a25": "0x000000000000000000000000000000000c384e257ac2372c996a4180f6d9a9a0e16631cc76929c600468583e8d798c17603e586d68dad3baa2426853204a502f7476c280a7cc3bcc4f25bc4bfa3e1216015c3e489388961303bbe308673f7faba33bae973af37d6ca444e1772a750c9775", + "0x2aeddc77fe58c98d50bd37f1b90840f96ee5a0b09e7e9a96219dd66f0f74c37ef2148a94f5867abb148a35cad2b2fe9cf6ffe0baf5f4f2f4ef894263baefead0e797a1e3e6d0a07f": "0x00000000000000000000000000000000042aa7daf7650583460d76859d7f4fea90eaf792ad9cc03e9bcc2667f165f00b36", + "0x2aeddc77fe58c98d50bd37f1b90840f96ee5a0b09e7e9a96219dd66f0f74c37ef24d4d1adb36534d96f7daa1a00790f8b168d3db7f0175e5f8dfd3430dc7edb4c5b807bce2b9d93a": "0x000000000000000000000000000000000493bd14a518853f72f3deb5357ee12fdd6e77151580b082bd468bca1358250d2e", + "0x2aeddc77fe58c98d50bd37f1b90840f96ee5a0b09e7e9a96219dd66f0f74c37ef25ef82af77881fe240cc50e90684f175ebef583b904fbc0b9aef4b38aaafd53e6436ad3e70ba366": "0x0000000000000000000000000000000004d2c2f040d9b3546eee26f30efecb97e72fdaddea5d4999845b37742841e95f57", + "0x2aeddc77fe58c98d50bd37f1b90840f96ee5a0b09e7e9a96219dd66f0f74c37ef2852cbaf60c5e38269fa27098d88ecb1640185c91860fb62d92ae9a6ab7713c79485bae49862b39": "0x000000000000000000000000000000000c269fa27098d88ecb1640185c91860fb62d92ae9a6ab7713c79485bae49862b3944a8bb3fcbbd5b54617b782667c7f8c5a89ca53c1f878cdc9dc1766f447ea30f922988e0c062661a2af3df12782ee38f6df030390d1874d113bb8a53c165f147", + "0x2aeddc77fe58c98d50bd37f1b90840f96ee5a0b09e7e9a96219dd66f0f74c37ef2b06e2ea680db3c12d9c0035dd422388e6d346f61df3d9f3667f8ab761c8c57120dd61917976e10": "0x0000000000000000000000000000000008b466b09ad7c824d88e8548f5587ba158415f7514a0d0dd7c18144f6503507f473c1cdb7f10555d9e080e83ac20acbb4880b32d3d30319f055e37652c7ef3d36f", + "0x2aeddc77fe58c98d50bd37f1b90840f96ee5a0b09e7e9a96219dd66f0f74c37ef32bbb6fec42f4b03e89cc7fecc4ad46cd7ba606522a8d1679863da498718cf9acdafbde8cfe4b78": "0x00000000000000000000000000000000049e7fb05bdd2dc88013e77f26a37dc19e1c1717fde8a27bfd1f2fa8231ddf8538", + "0x2aeddc77fe58c98d50bd37f1b90840f96ee5a0b09e7e9a96219dd66f0f74c37ef3e3959f84b063bcd6c29a7c39cee45b0e045a94081bc188ef73be2be086d66aefd850fc7eeacc45": "0x00000000000000000000000000000000083ee307326a809fbca23841d62753a3aaa5d3ef29e45a4f810ea1011c178f302d4e1f1d2881471357ea697093e5e68d46712d2b0e5b650945c4ecb571ea43757b", + "0x2aeddc77fe58c98d50bd37f1b90840f96ee5a0b09e7e9a96219dd66f0f74c37ef3f9a9fea1c2bb71688f2dd2918739ffc90f280131b7d8bbfeaf9f0e2bacfe952a88bfa3bc168045": "0x0000000000000000000000000000000008688f2dd2918739ffc90f280131b7d8bbfeaf9f0e2bacfe952a88bfa3bc168045cc2db6639c1895e08c384f618c9f215e32e0fd23f2ca0ff3b013d1c658287a75", + "0x2aeddc77fe58c98d50bd37f1b90840f96ee5a0b09e7e9a96219dd66f0f74c37ef5695ae6155ce7ab243612f0fc6c935d9ee0cbe21c453a83f58a9427054ccdc74966890ca57ca719": "0x0000000000000000000000000000000004eef86cb3454d5d2d17aceed4598209af5d3ec6a09cacc00bc88d86bba7f34645", + "0x2aeddc77fe58c98d50bd37f1b90840f96ee5a0b09e7e9a96219dd66f0f74c37ef59d68b847bcb2beacab23f327e732756f5d76a43cd32830d5d8a9a489cd9c5c6a8554a3374da056": "0x00000000000000000000000000000000042c527cb7d17e0fe6df0e0da303a71f3eb46ea5bd309858389666ce6dad8efe15", + "0x2aeddc77fe58c98d50bd37f1b90840f96ee5a0b09e7e9a96219dd66f0f74c37ef71158c0f51bb8fd5247e73b8ad3c36bb4e01c93a9bd6a6048afce1e2a45863ea5fe99778b530b61": "0x00000000000000000000000000000000085247e73b8ad3c36bb4e01c93a9bd6a6048afce1e2a45863ea5fe99778b530b61deb5320179cd1dab5b17c203384b7ec2fa9e73577a82954f9c526ad535552422", + "0x2aeddc77fe58c98d50bd37f1b90840f96ee5a0b09e7e9a96219dd66f0f74c37ef71b1777c4c6a13546b4eca928ede3e8075d86e25581d46adf3eff915646eab110d13e2fbd947b5e": "0x0000000000000000000000000000000004b4adbb4e711987eb53c39b12dfd79435736f1317a869db5f50d5a913e4045550", + "0x2aeddc77fe58c98d50bd37f1b90840f96ee5a0b09e7e9a96219dd66f0f74c37ef891e0d61d95d2f9ecc96f0e735d4677e64728f5300b27c97c3413ba01e7a60dd29cb89123990a66": "0x0000000000000000000000000000000004c0020cde3bd8293eb5d5b61b072a9f6b19cdce1624a8ee4a27ca8c57e3ffa628", + "0x2aeddc77fe58c98d50bd37f1b90840f96ee5a0b09e7e9a96219dd66f0f74c37ef8ef4c38a66ac4223cf3f47f611c9dd952bd9007a85b0d84383f91e2f25edd0f13d6be20b5805110": "0x0000000000000000000000000000000004be0bc39e129f4ecfac3d20c50d78472dca69f693150064093df5edb3a0caf14b", + "0x2aeddc77fe58c98d50bd37f1b90840f96ee5a0b09e7e9a96219dd66f0f74c37ef94e92ce97ad9912aeffde5a4dc7117e4cdde2d3fb3d2afc7b2f710d5d66c55c5d1d7c5873598706": "0x00000000000000000000000000000000044415d4ced8c9de7ba415022d5b356f25eeb4d9dcd522732b2c87520e29e66044", + "0x2aeddc77fe58c98d50bd37f1b90840f96ee5a0b09e7e9a96219dd66f0f74c37efa4f3e525e10f673faeffbbb88ab949b51abcacd45d7f9addf608a6e6ddc3d4b39147454e1a23a16": "0x00000000000000000000000000000000045f58951d682a66090492f70ce968af8b8d39a6308aebb3cabeafd44bb0213d91", + "0x2aeddc77fe58c98d50bd37f1b90840f96ee5a0b09e7e9a96219dd66f0f74c37efb1e196ecaf7c6ef54ec6a7bfcee3ac00ab63b98e084f1a1c4d0e82ff63c31387aee91c9a721a81e": "0x0000000000000000000000000000000004f063c0ba3d0dfdd209dc5b98dee86531ad264283fce758952e49f8e6b7f85c7c", + "0x2aeddc77fe58c98d50bd37f1b90840f96ee5a0b09e7e9a96219dd66f0f74c37efb5bc1ff496d8054008d8404893c7b4b80f397605cc96e61fec3c89676c8c2794a2a7d281d678b1a": "0x00000000000000000000000000000000201560de907974c342ad34bd99ba8b530cbf89b39a10be019f9abfed3649470718a00505eb2a4607f27837f57232f0c456602e39540582685b4f58cde293f1a116bb4e1d9efbe50d88f02dc608509ba4ef589646abb8dde69c9398738becc8cd48d34e07fff5d2c51bf316d91599d98e2e1ecc8bab38f57caa40a4206967dc8ac013ea937fa9da7a04ab5ae026b321323ffbc3f6ffd24898500ef3eaa6b2353613deb536d9d2138242abbfb7d0f1b7b2905d8316566edd28c2d029996a89e51e09b53bdc896b61a0c3facca04307105b99e44841190d41b655c127dce9447ce2d4e848eff972706bdacaf38bc657028f303d44bacde7b359b8595fe7a4268e7418", + "0x2aeddc77fe58c98d50bd37f1b90840f96ee5a0b09e7e9a96219dd66f0f74c37efc6a73dec7fa79b18c8305ff8478e6309325ebbfb81e8c1883d39e65d2ef84f88e4a428615c49277": "0x00000000000000000000000000000000d84248d8caebe59dd27fb0606a3640daab22456c80bf8449bc0f9ca721ad2e2074c6150d4b20644caff90e355c0740cf211f04ec624a65acac57608e7390488f0a2cb40effcc1bd1e91c49205a599b87e3a49dfae2ce9644f3a431e974c721c54fb22f3abb5bafd42556aaae871a79acac48e9b874703cedb7f8f5ce219860ae08dec5377d25559444879fa2dbfc018dc9bc4b574c73e7cc4ff17301e6f0404b0ca6359df267482f0eb4004f12f3189cc44d1e70441ecfcbc1a2d5c6c32066003b7291c36a6b23990b023acb5bddedf227b9688372d4ae99b442b031cadf13f66ee26714e05311dfb5e182d27b7f0e2c399c96ccdd81c25cf47e9c61315274631fd6d65677fb307c3ac6c6c0405a1ecd9a47d0ade13ebd9fd340038fc78d9d883672b86a19da9f10eab2fffdb74143afea62356c6896c265dd18207867f25751109a9868ff02ab61c9603e98eaf9560a864870596f58a7144203636bef6d04e269927f1c23cdd2161cb6bf0da7abb4dd94ce6a98ff07e9fbdedfe96acd3d7dbf5abee52eddafc82ea6226864dcf0583e034f6510d2b390ed60129b6855fc020c06868615ece4f03d149458a8a54f26f7b3992f687e066d7c50e6713f72dcd6285adc19a1fb8d9519f281e155457a5ae5e30ee6cbe81b70db34a18c3bd72c67244b0600cf06f1c8e912c9d968f1de9fe6ed32d033b8e87bfac698602c25604e2b4ea6e5748915493258986746cb3e58f9e76c69bd65bab4fc620dc649c102baf716280774e8e4e6118ffded6250a1b6b1a50285b5a61cf184e19a2bc8e8de8808583ea2629ce3574dc7dda1f20721f7d7a1109dea19ee434885d768c5c9f671271d10002bfd652b0ab50a36adb9bc74163a4385c6b4ad8d3cbef794c07716ee0d6cb04789c005102f21fd271c09568a78047f581710323b5f91b7c2d5743011e1286ec238210f082cca5552aa2ce9a0d1c4be9c7bf44c04f4524ded21f8cbcc611dccc10f47daf388814d58209cad72e4c07dd9131ffb7b2b909d39746577a971784a18d3235c574d9f25aa3371f0190be83bdc423f5b77fc310390e753b229a952644f5b938a2bca8d0b0d5b0f08bfa3faa67acf54f9d45449777022fc23cdbc0fd8c68f5ee90ef5d4f3a2b0d3e827b6b52d6d42c66f0789546e7672128891df61227d3663b23d3565e9f07343f2218b47f60b3221f8bc32692ac60a22c7fb936e021ac11f4e66c8e210deb3f90609d0be4335e8c434912a92fbb1f67d3800452f260707c021782450fc2707ad65e0ffebf1f9e4025b69b8e192378e4835b05f74ba5a53f10121888c3b765d7a0e4ad64209bb08abed45cf9b6f72eafb3af9782a1a7df77359ce352ba50059ec6e2635d7964a50cae9012e4a737f5e82c353aa0d2c13d8c2c4b4445943ffce2d55a39cd4c982e5bd4181d30f712ccfd8347ca45d74e6950dc3144fc86b2f190216b04dd5f75c5ee52d7d3d0a949bb697d48430072c35a5568d679cc0a70e5b714a16a87450270f8ed184d35e961629aa7c364f726e32e6b0a35b369455c50fcaf7153945fd6d92b850a593ea33b5c3b51d7e5a2acc9732afe3d57624b8bdd1afdaca3f940d0010ec54c6eeef52b15ee1da15b06924c295ae61b1b902e08f1b4939f83aefca9d3cf3c6048f1bee7ca71dc5c20a2e58599575b1d7994d5f588624fa628018dc6357f6a90f488a2d880525e582a914565e801907aa5ceae0511572155aaaed09c8ecc03b7dca4790609ffe26bdba0ccab8f3ac8a49d03d47e037a2f63bcb5f38a180115c70db29ee4f379e2e04c3354e346e6bb879c076c4b6290aaeec0a06ebc5cb198245f31343ac1160e16e942b5e4a7f6fd9a8525d277f96f3e758e51fb673c6c28a7203b1a57f6e90c9f81349e81628fe7cf9e8c5e313f1d418b48778051a756de0f652496423cfb3f1be28363c982ec4375d3b3e9c950f540316fe84dc53191424fd073613cf4dea51cd156eb00533dede137ae3424e18ed36871d41e440bdf62952275f43c899e1837e31612482fd4f47789ed517ae4bf2672eba2895d1b6a85e5d963e82cc77c48e57f17614a4ee7a1c85e78b96211b9af1d020030203a9d13c0eac03f4106dbe42d683140ed01c71965026d33ac38506cc0590b2ceceaf2a3cd648e16e0a1d4c105426719c2df8fb28c6749d31d1716854ef3548aff85aafef3175c5e49030715c00fc2506b7a79b3d933c72bb9ae21b97fcb67d5dc1811af6d5d9c412545e6ce7eb9a0362832dca982c4883b26bc9eb5f5af530535e7d216400578738ef04ef0871de73a26c112ec96a277c48e91f46d5385fbdfee248c6ee7c3a66a9f8e640b31922a840d9bfa0963116a9e97d84f9888882bdcb6faa12332997b7f5b83c7c75532216b6d4569e33bc6763785b94b98ec57d07573650e35e682492dd515e0a064d8958", + "0x2aeddc77fe58c98d50bd37f1b90840f96ee5a0b09e7e9a96219dd66f0f74c37efc7f2ed947ce60905842026fdfe358c9320e35012deeedc83c1e19d2b677eba10a1fad0d93c82b66": "0x00000000000000000000000000000000085c0db244fc6960005482b5e6c2896bf2064efd1e5be17e851dc8139f839cf062d237627616a57f2897c778f501c919d17ea969251d6b46cae60ba3f01dc0c72f", + "0x2aeddc77fe58c98d50bd37f1b90840f96ee5a0b09e7e9a96219dd66f0f74c37efdb56e406bbd33003c1db08dfc6786bee3b0e1b4aaf51e80b6f2ec9badbe3da87d30ad7605a2bd16": "0x0000000000000000000000000000000008e34c880765bf4cdda6ab2045979a9039544bbae925cfba4d6421286296cd9bdcbacafb0ea22a692dea279a648b8cb44649ca71629f9fce6d69e03a4869cd9383", + "0x2aeddc77fe58c98d50bd37f1b90840f96ee5a0b09e7e9a96219dd66f0f74c37efdbb17eb6b8c97966c335d86444f3189027cd53244265047e52a96b4621fdaeeb9bc128577898676": "0x000000000000000000000000000000001c38aa672a41872f698aa995f14f0bd9e54cfa4efd97350e742d68a0c44da377d9e1cbdb5c7c39209793cf71d71ccd0a5eec8ee530069837073032da3ec4a5a714ae3aba9a0f0d03d9fab3ad97a367fe66aba07ac0f7fc58d8dc18eed82f8c62f0a6f39c26ca691bd958706b03619b5579a313404e93089bafe5760b2a9db4b5518a989898ac32a8333eea5bebe65671f63fbae7c43756c21f8507be73a53941d1d6ea41749ba9fa1ea5fb094593de0726ce6c1ae997e000b3bbd66ef09298f92d5611f54264f980f8d850f4fd87ab8eb7e6c86b99b396f50d1aed3c5cafcdfd88", + "0x2aeddc77fe58c98d50bd37f1b90840f96ee5a0b09e7e9a96219dd66f0f74c37efe0e61bb6b0e225d68170716ab7c6735dd0a1012045d9ea33891b5f6596cf97eb217d0962d86a518": "0x0000000000000000000000000000000008ccbb21d7b5bf0b08630681c37ebda5b98b5454c8916463a9c2b50262466deb76d44824ac8d1edecca67639ca74d208bd2044a10e67c9677e288080191e3fec13", + "0x2aeddc77fe58c98d50bd37f1b90840f96ee5a0b09e7e9a96219dd66f0f74c37efeb09bd923dd400cca437639da37528d8edc0bb6b31966fdc0263218f4bd60c6f2cc37e963090371": "0x0000000000000000000000000000000004dc64ebe91ae1dd904651525eb5fd91eb0abf458cb0f5986158803e0075604153", + "0x2aeddc77fe58c98d50bd37f1b90840f96ee5a0b09e7e9a96219dd66f0f74c37efec4b60935b1627f3ecdb909643a31da23e3dec041ef8920632ec16fc5157297084eda7515badf68": "0x00000000000000000000000000000000043481012d5c43235dd891fea6f46c4745b4c6f9ae37e756f7da67f6af35831a23", + "0x2aeddc77fe58c98d50bd37f1b90840f96ee5a0b09e7e9a96219dd66f0f74c37eff27f362e41c7ee9487d7703ee644d9a9b59ad29aa7f27405851496306f69678965f1d18d1478740": "0x0000000000000000000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471400216b615048534c12bf9efdc9e4e25b4dd72c560029152b6546ba2fb62eca400d7edee7e5f36b5a": "0x040400000002000000000000000000000000000000000a447265616d62697a7a00000016636172697361676c61647940676d61696c2e636f6d000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714002e08e91d4d456f22f6f9f7bff5f160c25d09f3dda01266aa372084f68e73a49a6f75ffc0aad46a": "0x00000000000000000000000000000000001053756e7368696e654175746f732d5200001f4073756e7368696e656175746f736e6f6465733a6d61747269782e6f72671c73756e7368696e656175746f73696e666f40676d61696c2e636f6d0000114053756e7368696e655f4175746f735f000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714002f96199afbb10962dc0af0a0af60196831c33ef674915a18dcb54ed293ac3733b128d0faa0a66c": "0x00000000000000000000000000000000000a72756274736f7631370000001472756274736f76313740676d61696c2e636f6d000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047140044864097418a79480e2e9b103634bf32ba2c955634796a44cd1c6924e87b2596dc252a28383959": "0x0000000000000000000000000000000000096e616b757279736800000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714004b6e7aeec73523a6d28a83827355f149db71b1ffffafab9ecce641629c6aea5dfbbb9f4917b346": "0x00000000000000000000000000000000000862696e616e636500000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714007dd9a9e7c493d87e8b716984392ac7a4282ae6ac5b35317dd2cf838cd9d388bad322bc11d3ed31": "0x0000000000000000000000000000000000076b7573616d610c72616d7a7920626164657200001672616d7a7973616d69636f40676d61696c2e636f6d000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047140085d1df7366a986ae8f7726520ba56f9153c9e7820015d462a71c6ea0035ce0fef5dfae0a98b228": "0x00000000000000000000000000000000000454656b010101010000094054656b69697575000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047140093ec78bb21bfb2680407d00db6705819710e2f6dad5a89cad6a28b24c184126fd8d05476bd6202": "0x0000000000000000000000000000000000097368796f6f6e373100000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471400ba2794d92fc826e4269547e0e9a8c162de9215bd45921be44dfb58ec95d2f627990d5189001440": "0x0400000000020000000000000000000000000000000010436f696e20636f6c6c6563746f72730000001a636f6c6c6563746f726274636574684070726f746f6e2e6d65000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471400cf4acd8af41f16fcdf10bdd1d597869ff3089a69395c153847bbe208b6b42c71edad958fa7442e": "0x00000000000000000000000000000000000541413248001e68747470733a2f2f7777772e7065746573706967656f6e732e636f6d2f000000000e405065746573506967656f6e73000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471400e0417f161433ac2658c2083dcab9b118b5e828fb81344c4245deb8eed43fa890c8c0ae9cae526d": "0x08000000000201000000020000000000000000000000000000000004576569095765692054616e671968747470733a2f2f746861742e776f726c642f7e7765692f10407765693a746861742e776f726c640f77656940746861742e776f726c64000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471400e44be06404dd23f621dca649d16a5b33c9955e6a09a5cf3a881b4185a1930a02c7fc3245ac3333": "0x040100000001002ca07d51000000000000000000000000000000000000000000000000000000085069636173736f00000018696e666f40636f6d706f7361626c652e66696e616e636500000e40436f6d706f7361626c654669000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714014380e30ffcb2a672d2666b9ecf591f655d98e1800a37d63f454fc915cca7c6412cf55d98f43d67": "0x00000000000000000000000000000000000b476176696e20576f6f640101011c467265656b7962696c6c696f6e6169726540676d61696c2e636f6d000001000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047140148d7da0c4eece04cef024c8124fea94800b3d508aad0c474045b69144cfb3c24012bb915fedc10": "0x00000000000000000000000000000000000000000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047140167335afc9508e06aa2d675d46b5eeb0d922f4188b525daacb0091f6f31ce7d9409d45614eda803": "0x0404000000020000000000000000000000000000000020f09fa6854561676c65f09fa685207c2044757463682056616c696461746f72001868747470733a2f2f6561676c652d6e6f64652e636f6d2f0017636f6e74616374406561676c652d6e6f64652e636f6d000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714018d717cb9219f862cb783d5c0ddcccd2608c83d43ee6fc19320408c24764c2f8ac164b27beaee37": "0x04000000000200000000000000000000000000000000056b6174611041647269616e20436174616e67697500124061647269616e3a7061726974792e696f1a61647269616e2e636174616e67697540676d61696c2e636f6d000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714019d8773aba33ec5c48cbd210165097e4955ba0b35553db067e959752d454331835be646b470d15b": "0x000000000000000000000000000000000004426f4100000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471401b8e16c4ef5704b081bfb25dd99aed0b3d899820c722788535f82eb14cac2ed0adc9daa5a4fd72f": "0x00000000000000000000000000000000000678524d524b000000000000074078524d524b000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471401bcc09d733aeb61505e685f12b11fff499400211f38ea5a8cd9f1e72e9883b58fddcb66c563e84c": "0x0000000000000000000000000000000000055775766e00000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471401c62b08e0f1d3292eb9ad501926b86b6c074a5a48bc16503dfc910b13e1ce2a8bc4440cca43ab2f": "0x00000000000000000000000000000000000e4365646f75782057616c6c65740e4f5549534c5920434544524943000013632e6f7569736c7940676d61696c2e636f6d000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471401d4c9b3a23a716c824388cb8ad264b43a93320076e3f6690d707c3d1d53dd022a645c0127a78267": "0x0000000000000000000000000000000000095865726f6e696d6f0c4a65726f6d652048657272157777772e6a65726f6d65686572722e7370616365001867616e77656176696e6740666173746d61696c2e636f6d00000c4047616e57656176696e67000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471401dba54cb1c92c2856aa4370ee3d21b98ec19f0cbf2106a036215937a15bbe517b24ae5fef4d3870": "0x040400000002000000000000000000000000000000000a4441524b4c4947485400000016616c657373696f646f633740676d61696c2e636f6d000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471401e3012609b6e0fe77b377299bb54afbbab70894a10e4ba1370f6a60914c8ed37f9b2484da37a335": "0x00000000000000000000000000000000000a4e4654204775696c6400000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471401e66931ebe7cc802a82fb6c3dd0269f6977b022fc3abfa2f1ed9783de2d7f26672b7eebf4fa783e": "0x0000000000000000000000000000000000057072657300000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047140205d71cb9b4787812eeb34296344896ba0be07383211f262b76cffae3d00aa91d0c3d10e7abd37b": "0x00000000000000000000000000000000000769676f72656b0000001569676f7279616e62756c40676d61696c2e636f6d000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047140214f0b5b1672e56729f8acbb64cb60b5edb62beadc9ac05430ede0086e29800ee32d106befc7825": "0x0400000000020000000000000000000000000000000008416c436861696e0000001a6b65697468616c616d6272756b6f7340676d61696c2e636f6d000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714022078fbf54f7d762fa1b6d109d1876820d529c1a53f5e59ca5a05f01d8833439428e811aada3923": "0x000000000000000000000000000000000000000000000000114053717561644c65616465724d61726b000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047140223d09f1c0c1ef00ce0bbe155c5f116187af43bae0bd493872f436a139e23d9b26289d0721a310e": "0x04010000000200000000000000000000000000000000094c6974656e74727900000012696e666f406c6974656e7472792e636f6d000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047140224acf1d46b915ca048e9318fe2e6a8b6f9174800c44caad3e44d22f92453d1de685afb39089e2d": "0x00000000000000000000000000000000000b54484520425552524f570b54484520425552524f5700000000000e404348414f535241424249545f000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047140224be9facd8c216c2ce97485afd4c6f5cc11da558f0b28b62a277fdb50d7bd0cf3d88dfed968217": "0x0000000000000000000000000000000000076175726f72610000000000000d40417065734e4175726f7261000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471402273ab7613e5661d033ca16a330cf722e09b908a545818f8e2880a221d16d902923ada564b4b646": "0x040000000002000000000000000000000000000000000c416c4d6974726f7669636800000012616d40756e697175652e6e6574776f726b000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714022895ddfaa9819ec423a2dd622f907c00dbf99e423c4e3c9e937684b6ac14fa49180637c6eed61b": "0x0000000000000000000000000000000000023d000000000000034071000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047140233abfcd4caebc1fc8f0be99f1dc3c1bc20b122eb888761ffa281abc9783f910df8b57ffcf8b572": "0x0000000000000000000000000000000000095052494e434550530000000000000e405072696e63657073526d726b000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471402492b2d8deb67a91862b74508884386ca63e94959b33773bf0f1ba6e3aaba793e8975760ba19a21": "0x00000000000000000000000000000000000948454e43484d454e0000000000000d4068656e63686d656e5f3531000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714025081289a767e3f04b72fd6c91c2799dd0f0c74accd0e5d6dce0f665b5a175ba3fd80a122416078": "0x000000000000000000000000000000000009616c7068616261650000000000000d40616c706861626165313030000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714026bed6843025f8466357ad0e7451c02f6d53fa777f394c31cc2680c4a7cf448c48a91d78ecbc565": "0x00000000000000000000000000000000001150616e74686572732043756c7475726500000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714026cd546f7bcbf83ecfa264fd1da282eeb7b06b8c7fd5634e9f5da8eb1163c79b789d943c310ed25": "0x040400000002000000000000000000000000000000000c53555045524455504f4e54001968747470733a2f2f74686f6d6173722d666f746f2e636f6d001774686f6d617340626966726f73742e66696e616e63650000104054686f6d6173525f537570447570000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714027f0a2e5771d1390ea95a5a9a64e338318cc9e38b07fb0dcf75e164f4b968d3b206296c2663e059": "0x00000000000000000000000000000000000000000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471402a74f185bfd81d73ae9f951aef3bab402292d205c9ea5f850e5b80b563a9b5837ac40ad97c22469": "0x00000000000000000000000000000000000000000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471402af845724d240cefea7e94482e6aae6ba684414c251845b33b1dbd8cfdc035959f4ff948089dc17": "0x0401000000060000000000000000000000000000000007636865657365156b6f6e7374616e74696e6f7320446176617269730000126279726f6e7333407961686f6f2e636f6d000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471402bc718576057bd5c0914fdaf5815ff54b30fe11a656cf17539b090c36d5f5650260b12a7b94a945": "0x00000000000000000000000000000000000f62696e616e63655f6b736d5f33390f62696e616e63655f6b736d5f3339000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714030bf2a06d3af7df887b2f85c74b58160bb1659de7f63e0dffb480a46f99afc1d1e4002a44aafa1a": "0x00000000000000000000000000000000000d4d6172696f506172736f726100000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714031326492a87a9c14631954522a90e4361e6b9bb3876cf6213bac251f99d456ed4703b47f289b95e": "0x0400000000020000000000000000000000000000000008446f746361737400000019646f7473616d61706f646361737440676d61696c2e636f6d00000a40646f74636173745f000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047140318c1db47739db4d030ca0b2a60a30e7d1a0fec231f6f36c3b608036d25ff6b2b9ab9576d59c252": "0x040000000002000000000000000000000000000000000c5374616b652d517565656e00001840717565656e706572736f743a6d61747269782e6f726716717565656e706572736f74407961686f6f2e636f6d000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471403195376b973a33e30b25a315eb8ea1ff57e39183ddb0a922cd08e2443e6fdf4cf28bbe34b103800": "0x000000000000000000000000000000000009736d6a756e696f720753616d65657201011473616d62757433363940676d61696c2e636f6d00000e404d61736b617261436869636f000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047140323373f05a102e67e99b3bfa6f2df6433c885bb45dcdcaa0cb01dd07079d5e9b1f687714322672c": "0x00000000000000000000000000000000000c7374727967756e656e6b6f074d616b73796d000000000009404861636b733732000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047140328eb74cc6d2a41402cc6cb8ec16b5648fbc7be76657e17291d855b4d2dfc98511586789bf6c01f": "0x04000000000200000000000000000000000000000000174b696e656d6174696b73204c61627320e29a97efb88f000000136b736d406b696e656d6174696b732e636f6d000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047140351153466a702772a326eec0bd3f6db6e6a17ecc5ba726460ff351045fe63ccde53c971944aa84a": "0x0000000000000000000000000000000000056d75736801010101000001000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714035c8158e47e1177ceb5a9283e6ff1b5ae17a18181220657597cb476fbc726e2ca302d1e7a9f6d2c": "0x0000000000000000000000000000000000124b7250726f642053747265657420417274000000156b617274656c726f636540676d61696c2e636f6d00000c404b617274656c526f6365000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714037dbcdc8f46729a2cba024614ea8ccd1ebf7a634f30b38d65c082be6aaa92551b9c3b4d1f15ae6e": "0x040000000002000000000000000000000000000000000b5370696379205461636f0000001a73706963797461636f70657070657240676d61696c2e636f6d0000114053706963795461636f506570706572000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047140398dfc6cfa0cad07e7699082933c3da2328188e77d3ed6f0d6044e5b0e1a3cef907339b823fca62": "0x0800000000020400000002000000000000000000000000000000000e4d697463682d576172696e657200001a406d697463682d776172696e65723a6d61747269782e6f72671d646f742e6d696e6572732e736369656e636540676d61696c2e636f6d000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714039ea54cb812a324847194325a12bc4f4faacb6aef973eda31658195c26b934318b960aa69050819": "0x00000000000000000000000000000000000a73796e636c75622d330a53796e636c75622d33000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471403ac99c30a0f9cefc87323333f6c7ed668bddfc05f00d058646f87df33589d4b3f3b2d159ce3e831": "0x0000000000000000000000000000000000074169204172740943727970746f204a00001561692e6e66742e61727440676d61696c2e636f6d00000c4043727970746f5f4a5f44000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471403ba33ceedadcce5605ab29b9b1110fc5aecc4d1604862282fd58887d45e7b47a875901780a3103d": "0x00000000000000000000000000000000000f53686964656e204e6574776f726b135374616b6520546563686e6f6c6f676965731e68747470733a2f2f73686964656e2e61737461722e6e6574776f726b2f00156465766f70734061737461722e6e6574776f726b00000f4053686964656e4e6574776f726b000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471403bdc0558aef9e267eba793f6c8b72db5ccbba0972846a41dec11d3e62da13d9c09a868863f50848": "0x04020000000200000000000000000000000000000000085765623320564315576562332056656e74757265204361706974616c1068747470733a2f2f776562332e76631440776562332e76633a6d61747269782e6f72670b686940776562332e766300000d4056656e7475726557656233000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471403bfd6fd4ef57fa5a0ad3e520332a754892d7a16de9de871b9f20e982d62a498b5d9c7e5f93d433e": "0x040000000002000000000000000000000000000000000653696f33340000124073696f33343a6d61747269782e6f72670f696e666f4073696f33342e6f72670000084053696f333437000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471403ce064f38ae56473816e99372dd086042bb6bbe15f082d70849a371070675e3819980b50fbbfa6a": "0x00000000000000000000000000000000000f614861796c65796672616374616c074861796c6579187777772e63686173696e676672616374616c732e617274001b4861796c6579617274776f726b73406f75746c6f6f6b2e636f6d00001040616861796c65796672616374616c000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471403daf1ed6a71ceeb484a68f3a30ab11bfdedb06f43f5bb9aae28c3caf66a67fe408efee66e7df46d": "0x00000000000000000000000000000000001d446973634c6f736572202850656e736976652052686f6d626f696429002168747470733a2f2f6170702e737562736f6369616c2e6e6574776f726b2f3633000000000d40696c6c756d616e61743333000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471403e65d4ca28086078c2625b0e10c7bf65f283c576878cf00f67478d3dbb6bf39ee62b3ca19ce893d": "0x04000000000200000000000000000000000000000000117061756c6f5f5f7a61676f20f0938582002068747470733a2f2f796f75747562652e636f6d2f5061756c6f5a61676f595417407061756c6f5f7a61676f3a6d61747269782e6f72671c7061756c6f6372657374616e697a61676f40676d61696c2e636f6d00000d407061756c6f5f5f7a61676f000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471403e9f523ac424d6258c88b6777d3a1d2f2dd03cfd6f3bc37634380b273fa9e3fe2cf0927a39a0411": "0x0000000000000000000000000000000000074b6f6f6b694300000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471403fc9979d20d8f4376e282d7a7eef593fe7a9a8c5d08a21f134e8858e1b1753bf347057c4db9b234": "0x00000000000000000000000000000000000b4441524b464f5245535400000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471403fed7fe7c184ba490bd3d091b8837f2f41c38b6e3bebd28a31ee280f82d15e687f95d798ef41c17": "0x0400000000020000000000000000000000000000000008457a696f52656400000015657a696f2e726f6a617340676d61696c2e636f6d00000940457a696f526564000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714042590a80582f1a138a93e60974816d78c774a853979d3327de0e119fe2606d11d8de3d13bbd0d17": "0x00000000000000000000000000000000000000000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714044f0e81770d2fe4d42eb2efe47dd6c0d5587693d706b6ff988e1fb289c21afb1099c3eede2ea543": "0x00000000000000000000000000000000000e484f5420434150554343494e4f0000000000000d40484f544b50554343494e4f000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047140454cd0bd8fd07803ec587860fea3a47649fef7bdd6be7786fbcbffed789f454b52613b22358850f": "0x00000000000000000000000000000000000e42617261636b204b7573616d6100000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714045dc4c6b832bb9cba718c7f73c24fc4bb006f6aee231c6764560a69f5a8c2d6bcebeaf59b886836": "0x04000000000200000000000000000000000000000000097468656775696c64000000197468656775696c64736f7572636540676d61696c2e636f6d000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714046409e5f145bc2af4f95e82d3eeecfde0058a399005262a9709101ddf3f2a564ab34040678ece15": "0x040000000002000000000000000000000000000000000b574542332d535041434500001740776562332d73706163653a6d61747269782e6f726714696e666f40776562332d73706163652e636f6d00000e40776562337370616365636f6d000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714047021104d1ffe0a329c95d5190b434b204b6ed49f23129aeea1cb38f70aefa1af621b4c01d48311": "0x000000000000000000000000000000000010427269736b426c61636b4d616d6261000e636861696e677572752e61707000127061787375726640676d61696c2e636f6d000011406c6f6e67626f61726466616d617261000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471404bafd1de148721f84bebc905613c15b1464d94e00068be0a67edfb4b274b180fa00573e4a41656e": "0x00000000000000000000000000000000000478666c0878466c5f446d700000000000094078466c5f446d70000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471404c7c5013bc5e632ecfe133cb8a7eb6248a79ec2838c5982a3996db0c69c8427dc1e4ca3fdb0732a": "0x000000000000000000000000000000000014f09f90b2204b7573616d6120447261676f6e73002068747470733a2f2f6c696e6b74722e65652f4b7573616d61647261676f6e7300186b7573616d61647261676f6e7340676d61696c2e636f6d00000f404b7573616d61447261676f6e73000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471404cc90b988a75711683e24f78a248b20b2c8805cae1d228c1140da7d15f2d92c91dee43da6df3642": "0x040100000002000000000000000000000000000000000e54656c6f436861696e5f4144561e4d617263656c6f2050c3a972657a20646520417263652047c3b36d657a1768747470733a2f2f6269742e6c792f334d6863375573001d6d617263656c6f40636164656e61626c6f636b636861696e2e636f6d000011404d617263656c6f506572657a446532000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714050595b2a27bff0328bc337a98b458dece2c080a545fe7eb38ab06f7a26b9dc576357443285b4c79": "0x00000000000000000000000000000000000a326e64736861646f770f457667656e792042616275726f760c73756273717569642e696f0014652e62616275726f7640676d61696c2e636f6d00000f40657667656e7962616275726f76000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047140505df941b88d8a60a725e79b9b6933c684a19923c69eb95ed2bf60a37f418e276a4ecd9d80d8961": "0x00000000000000000000000000000000000a50796d2050726f6f6e0000000d6c656d40726d726b2e61707000000d40416c706841697264726f70000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714050b93a25349a94f32694dc2fe7ff7637b26f93f51636ce8beaf128eb4bcab5297d13dbe555d2830": "0x000000000000000000000000000000000008414c207c2053490101010100000a40616c617a616b7279000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714051fe135342851ed0ef762dfeb3c0cc556212597df740eb320ad5b10e526a93e1aa32df8dc3d8c44": "0x00000000000000000000000000000000000f43727970746f42726f436c61726b000000000000104043727970746f42726f436c61726b000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047140524d45908638528248a8784f67eaab3daede6b3367277040f38ad93339171253c1698daccfb4f6d": "0x00000000000000000000000000000000000b4e4f42554c4c534849540b4e4f42554c4c53484954000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714053f986ef1b208a2629a4497433e01dc77b48378a2c9f90059f5a6386c4d0042fe1c9751cd29bf21": "0x00000000000000000000000000000000000847696e6f4172740547696e6f1d7777772e696e7374616772616d2e636f6d2f67696e6f6172745f372f001467696e6f617274303740676d61696c2e636f6d00000b4047696e6f6172745f37000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471405536af493f9e4a9c29f38d97fc79f3c60343d96cf6cd3e334fdf03987c50a7fd788ffed2a5ec928": "0x00000000000000000000000000000000000a43727970746f4a616e10616c656a616e64726f20757269612000001f75726961616c766172657a616c656a616e64726f40676d61696c2e636f6d00001140416c656a616e643437383530323535000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047140556a86b11fa77913c7f40746d04d77628d886dfd469c9bf606232dedaa248f5c219d32da93f4054": "0x0405000000020000000000000000000000000000000014f09f8fb5efb88f20464c4f5745525354414b450c466c6f7765725374616b6500001b666c6f7765727374616b654070726f746f6e6d61696c2e636f6d00000f404265466c6f7765725374616b65000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047140557741ad8ff629b30ada415c8cc022b6ae05febe4df84af44b09b542490887b11ab3df04714bf2c": "0x00000000000000000000000000000000000864697374616e6b01010101000001000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714055ca836acf0447774422321a842adfae9419ecd3983c4fa2da6e879ccc1db031e54c742bbb9bc03": "0x0800000000020400000002000000000000000000000000000000000b56414c49444154484f520000001576616c69646174686f7240676d61696c2e636f6d000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471405600578c1e1169728b2f7bef7da67014627c1f7e36683afc5a9b1a9e071570065dbee9eac414b03": "0x00000000000000000000000000000000000a6b7573747261646572000000146b757374726164657240676d61696c2e636f6d000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047140573bb60d22fa77e98bdd9395e86f4d48a442f70fe2513fd3fe0cdc7e95105ced193ba2666c8fb41": "0x04040000000100902f50090000000000000000000000000000000000000000000000000000001c536f7665726569676e204e617475726520496e6974696174697665001c68747470733a2f2f736f7665726569676e6e61747572652e636f6d00197061756c40736f7665726569676e6e61747572652e636f6d00001140736f7665726569676e6e6174757265000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714057502993decae27be3d23293857895d14cd4b30e1823365792d89c77776b238e4d883e8d2261338": "0x00000000000000000000000000000000000000000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047140587e6d391ccaa424c44f3e63cd28ea42371fea311f977e701ca31749ec7d0262461bc41591d3607": "0x00000000000000000000000000000000000e44565f4d6f6f6e686f6c6465720444616e00000000000a4064616e6d636b3138000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714059bc9cf5ceb19d4b2801b3240cd70a56baa1aab6d2b26252bc804c254f8e2942d365e3207b46a6a": "0x040400000002000000000000000000000000000000000748554e5445520e48756e746572204569736c657200194068756e7465726569736c65723a6d61747269782e6f7267156b736d4068756e7465726569736c65722e636f6d00000f4068756e7465725f6569736c6572000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471405a60c9d4c41f598de9d02d7d5447ea749e3c33f38033ecbdec8f4ad6abb3f0a17d6023db1988b1a": "0x0000000000000000000000000000000000064a6f65205100000000000009404a6f6571753135000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471405b079eb94353bd94adf51a47b72795366d52285e329229c836ea7bbfe139dbe8fa0700c4f86fc56": "0x040000000002000000000000000000000000000000000e536861776e2054616272697a690e536861776e2054616272697a6911736861776e74616272697a692e636f6d1f40736861776e74616272697a693a6d61747269782e7061726974792e696f17736861776e74616272697a6940676d61696c2e636f6d00000e40736861776e74616272697a69000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471405b5d46c57dc301d8c99cd908a45bb7973537ce461ff349904f6b3176ca9f594a2e83d720e09cf72": "0x000000000000000000000000000000000002520252000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471405d31d1ec885004a5a6e6d7f1f5af2300c1b721cde7f08238ffef321bcb45cce819b00557fdedb00": "0x080000000002040000000100902f50090000000000000000000000000000000000000000000000000000000f507265737362757267204c616273001a68747470733a2f2f7072657373627572676c6162732e636f6d1a407072657373627572676c6162733a6d61747269782e6f72671d7072657373627572676c6162734070726f746f6e6d61696c2e636f6d00000f405072657373627572674c616273000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471405e3f970c23ff63cb85d101c656fa86dc284f34f7583b5f178d9e9b619df6031fe2c04b4c5f07e26": "0x040000000002000000000000000000000000000000000c414e47454c20535441534800001640646c697365656e6b6f3a6d61747269782e6f726714646c697365656e6b6f40676d61696c2e636f6d00000b4044796d797472696934000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471405e501157aa27fcd22240cd28aac3cb675651ddee8045f1fdd5d532c2b149e3e68b0b8f606b6e075": "0x00000000000000000000000000000000000000000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471405e51ec513573d8d8eb71ee062ea6e33ef20d8ece22607a4ddce26104535141b562a84f31124256d": "0x040000000002000000000000000000000000000000000c4d41582d524557415244530000001364757a6972796e6140676d61696c2e636f6d00000f406972796e613235313432303332000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471405eb675fee1282900e6bd67d5dfccc6180a5ad07870653d1a8a57ab09efcff251a49c234b649f423": "0x00000000000000000000000000000000000641694172740000001861692e6172742e3432302e363940676d61696c2e636f6d00000e4041495f4172745f3639343230000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471405f8e083dda4d67b66e0b6ed9ffcce16a6e8a77fad73f6029f289139229a359380384929ba8d093a": "0x00000000000000000000000000000000000a524554524f57415645104461767964204b686f726973686b6f00001a64617669642e6b686f726973686b6f40676d61696c2e636f6d00000a40646176615f6b3230000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714061c4dd514901839c0cca7d600db0542f7d46a623c53383cb24ee7ef9122c5b42a5f63551c054438": "0x00000000000000000000000000000000000000000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047140635da251fe445574e449bcf3a54b723c9897abf182e125d472242d1ef0676052fbacfb900b9a044": "0x0000000000000000000000000000000000165370756e6b42697420537570657220536861726573000000000000104074686567616c6c65727931313131000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714063f98a01f914d5d7634ddf79f2e749774d401cf31cc4565da1627f6857e2bb5c29a219121512068": "0x0000000000000000000000000000000000066368696c6506456c656e610000146c656e6172696f343740676d61696c2e636f6d00000c406368696c6c655f617274000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471406464a684f7b7a0d1c6681030fd4860fcfc1dfad9ae55fc0181229b007b6365dc4c8f5fbe162554c": "0x040000000002000000000000000000000000000000000d45786f746963205374616b65001968747470733a2f2f65786f7469637374616b652e636f6d2f184065786f7469637374616b653a6d61747269782e6f726718636f6e746163744065786f7469637374616b652e636f6d00000d4045786f7469635374616b65000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047140655181280220c8b6280b912d54001e1ac0bbc1023ba9a16974a6c23d22e817e97d418ea94d29642": "0x040000000002000000000000000000000000000000000946726f67f09f90b8001968747470733a2f2f66726f677374616b696e672e636f6d2f184066726f677374616b696e673a6d61747269782e6f726715696e666f4066726f677374616b696e672e636f6d00000d4046726f675374616b696e67000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471406885e6b6b0cc106068c252ec614ba3bc04e729d590bf21ce3b82ebd4285b8319fc56536027d1460": "0x040000000002000000000000000000000000000000000d3036312e6f6666696369616c000000173036312e6f6666696369616c40676d61696c2e636f6d00000d403036314f6666696369616c000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714068a83f6750959f2b4af44560bd1a1aedded0deca4f3a57548b4b70d63f69c7fd16b41f6599b7f75": "0x040000000002000000000000000000000000000000000f54656e7462616b657273f09f8db0001768747470733a2f2f74656e7462616b6572732e636f6d0017636f6e746163744074656e7462616b6572732e636f6d000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471406962b7186669a025e5f430170298c557cedc08e8f2b688e59bc2a7e081a6467eb7a0b7b5ba4c90e": "0x000000000000000000000000000000000004766c6405566c6164010101000001000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471406982ce1b07dde21ce8ce1358c0f5ab2618e38a9c853948c51bcf3ad550f7d65af1cd03f959f2843": "0x00000000000000000000000000000000000b6a68656c657a6e6f6666114d616b73696d205a68656c657a6e6f760000176d2e6a68656c657a6e6f666640676d61696c2e636f6d00000c406a68656c657a6e6f6666000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714069b111e5a0fe7089a8260623bc5831d8c2b343584a77007782cf231f8063e2caa2abb4ff686c466": "0x0000000000000000000000000000000000195361696e742773204469676974616c2056656e747572657309437361696e743032000014637361696e746e303240676d61696c2e636f6d00000a40637361696e743032000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471406a51bab8ef99a0b50d987e17e9e6d29755219eaaf922c92870657adbba3a3d0208e30b0e9651c38": "0x00000000000000000000000000000000000f412047686f756c20456469746f720000001c6167686f756c656469746f724070726f746f6e6d61696c2e636f6d000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471406ae29fcb31f2504fcea4f4585d2d271139edb4c75a70445cf84063d0b7a05955af4620daf56e238": "0x04010000000200000000000000000000000000000000075855414e5f32000013407875616e39333a6d61747269782e6f72671b79616e676a696e677875616e6d61696c40676d61696c2e636f6d000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471406bc1957793c67e8d2f05ac62ec209254a2796a6e45f599195b90fb78de0c915e2b49d557332d56f": "0x00000000000000000000000000000000000d4e696b73696b66696b73696b124e696b6974612047656c79756e656e6b6f217777772e696e7374616772616d2e636f6d2f73696d62616c696f6e735f6e6674001667656c79756e656e6b6f6140676d61696c2e636f6d00000c4067656c79756e656e6b6f000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471406fef9da176fe6b5504f8379d55a37d9b91937eea092e2d74d85bd1894cab557bd791b92f47dd566": "0x00000000000000000000000000000000000e4c554343494f5f4b5553414d4100000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047140703fa0ba498f4c1d6aa353e69dd58d0298d9d5cc2000b0b279f90e3d6a8e80de5932e3f1e300b06": "0x040000000002000000000000000000000000000000000c456c204c65c3b161646f72000000166d6676617267617339363640676d61696c2e636f6d00000c40656c6c656e61646f725f000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714071aba1c4fbe2c7afea2b3bd4635b227539d7b4894ea4b09eccc01acd424d4e811b2dbff5670f726": "0x00000000000000000000000000000000000000000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471407215386cd0fce6716c95a9cdec3df8ff80ca21d4c9f8fec3f4c7c9fb940e0ac2d1f8bf486acd35c": "0x0401000000020000000000000000000000000000000008677265656b647810496f616e6e697320536f75726469731e2068747470733a2f2f7777772e616d706c696679676c6f62616c2e696f0119696f616e6e697340616d706c696679676c6f62616c2e696f00000940677265656b6478000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047140737c7a9c60b7040b26699df67dfb10499cad602d1eb7680109097abc955427dac056d4ff0915757": "0x00000000000000000000000000000000000101010101000001000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047140760d903221d52a2d6260d36b4f57d17c0d1214f67f51ad72b44ca6a5b28b267a057df44a4ffc75b": "0x00000000000000000000000000000000000a7468655f766f6964790000000000000b407468655f766f696479000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471407628049f99bf7d7a46c0a25bedc15be8fc45d5d9bf710247c4cd6b7478ac3d71f71e67937522e15": "0x0401000000020000000000000000000000000000000009417661204c6f636b001468747470733a2f2f6176616c6f636b2e636f6d00146176616c6f636b406176616c6f636b2e636f6d00000d40617661756e6c6f636b6564000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714076a68a64b11f79daeeaeddfdd71854dd03402c966ccc5daa5c3afa196f2591dfc22ccf263f77503": "0x00000000000000000000000000000000001154686520496e7641726368204d696e74001968747470733a2f2f696e76617263682e6e6574776f726b2f000000001040496e76417263684e6574776f726b000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471407715dc9ad8895a8e898988dda904df740a306d0c786ed5668d1344720b102be91a3956bd480f35b": "0x00000000000000000000000000000000000a4368696e674c696e6b0101010100000b406368696e676c696e6b000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047140798b555f15705031ed39a4aa544b98ebd1243abe6264730ea0921edd5e279e2c7c5f136bfda7e4d": "0x0000000000000000000000000000000000096c65696265727479000000167261792e6368693731373140676d61696c2e636f6d000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471407ad6e0f21f25f78887ddc26a5efdc1bbd8bdf8e1051dc07279de6abf830bad4998e44d848812458": "0x00000000000000000000000000000000000b4b7573616d612043585500000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471407adcfcd16f835d4b2bac0ce6ae2d74d54b020ec4f2ced833d9d9367ce9b44fd03c47b2955449e03": "0x0000000000000000000000000000000000076d61747379730f416e64726577204b75646c657373127777772e6d61747379732e64657369676e0015616e64726577406d61747379732e64657369676e00000e406d617473797364657369676e000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471407c7d38f8167b3b8ea868dc748fec06ebc5409c01d3a3445b49ff65f9df353a5f6a45582eb001522": "0x000000000000000000000000000000000006646574306e0000000000000e40416c656b7365693032303231000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471407e3699c0690de378835373096d1ba3d43eab5289f28507faf3f5b7c7905cc2cace9903bea43154d": "0x040100000002000000000000000000000000000000000e5354414b494e4744585f434f4d0e5354414b494e4744585f434f4d1668747470733a2f2f7374616b696e6764782e636f6d16407374616b696e6764783a6d61747269782e6f726713696e666f407374616b696e6764782e636f6d00000b405374616b696e674478000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047140823dc59ec2f7a204eed7cf3f4f6560d58db4eb78bd24b655bbd1d7a5c6b454e77c8dc5e2721a54d": "0x04000000000200000000000000000000000000000000164d4f4f4e204c414d424f5320f09f8c9520f09f8f8e001768747470733a2f2f6d6f6f6e6c616d626f732e6f726717406d6f6f6e6c616d626f733a6d61747269782e6f72671976616c696461746f72406d6f6f6e6c616d626f732e6f726700000f404d6f6f6e4c616d626f734f7267000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047140832e37ad433bf330093c7603ddb81760e5c90ba6c0fde51812e18e6cc14121c081f5a573a868142": "0x00000000000000000000000000000000000b4441524b464f5245535400000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047140842535831df92d1f47c8e560ea22d951dc1d11f507e03cf84d24b763ac809f65b0cc96a38f0152f": "0x0000000000000000000000000000000000066f7a7a7a6100000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714084526527aebc960f46d9672ffd7ed18f87db293545cf8443b938604cdc750370efa50af4d74e603": "0x0000000000000000000000000000000000074a2d54686f72124a6f6e617468616e2054686f726573656e01011c4a6f6e617468616e6a74686f726573656e40676d61696c2e636f6d000001000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714085391a2cae90f2cb0ad422a668631d7e1deca3ff382cdba5899815abaa63f1d3a5c41ea5be4b930": "0x0000000000000000000000000000000000075a414942554e00000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047140857cb9df490db87c8e9e95dcbc6b16730ff59ea5883c581d9a8468c6c9a8491282d765dc79e8b07": "0x00000000000000000000000000000000000f527873747564656e746c6f616e730000000000001040727873747564656e746c6f616e73000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714085aa13b537671b97ced45565a0da076fdffafc5b516479c72f4ad5c4a932ca1656b029bb79f8b61": "0x0000000000000000000000000000000000204d697373696f6e20436f6e74726f6c207c20436f6d6d756e6974794e46203100000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714085fdbb7e912dd07e2447f4fc17d2e0346ff5033dcfb1125d965384a3f2dc1ef86ced9346f8bb942": "0x00000000000000000000000000000000000f53757065726865726f2048656164000000000000104053747564696f536b657463686572000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047140867cd2096d96b96ea6a0804e0024beaa87fc072eb250446162310017e52147d18fada54a8ddb57b": "0x0000000000000000000000000000000000094e6f6465706c7573094e6f6465706c75731468747470733a2f2f6e6f6465706c75732e696f001268656c6c6f406e6f6465706c75732e696f00000e404e6f6465706c75735465616d000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714089158aaccdbbbcd36061b78bcd9eac1f33933dae70291680fa0718170cf24431cced2274e8e2916": "0x00000000000000000000000000000000000101010101000001000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714089745272fb1fb5054bbd380dcf112ebfe5500ce634b45349943063e90651ab0ccd0eaa53baaa27b": "0x0000000000000000000000000000000000164576726c6f6f74204f6666696369616c204d696e74001868747470733a2f2f7777772e6576726c6f6f742e636f6d00116c757575406576726c6f6f742e636f6d000009404556524c303054000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471408a50dd1623e5808bc8299cd873cbc489fb2b4f86c0220fb82bcbe6f87c419d4f82e258fbb11f11a": "0x00000000000000000000000000000000000f4b5553414d41204b494c4c414820000000186c6567696f6e2e6d616e79313140676d61696c2e636f6d0000084037333631304e000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471408afdf9f47614de486c987ce4f2f3af1bbe573bc5062e0d9369142d2f941758af4f5069e93ddaf42": "0x000000000000000000000000000000000008656c6d6965646f115061626c6f2056616c646f76696e6f731e687474703a2f2f696e7374616772616d2e636f6d2f656c6d6965646f310017656c6d6965646f776f726b7340676d61696c2e636f6d00001040656c6d6965646f6f66696369616c000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471408b12c769aece86816433ddf1a483df91e588d4f5c677d25e99ee2144a6dc2e8bf38df8ce0970156": "0x0000000000000000000000000000000000054c6f707000000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471408b34e7e2acff7a2e2fd73bf97986a65ab0771df0eb3bc9fce592a2579562834f3e58ab28c760422": "0x0000000000000000000000000000000000084d696368616c5a0f4d696368616c205a61647562616e0000137a61647562616e6d40676d61696c2e636f6d00000f404d696368616c5a61647562616e000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471408cc79e8d56c8beb7c88cb63517049b0569ba773b2cd7be3dea4c7c88340ba5f31c7bfa2e847f65f": "0x040000000002000000000000000000000000000000000b57617465726d656c6f6e00001b4077617465726d656c6f6e6e6f64653a6d61747269782e6f72671a77617465726d656c6f6e2e6e6f646540676d61696c2e636f6d0000104057617465726d656c6f6e4e6f6465000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471408d021ac78f6fc34ee1605fe949a127bc198df93f5fc6e420168e5656d28770d0e9e9402ac842c51": "0x000000000000000000000000000000000010486f706566756c204f66204e46547314486f706520446f726f746879204d75727068790000177468657275676761626c657340676d61696c2e636f6d000011406b6576696e6d753736333333363831000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471408fadc8547f2d84d901564894dc37fb1719defd3063b29e6496544b7362fddece74fe06c88baad18": "0x0000000000000000000000000000000000134d6f726f6363616e20747261646974696f6e01010101000001000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047140911084e9a4894bcac99f396388330ea1200432287395014e1bfb65195705130193212c656481e2e": "0x000000000000000000000000000000000008746173685f327300000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714092d9c51c43937f55ecd23f062fc8fb0405c798c00b5759f52bdda38ebf10bbc464c757686125236": "0x00000000000000000000000000000000000000000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047140932ed16a6ce31dbd08450b51426556a9e61b8e928b97c6075d95cda58b433fdfca36a2b69d9766b": "0x00000000000000000000000000000000000d43687269732043727970746f1243687269737469616e204361726d6f6e611d68747470733a2f2f63687269737469616e6361726d6f6e612e636f6d000000000d404348524953435259505430000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714093c88d361b492968e76c9299f5a2046beaa5266ac0ef8b7b310c929704f15d8e6657b371302202d": "0x00000000000000000000000000000000000b4441524b464f5245535400000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714094ca67c6fbadcea0ca2923ab15eaad6a04c929078d754253249227ad18927018f0a2c3be0fa5621": "0x00000000000000000000000000000000000101010101000001000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471409621844aea6b395108a708f579783ecb399a6e3f7a67b997440e4925737e9bcecbc49558d505d5b": "0x000000000000000000000000000000000005646f7431000000186661726d323032324070726f746f6e6d61696c2e636f6d00000840305f6f705f71000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714096c13bcbcb0791226104ba050f385c19450c62d2adb3e9deabed8783eee0059d582ff8918c03b10": "0x040100000002000000000000000000000000000000000d456c64726f6e20636861696e1d416c626572746f204761627269656c20546f727265732050696e746f00001f616c626572746f313640636164656e61626c6f636b636861696e2e636f6d00000a40416c746f625f3372000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714097cc1943b09bfaafc155a7f9fa6dec3ed3ce1edce6adabc9c0d1f3a9268ed34d499958d72dd6e22": "0x00000000000000000000000000000000000f4b7573616d612053686179616e3100000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047140997afed24646842ce9d61eca43a43e6bfec323df5c1e7084c1281161b82edb584027649766ef73c": "0x0000000000000000000000000000000000054e696b6f00000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471409a23974df7b0430c6038c7457c93db81c307499774a52b6e0a6915c040f1496c9baa6efe15b9704": "0x00000000000000000000000000000000000000000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471409b0fa30b4583caec82fcff0545821a3261f43a4956d1bec8f73ff13cec3c5e6d2788b27b7403547": "0x00000000000000000000000000000000000969736162656c6c6c0969736162656c6c6c00001945647a7a6131323334353637383940676d61696c2e636f6d00000c406c6c6c69736979616161000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471409c590716ba75942788dc4de3ced2049b97d486b9fa84c1b4b442bc85ec2cf6dd67629f689a1cd72": "0x00000000000000000000000000000000000e50535943484f4e41555449434100001840707379786e6175746963613a6d61747269782e6f726716707379786e61757469636140676d61696c2e636f6d00000d40707379786e617574696361000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471409c71da7f0f4f7aa98edcae85e6eef98ba192a51fa0efd89aac0541fa264d46adc9d8f29d3e21047": "0x00000000000000000000000000000000000b4441524b464f5245535400000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471409cedc84fed5609d6c1c40574832dee06228c10e43537fe6b3bc4cc78cdb7d34d1586d8904d8fa7b": "0x040000000002000000000000000000000000000000000447696f1147696f76616e6e7920476f6e676f726100124067696f79696b3a7061726974792e696f0e67696f407061726974792e696f0000084067696f79696b000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471409d05f5fb1d062ad503551a752e49ebef1b6988ee561cbbfe0f442a56fe624a58ae80ff3b3b9cd7d": "0x040100000002000000000000000000000000000000001f45617420507261792056616c696461746520f09f8db4f09f998ff09f96a5000013407978313178793a6d61747269782e6f72670c4f5456406570762e6c6f6c000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471409e2ab1c6ac2e7039041c96d3710d0a1abe9f550306f252e363a81d717eddae45201284dd8538842": "0x00000000000000000000000000000000000e526f636b585f4b7573616d613306526f636b581268747470733a2f2f726f636b782e636f6d0012737570706f727440726f636b782e636f6d00001040726f636b785f6f6666696369616c000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047140a4afe501add7d8e2a9ab96177cbb3a9002cc0f132d4226537b14469ef685792839f47f15971d047": "0x040100000002000000000000000000000000000000000b5052494d455354414b4500000017737570706f7274407072696d657374616b652e6e6574000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047140a5ed2dc88d315840e534d4d97bb282068c705fa51611698a6c6680ded8ef9ad9e3ec644a4a1691e": "0x00000000000000000000000000000000000a57656233204368656600000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047140a7a36431e6bf788600e047c97181ac8d0b9d5a6372f6018f556d68b2b4cdb529d87da365f718d40": "0x040000000002000000000000000000000000000000000b554c5452414e4f44455300001740756c7472616e6f6465733a6d61747269782e6f72671976616c696461746f7240756c7472616e6f6465732e636f6d000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047140a847e530cdb1c2e56217b7de1cc11317965e5fbbcd5befc40472e060042a6f69bf1aab0d2f08632": "0x00000000000000000000000000000000000f42696e616e63655f6b736d5f32320f42696e616e63655f6b736d5f3232000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047140a875f4d26e2532608676ec0e77c681fb1f96768ff752f535fce573b540abd2415087938e1c44456": "0x00000000000000000000000000000000000d4d61746861642040524d524b00126861647279736d61746575737a2e636f6d001b6861647279732e6d61746575737a383640676d61696c2e636f6d00000f404861647279734d61746575737a000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047140abb2bf22ebf7bae9efc577205550c1b254ff059895120f132de3e3b5fe0b9d22370e116257c0659": "0x00000000000000000000000000000000000f4b7573616d614d696b6520322e300000000000000c404b7573616d614d696b65000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047140ac3c356396cc02a160a6f4320d23a7715715fce96136dfa55616525f135a9868bcf1ba6f11acb25": "0x0000000000000000000000000000000000096e6674787469666600000017746966666465717569726f7340676d61696c2e636f6d00000a406e66747874696666000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047140ac7b83a778623410cfc58e61cb62c25fc3f45a56005f7b6cec22fe84eed6ac7c8992ce3209ab024": "0x00000000000000000000000000000000000a42756c62617361757200000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047140adcc02215ec15f4def30af11d3d4068f7418b757cd81b67176367423f5ea96868fe398290ae2669": "0x0000000000000000000000000000000000094b534d5f4d4152530c4d6172696f2052657965730000166d6172735f39323036406f75746c6f6f6b2e636f6d000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047140adfdac33d62d66a58e7e4aec9b2e494e77ea7aa2ba910d82923c91adf3c4a85cd912a16fa7da527": "0x0000000000000000000000000000000000105061727454696d654c6f766572585000000000000011407061727474696d656c6f7665727870000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047140aeb5541d86b4845cc2f2f205d3d20d5a1f879ca5c20dc701fc9ca9aac3a17cfb7cf9527e2dcdf49": "0x040100000002000000000000000000000000000000000966726573686665720f4665726e616e6461204f7274697a010118656c656374726f2e6665727a6140676d61696c2e636f6d00000a406672657368666572000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047140afdef9f452d50b7c210bd52d3613aaeb1a76e1927e26284338d1ebab34b6b6f1208c7de97099b2c": "0x00000000000000000000000000000000000f4a6150616e646173205371756164094a6150616e646173134a6150616e6461732d53717561642e636f6d00186a6170616e646173737175616440676d61696c2e636f6d000010404a6150616e6461735f5371756164000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047140b168c54499a2304bc97fbd07eff9c15a64279ab2c35c3c9aaa0e2c6ac35e2447dce59a7d528cb62": "0x0000000000000000000000000000000000044e454700000013646e65677265613940676d61696c2e636f6d00000a40646e656772656139000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047140b1bb76cb1a645af0ae6793d3b38c6903b70523d5a93579a7800fa29644ee67224b1b42792178c0c": "0x00000000000000000000000000000000000b737566696479616e6f760000000000000c40737566696479616e6f76000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047140b28cb00eb8fb1c6366e5d037b1dfbaea9aca8c05fa5e5d36147fad2a2ae114e33379a6b06bdbd54": "0x00000000000000000000000000000000000f676d616a6f722d656e63727970740f676d616a6f722d656e63727970742168747470733a2f2f6769746875622e636f6d2f676d616a6f722d656e637279700018676d616a6f72656e637279707440676d61696c2e636f6d000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047140b2d46548eb3753ccc96f77c66f0b96cfa65755b8d15bf9de55e014725c696d4f8e385701633b415": "0x0000000000000000000000000000000000064b6177696e064b6177696e000000000009404b6177696e4d50000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047140b3a777104037709f221049df41595b4296f7cdf47a38b5b7c3187f9cad55c48ad60277ec92ce869": "0x00000000000000000000000000000000000a73796e636c75622d340a53796e636c75622d34000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047140b490dd7c2add7ac567e17eb14c080fb53b263d9e08ed4259b3da6bfeacb088f3476752540b8f909": "0x00000000000000000000000000000000000d4172746963204b7573616d61001968747470733a2f2f61727469636b7573616d612e636f6d2f000000000d4041727469634b7573616d61000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047140b4bb8bd516529ad1cb12b2bfc64acd31cdd6d603e4d2752f952ce53346f87155acfdfd3f5d32304": "0x00000000000000000000000000000000000c4465782d53747564696f7300000015696e666f404465782d53747564696f732e636f6d000011404465785f4172745f53747564696f73000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047140b5975a00e39357f7e6df0b6f8d257074021c3bf045f9a74c020908f462edae423b2af34ddcaae10": "0x00000000000000000000000000000000000b43617374656e72696b6100000016707269636875646b61303340676d61696c2e636f6d00000c4063617374656e72696b61000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047140b78efadc03e987f66241b171bd08521a33dc807061373a092faea04252f58b70792e7c7ecfd500e": "0x00000000000000000000000000000000000e4b7520436f6c6c656374696f6e0000000000000f40636f6c6c656374696f6e5f6b75000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047140b83cb57ee6e53be78277862099de58a7be0c6472923086fc92cd75c12beb02fe9fdbe0c8411b409": "0x04010000000200000000000000000000000000000000054d616b73000019406e6f6465732e6272616e63683a6d61747269782e6f72671b4d79726f73686e696368656e6b6f2e6d40676d61696c2e636f6d000010404d616b73796d3630343130343331000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047140b932747c4dc16804e89698cf8e1e4062df1e6994e7491d1b05c22908a4131a57bb753bebd99d82b": "0x00000000000000000000000000000000000b576562332047726f7570001868747470733a2f2f7777772e776562332d672e636f6d2f00116a6573757340776562332d672e636f6d000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047140ba79531536753bb707c94e3ad62ed919cf1eebeffe3381161c4daef849a306d698539931a08ce14": "0x04000000000100902f50090000000000000000000000000000000000000000000000000000000e576f6c6645646765204c61627316576f6c6645646765204c61627320507465204c74640000176d6f68616b40776f6c66656467656c6162732e636f6d000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047140bb2cf3340206487cc03adeb1111b9cfc802ef169d0629ec766a2588ab7609ed7363ce19e584ee5a": "0x00000000000000000000000000000000000552616d7a0552616d7a00000000000840307852616d7a000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047140bb6f52935e1627fb8293604e2a0be96865b68a39d42cd4f5d53fcac3ac44ef060158ff7702aa419": "0x000000000000000000000000000000000009536c756d646f6745011d68747470733a2f2f70617472656f6e2e636f6d2f736c756d646f67650101000001000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047140bc06185ac12eb70fece00a202f0832dbb17324ef664cfbd18ce6b0625fca47f0931f0d7785c7445": "0x0000000000000000000000000000000000135275746765722076616e20646572205461731052757467657276616e646572746173187777772e72757467657276616e6465727461732e636f6d00000000114072757467657276616e646572746173000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047140bcf942d23af458454aa43748f98be9e3704f9a2a95cae73b3b03724b19cd79ec06f383b2daffa2f": "0x00000000000000000000000000000000000c6d6f726964696e2e657468000000166d6f726964696e2e65746840676d61696c2e636f6d00000d406d6f726964696e5f657468000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047140bf3579ecdcacde0362f7ac49028175d12576f48a1cef9e71c533ecd9221237c772132cbf5168342": "0x00000000000000000000000000000000000f526963682056616c656e74696e6f0000001a776869746576616c656e74696e6f6f40676d61696c2e636f6d00001140526963685f56616c656e74696e6f6f000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047140c100cc5eae89342e659339aaaf44f9871d9a42595bece9cc446cc4dc321dcb30c798332a5780846": "0x040000000002000000000000000000000000000000000454555a0000164074757a2e70657465723a6d61747269782e6f726716613935323435313430383940676d61696c2e636f6d000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047140c2040d8da8b2f132053de39c4b63304c65a0cc0d93d1b81537a4ea78be0e09404dc74f3ee8e276a": "0x000000000000000000000000000000000019506f6775657a636c61702d506f6c6b6461646f747b4a537d0000001f4d724b69747479536179734d656f774070726f746f6e6d61696c2e636f6d000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047140c230db7b4eecaf8c4d023d2b04cd11112b689517d5e8bd20a66aa5c62f9bb7830e227ff88617f2c": "0x0000000000000000000000000000000000045a4841055a61696e00000000000c407a68615f747765657473000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047140c32af425ecf7636aceff65e3bc5a9cc1ee6dc90a3acc03f65cd6a66c7c23104d7d21a3f4d266a3b": "0x00000000000000000000000000000000000e33394b7573616d696e61746f7200000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047140c388e1358813ebd801e4481679d2522f3f9cf41a66df264210fe9780528c04280a33003e2022618": "0x0400000000020000000000000000000000000000000016416c78566f79204b7573616d612d3120737461736800000015616c6578657940766f796e6974736b69792e7275000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047140c3a9dcfc81a3cfe046677c468409001b6cb1e3a1043cee8fa919aca71e27a8f65ebb965c6ae717a": "0x040000000002000000000000000000000000000000001170692d76616c696461746f722e636f6d000000157461754070692d76616c696461746f722e636f6d00000d70695f76616c696461746f72000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047140c41e5ffb19e12ae30a11a36a48739b8fa4bee6844af919e22aa50f114f9e395a1caec59cc157102": "0x0000000000000000000000000000000000055365756e00000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047140c46249d82bfb0b0d074e77a0de68e6cf05f748acb4958d062f29eb223b87be225918f23d9bf6866": "0x000000000000000000000000000000000009756469626162613100000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047140c50403091a3fe08acbaf2c1d45ca4529a36ed37d0197fce11c1848cb62c607457c5629688ca0554": "0x00000000000000000000000000000000000846334a6f756c650d566c616479736c617620502e1b68747470733a2f2f6769746875622e636f6d2f66336a6f756c65144066336a6f756c653a6d61747269782e6f726700000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047140c6834f1c2c76bf29aeff1e8a9d96bcdea1837651f64dd248d8c2bf13b76759fae5c60f6237e641b": "0x040100000002000000000000000000000000000000000f313132304e465447414c4c4552590f313132306e667467616c6c657279001840316e667467616c6c6572793a6d61747269782e6f7267163131323067616c6c65727940676d61696c2e636f6d00000d40314e667467616c6c657279000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047140c6c6f483598e787deb2bef705dcf0792c4027cdf5fe3cc6f064446f80d5281c11fc0883a95a6761": "0x08000000000100902f50090000000000000000000000010000000200000000000000000000000000000000055a45524f0d5a45524f205245414c4954591068747470733a2f2f7a65726f2e696f000e6d6172636f407a65726f2e696f00000b407a65726f646f74696f000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047140c8734e9ceeea871e69ade711fa80a229815e5847e1041104fd08fb5a4e77e2a5f0d912b16aaaf03": "0x04000000000200000000000000000000000000000000094d696c6572756e6f00000019696b61617274696b61776174693740676d61696c2e636f6d000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047140cac97255720a64876323344da3952acb9f0a654bb3402f6a95eeee8abc97c3b13c2848ce9bea600": "0x000000000000000000000000000000000010417274456e3639736567756e646f73144172746520656e20363920536567756e646f7300001a617274656e3639736567756e646f7340676d61696c2e636f6d00001140617274456e3639736567756e646f73000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047140cc8f64bbd2e71ea820050e114404eec82932c59bedbfb6c1b58981e8f85af37e5d4f26a34226960": "0x0000000000000000000000000000000000104d6173746572537061726b793430320d44616e69656c20426f6f7264000014442e6a2e626f6f726440676d61696c2e636f6d00000940646a626f6f7264000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047140ce0f91c97c65aae744be50accad162e5162a2499a897f5cfd792e0ebf9ca6ed7d13b5e404b36007": "0x040000000002000000000000000000000000000000000b536e6f7762726964676500001d40776861747265676473666f64726a6b673a6d61747269782e6f726713616964616e40736e6f77666f726b2e636f6d00000e40736e6f77666f726b5f696e63000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047140cea71908e309bff28cf33cbe014592a6f11c9133006203591ac206fce44a0d3ac5519667aed0706": "0x00000000000000000000000000000000001167c3b66b68616e207461c59f7465706500000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047140cf71787521e6de28a04ab3a66328e01112d81c15314c12bd4b6411baf8e05225e47a13daa78dd18": "0x000000000000000000000000000000000010446f7473616d612e4578707265737300000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047140cff0134bde4ac18abb9286b2b288f2af6eb392d95b12a64768174de723047b9ae0f86283dd5e34c": "0x04010000000200000000000000000000000000000000115374616b696e6734416c6c20f09fa5a9001d68747470733a2f2f7777772e7374616b696e6734616c6c2e6f72672f18407374616b696e6734616c6c3a6d61747269782e6f7267167374616b696e6734616c6c40676d61696c2e636f6d00000d407374616b696e6734616c6c000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047140d0340c34236dbdc923059e1888ad3f7c623b3f84c113bc75975e5dd8957590104b9c0613433b67a": "0x00000000000000000000000000000000000a4d696b686173686f7611536572676579204d696b686173686f76000016732e6d696b686173686f7640676d61696c2e636f6d00000b406d696b686173686f76000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047140d081f1081222619c8937715d6516a1081fc4e2757dcdb7a687f9f3a4021e0671f1ff7576a88d55c": "0x00000000000000000000000000000000000d42726f734f6643727970746f0101010100000f4042726f736f6643727970746f31000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047140d09678fc53ebff9b6ab520cbb6fe9b6bc5433fa4193074bd1aae212f0dc969d6af584e140a08a5d": "0x00000000000000000000000000000000000d52616d70204e6574776f726b1852616d70204e6574776f726b2073702e207a206f2e6f2e1668747470733a2f2f72616d702e6e6574776f726b2f15406a7061756c696e613a6d61747269782e6f726715636f6e746163744072616d702e6e6574776f726b00000d4052616d704e6574776f726b000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047140d227a0c675a37dee0a1c40e9a37cd51d6b644a33e8e4952d576accdbb13c967bf8ea3474a583031": "0x0000000000000000000000000000000000105375676172436c7562205363657468105375676172436c75622053636574681f68747470733a2f2f747769747465722e636f6d2f5375676172436c75625f010100000c407375676172636c75625f000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047140d39c09be41728d25271937d9336b12c2801a62938d27878729a7987c705770d5f19c0e42ffcc64c": "0x040000000002000000000000000000000000000000000a455645525354414b4500001a407669745f657665727374616b653a6d61747269782e6f726714696e626f7840657665727374616b652e6f6e6500001040657665727374616b655f706f6f6c000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047140d39d429edc8d0712254479a21f40fd96f3ed15a8f08f6d289e7c9d1701ebf89ad6ff6d5755b824f": "0x00000000000000000000000000000000000f4449202d20537562736f6369616c0000164064656e6368696b33373a6d61747269782e6f72671564656e69732e6967696e40676d61696c2e636f6d00000b4064656e69736967696e000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047140d3c3a7016e8df8e500908d663623ee3c05935758e1f056d70c0a8ea33fc0c00384845dd7f3dfb56": "0x000000000000000000000000000000000008444546496b736d00000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047140d4ca3ddcf99187b260a01d4ea712ce6bf0fa166b6aebe2ddfc86bf523307005f6c87c2ca654916b": "0x00000000000000000000000000000000000a626c6f6e646961646100000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047140d533a9fec9db13002b47d21483aa953be67636583cb184f55d575e0f71ec75f45383a786324a64b": "0x0400000000020000000000000000000000000000000015f09f8d8120486967682f5374616b6520f09fa5a9184e6578757320496e666f726d6174696b204475727265721768747470733a2f2f686967687374616b652e746563681640686967687374616b653a6d61747269782e6f72671e686967687374616b65406e657875732d696e666f726d6174696b2e6368000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047140d5ce2f7af07c1b88afeae9a945866e010eb1bef5082c9f0670e484984b6873e7f0eb297cd4d8e54": "0x00000000000000000000000000000000000d307847686f737452696465720000001e6b696e6767686f73747269646572303037363940676d61696c2e636f6d00000e40307867686f73747269646572000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047140d65a8f206f0572aa67b45909ab82a670809e0eb1dff23c0d4f296974b62d8d823cf45471044c516": "0x00000000000000000000000000000000000b45736554654c6f70657a0000000000000c4045736554654c6f70657a000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047140d7e595debaf7057166a8e85fb2ae8e4bb6815407ab2e17573050a080e1babc5022264fef9e96f5e": "0x00000000000000000000000000000000000768616e6e657300000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047140d8bedb75031185630734713c5ab53cf7cffbb321ced799fc7d49b43f385234b15c2ca720a222573": "0x000000000000000000000000000000000006706f6c6b6100000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047140d905eb3b2787c26d495b0e302e1a577cd8ac5bd2681568e809e706bc32ca18d0a3921680530fd19": "0x00000000000000000000000000000000000b4e6f6f646c6544756465000e6e6f6f646c65647564652e696f0000000010406e6f6f646c6564756465706d7673000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047140d98f82850d6b275f2e9d52d264f1d78a2f3379ac661de73255cf80b6b54a4b80de6d9c31f748a0b": "0x00000000000000000000000000000000001b5375706572636f6c6f6e7920446566656e646572732046756e640d5375706572636f6c6f6e79201868747470733a2f2f7375706572636f6c6f6e792e6e65740000000011407375706572636f6c6f6e795f6e6574000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047140db5079f95a9bf8dfa7c3aa61ad8c8ddee5e79e5cf0f0094d4ec0a1c5ce1b74064a3001d0ea2b64a": "0x0000000000000000000000000000000000084d722e484f444c00000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047140db9aeb749b73803bea5add43dcec81b15267ff88d61106f1640f5a8c84bfe8555fcfddc64bf3405": "0x00000000000000000000000000000000000000000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047140db9d7828adfae319e7c6c92b95381eda2995d8b4b6f3926b694c74c3643dddf3e4d182c316a3a13": "0x00000000000000000000000000000000000c4444204d7974686963616c0d44696e6f2056756b656c69632168747470733a2f2f7777772e6c696e6b6564696e2e636f6d2f696e2f64696e6f001964696e6f2e76756b656c696340686f746d61696c2e636f6d000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047140deed80c472e7c7c686a3a22aef015c34517659f4f96c5f1768aecc308f1467dc621e85c709d1809": "0x040100000002000000000000000000000000000000000d444953432d534f46542d30320e4469736320536f6674204c74641a68747470733a2f2f7777772e646973632d736f66742e636f6d154064697363736f66743a6d61747269782e6f72671876616c696461746f7240646973632d736f66742e636f6d00000e4044697363536f667457656233000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047140df42bc818c9fd1ef89bedd1de864245baefc341997957f57eaf77620e26ef1aceee9bb50bce4220": "0x00000000000000000000000000000000000b617065586368696d707a001d68747470733a2f2f6c696e6b74722e65652f617065586368696d707a0015746f75636840617065786368696d707a2e636f6d00000c40617065586368696d707a000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047140e032f02dea784887ec0c61a682519e78e65026c51ceea52273870636814605a33518f02ad543317": "0x040000000002000000000000000000000000000000000d737765617479627265657a650000000000000e40737765617479627265657a65000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047140e08280eb46d228ef69de233dbbad30fd78a5a88bc8fb4d38bb9c0caa6f0e73a4a4f8955ac5ec253": "0x00000000000000000000000000000000000941534148204e46540000000000000a40415341485f4e4654000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047140e0b3aa196d8924da44db018b0966000a7601da48063c535ab23ef856aaec13fa1555260c244143c": "0x0000000000000000000000000000000000010c4672756974792d426f797301010100000a4030786c756b656f69000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047140e211dc5b0982117b47a017c3ebaff5fc5e7b686fb511d9d8b7065322339274695f8fe1d38200172": "0x000000000000000000000000000000000006666861696e00000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047140e21b1928b52b99a9adf3209ba3436e0c3e7b87ed6aa40fa1a88fe68ed3a00ad0e922a147494324a": "0x040100000002000000000000000000000000000000001847454e534849524f20425920455155494c49425249554d0000001d616c65782e6d656c696b686f7640657175696c69627269756d2e696f00000e4047656e736869726f44654669000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047140e28c8c63d0620b0c84c7013e7639f5ce15c6b51d9a33ab040dedf1851c71d697f3fad5f14594549": "0x040000000002000000000000000000000000000000000f506f6c6b61646f7462616c6561720000001b706f6c6b61646f7462616c656172657340676d61696c2e636f6d00001040506f6c6b61646f7442616c656172000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047140e2df285221b11002639d5a44f52ebb752039a5def9e776c12b8ed3ba1a12e60299cfc00fe546c2f": "0x000000000000000000000000000000000015504f525455475545534520434f4d4d554e49545915504f525455475545534520434f4d4d554e495459010119706f6c6b61646f7462726173696c40676d61696c2e636f6d000001000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047140e60e74a5190baf65ae72c7ce8ab9b183909c1cb1eaf21f02850c872130f391af72c4380efa3e738": "0x04000000000200000000000000000000000000000000084e6f76614e6578000015406e6f76615f6e65783a6d61747269782e6f72671669726e64656e69736b6f6d40676d61696c2e636f6d00000e404164696e64614b6172696b61000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047140e73707fed983955ae1ba2069c434aa22b860314674b862a23eb53ae9603316439d3cab44e6c7e20": "0x00000000000000000000000000000000002047616f20746865204879706548656c6c207c20326f6636204d797468696373000000000000084047616f417065000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047140e77a555b20dfd069642d0db9f3b301b44df74b63b0b930011e3f52154c5ca24b4dc67b3c7322f15": "0x040100000002000000000000000000000000000000000a536f72616d6974737516536f72616d697473752048656c76657469612041471868747470733a2f2f736f72616d697473752e636f2e6a701d406d616b6f746f2d736f72616d697473753a6d61747269782e6f7267127440736f72616d697473752e636f2e6a7000000e40736f72616d697473755f636f000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047140e7ebd7950f6e71f663017d73b55d4f4a7fd5adcc62006ff49b12f6056f2f30fefd21b4a0ee35610": "0x00000000000000000000000000000000000c5a68696c696e5374796c6509566c6164696d69720000136d722e7a68696c696e40696e626f782e72750000084058616c6c4861000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047140e8cb1099f1092089cb4a8212f1c823c25693c15467047378f846454bad62d6c947a2ade36563851": "0x00000000000000000000000000000000001f4d6f6465726174696f6e205465616d20426f756e74792043757261746f7200000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047140e9910201efc63d224eb144dc285fd665819aa61ee6765b27039ec6d4c6c9993a7c163f063cdab07": "0x0000000000000000000000000000000000034d52034d52000000000009404d525f30303431000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047140ec06ed16827147be2c0f5532d658a0c0d9e12c26bc062e30d309adf8e39b4a0c29e489f382bfc49": "0x040000000002000000000000000000000000000000000a63727970746f6c61621243727970746f4c61622e4e6574776f726b00144079616f6873696e3a6d61747269782e6f726700000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047140ecb33ed71b3de7b708eeff6aba393c24d89dbd6bc74e46cef9ccb7be321647b624781b76d9ba304": "0x00000000000000000000000000000000001054686520506978656c205661756c74000000000000104054686547616c6c65727931313131000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047140eedf7d25e7a7bc88063c56f76c1dec83d0cc13abbd248d438d512f5510a62dcd6e98d2fa9e38e41": "0x00000000000000000000000000000000000a74616d614a6f73686901010101000001000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047140eef1e0dd5e940a8d8e704ee02d595b8622d1d1901dbae3dc049118e36e85317e2cb7f9166b7c93d": "0x04000000000200000000000000000000000000000000095072617368616e74000000157072617368793230313040676d61696c2e636f6d00000f4050726173685f4167617277616c000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047140f177f5acba9e6e070661c356f24a2cddc859fbae974cdff149661f165f5e622df3060bcb8e7b373": "0x040000000002000000000000000000000000000000000e53796e6572576f726b20496e63000000167374616b696e674073796e6572776f726b2e636f6d000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047140f75f7e0ac3e676454273ca13308c2a9f40b322ab6c192da5ab9f8cc8be07326dfdca1c59689bf08": "0x00000000000000000000000000000000000c432e204b616d696e736b69001b68747470733a2f2f7777772e632d6b616d696e736b692e6172740012636b40632d6b616d696e736b692e61727400000d40434b616d696e736b693137000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047140f7722ef9e3f0c3bb0d8ce5256f0b5a51a38ccaadc6d21fe930d8ff3da1dca198ebe1807802da753": "0x00000000000000000000000000000000000b4441524b464f5245535400000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047140f7f00ad7cb619c008769738ff8d53c17d6e0f0344e52c50a5ef6b61a33389f4dc4adbb7aa2f384d": "0x04000000000300000000000000000000000000000000105765623320466f756e646174696f6e1d5765623320546563686e6f6c6f6769657320466f756e646174696f6e10776562332e666f756e646174696f6e0016707265737340776562332e666f756e646174696f6e000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047140fc514eab423f9a784434de779e5fcbe6da08b123b0d1556c5ded43cccd6a9b1f6efdc9ea4942032": "0x040000000002000000000000000000000000000000000f4b75732056616c69646174696f6e00000016686579407468656b7573616d617269616e2e78797a00000f405468654b7573616d617269616e000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047140fcc6386bb41988e76d82b70c69c1fbb8c15260720357f8964dde4621520267051b69a86d46be767": "0x00000000000000000000000000000000001050726f666573736f724875676865730000000000001140726f63686573746572736e69746368000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047140fce6746c0fcbe63c2fb8933d2f269bfc83970bcf019e9b9204fe40666ca00494eb9c6560a53b01b": "0x00000000000000000000000000000000000000000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714100660e0aeb247211c2a9af7bdca199cf341b9fc1315c3fa625849d6e9bff3e7361f40f4889ab57c": "0x000000000000000000000000000000000009446f746576656e7409446f746576656e741568747470733a2f2f646f746576656e742e636f2f0000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714100ad1333a8758d9d8cca15fca39d01fde7d1eff1cc8529dfca033c40777994e23150e81c72a1640": "0x00000000000000000000000000000000000841564c204b534d00000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047141015fbd7c4e0657c321b74ce57dab7e81fd0a29d2d5eb705ec3f0950df8d9673d2f0e9188fecd867": "0x00000000000000000000000000000000000e4c6567616379204c65617665720000001b6c65676163796c6561766572736c6c6340676d61696c2e636f6d000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714101dc364cacca331289d0e953caa48c4e7e416022169d1a71ca9ef7726571d551b3fcff2bdc59a73": "0x0000000000000000000000000000000000094879706548656c6c094879706548656c6c1e68747470733a2f2f646973636f72642e67672f664d63386862506d354d000000000b40687970655f68656c6c000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714102148a1017f00501a393b336f8230565ac033b4e83c4a1711f87eff586d2acfb351a1254c41235d": "0x0000000000000000000000000000000000097869657765697a63077869657765691d68747470733a2f2f747769747465722e636f6d2f7869657765697a63000c787763764071712e636f6d00000a407869657765697a63000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471410285ff7a2dfaaed30dd6b5e5177c32a64cdb0f0e601d77902c2833062b3cb7f5800e7a2c497640a": "0x000000000000000000000000000000000009f09f8c88f09f8d8000000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471410373f12dc9ab897a4a045fee5632d07206b047972efbf41de0351885f7d0c8d7bd2f272dd98c053": "0x00000000000000000000000000000000000e4d6172696f2056756b656c69630e4d6172696f2056756b656c69630014406d6161722d696f3a6d61747269782e6f7267176d6172696f76756b656c6963407961686f6f2e636f6d00000a404d616172725f696f000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714103e847acd44a834c8c0c1fb9bb3902b9e4790461bec2c33afa31c9a3b72a4e4ab6c050b4a284507": "0x040400000002000000000000000000000000000000000b436f6e6e6563746966790000001c78696f6d6172616268756c6c617235323740676d61696c2e636f6d000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714104c4a90570bc5fcb01a8d3e27c8f4a2f1ed53bad7d240999ec076bb23155fdc020b70e2680efa1e": "0x00000000000000000000000000000000000943727970746f44560000000000000a4063727970746f6476000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471410547c88eb5e1280f889d7a8087639059b95b1b3de84c8f80361fb2309a7497388b6ded2e815d766": "0x000000000000000000000000000000000015484154454d207c20444f5442454c33415241425900001940686174656d656c73617965643a6d61747269782e6f72670000000f40686174656d656c736179656464000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714108d9a2d402cd7cd82e813a68fe066b55cfbfb48fb99484e96f813e3f2b98ae3dedda80f5b069243": "0x00000000000000000000000000000000000000000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714109f2a19e0b0e38a20d4b086bb5326ac9896b0a3ab4f37fdb680a09706c4460c98110b1a7aae4f12": "0x0000000000000000000000000000000000000000000000000f406672697a7a6c657a6c7a7a6c65000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471410af15fa81ea76ada81e54507ca4f6fa30932b96d35e8f073556c99f4e3119e5f679893450192109": "0x00000000000000000000000000000000000853435954414c4500000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471410afe0be04153ccb6e7a5ea5f4113720dab9d89c4b7f949ea67731df7421ea069516115777b2ba6d": "0x00000000000000000000000000000000000d4265747479202620426c6f6f00000016626574747978626c6f6f7340676d61696c2e636f6d00000e406265747479626c6f6f617274000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471410ce5b49d79045fda2b8bfb3c0c1f04346134e7b27cb5b63de8a7af0d57c502d09c05ba7b3dd1e28": "0x0000000000000000000000000000000000054475636b010115406475636b77696e673a6d61747269782e6f72670100000b407468656d6475636b73000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471410d658671f80bdd8baf077e92aca3921fc948042653b85d2c7cf1dae44eafdd35270943ded113425": "0x040400000002000000000000000000000000000000000c50726f647563745f4c49540000001d6665692e6c69752b70726f64756374406c6974656e7472792e636f6d0000094066657977756465000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471410fcb033412d7d4970882eac544428a1332197cdf4e46f0ec005b083f30c9e00beed9f0c0f48817f": "0x000000000000000000000000000000000007576176696e6700000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047141109d1b0b3898be6446130ed95427fedb36702f4ab2eae7612e5f2f5033cf0f8b51ea97e13f1d219": "0x040000000002000000000000000000000000000000001e494e20535042202d20f09f8dbef09fa582f09f8db7f09f8db9f09f8db8000015407370626472696e6b3a6d61747269782e6f7267185350424472696e6b4070726f746f6e6d61696c2e636f6d000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714110c6956c14d8038f81fefa90f5199ca0d60d147602cf2f9001266e557483d41ce8c671d51605313": "0x0000000000000000000000000000000000104968617665427574745468727573680000001744616d704372616240686f746d61696c2e636f2e756b000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714111aa70eba23115bfec58ced993f959b9e3f61848eb10caa2a1376941d30c06be2425b1e31f50e23": "0x00000000000000000000000000000000000c4469676974616c205a6f6f002168747470733a2f2f6269742e6c792f4469676974616c5a6f6f47616c6c65727900186469676974616c7a6f6f61727440676d61696c2e636f6d00000f406469676974616c7a6f6f617274000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714112601944f90bca480e7d9cef14591225c0e2a135224b576efd10b38cde56f71ef231dac8973b524": "0x00000000000000000000000000000000000d236d616b6f746f7069616e73106f6666696369616c2026206f6e6c7900001362726f6f6e79636f40676d61696c2e636f6d00000d406d616b6f746f7069616e73000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714115e48078425c5c92aa70df8bfb5ebf58cd2bfcdabad29392ed53b1d2f2ab81e519e6bc4f490c13b": "0x080000000002010000000100f0373a00020000000000000000000000000000000000000000000000000000046e6a690000001a6d696368656c6c652e6e6a692e313240676d61696c2e636f6d00000000096e6a69233536323800", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714116a7dbbc41fa50e64b011ce64137258e47a08cab6b492788e03e74f44c7c3a22c567217af20645a": "0x0000000000000000000000000000000000026a0000000000000b406a656e5f646567656e000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047141181e386a86037f2d269f40cdc569d0855c22874f24a81b572d76d8d08469c33d1cf70db2d5b206a": "0x00000000000000000000000000000000000970617374614d616e164d6f6368616d6d6164204875736e692052697a616c1968747470733a2f2f6963616c31302e6769746875622e696f19406875736e6972697a616c31303a6d61747269782e6f7267156d6f63686875736e697240676d61696c2e636f6d00000d406d6875736e6972697a616c000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714119a0f76e4d92fd98c68b0748032acd289880d004ed59fd72856fcd75133faf360f0e1652a23276b": "0x0000000000000000000000000000000000064c4f474f53064c4f474f531e68747470733a2f2f747769747465722e636f6d2f6e66745f6c6f676f73010100000b406e66745f6c6f676f73000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471411b8ff944fec6dc1d09a1884c8ca6641e644447f160be702de9c6748da6b51c553d6ff35cd8e4e08": "0x00000000000000000000000000000000000000000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471411ba561e194c5f74d897ab7ef91822fe787ae9e4ec865e6aed2aa20e59e6ca0df2fb67d266497d4b": "0x0000000000000000000000000000000000174b6f6461446f745f4672657175656e745265616465720c4b6f6461446f742e78797a0c4b6f6461446f742e78797a0000000009404b6f6461446f74000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471411c43684ff6dd5c2426d4caa9a620d37f530756d282dd41b1105cfb4e4e3bcefc18609d1ee199d1c": "0x000000000000000000000000000000000006536b61646500000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471411e075ceba8e3f4524112dbb17e6f83bb832ee26149c8b00cefac96a1a668ccf0645898c3c271d04": "0x00000000000000000000000000000000000c54696d204a616e7373656e0454696d19687474703a2f2f74696d6a616e7373656e2e63727970746f00177468776a616e7373656e383940676d61696c2e636f6d00000e407468776a616e7373656e3839000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471411e755e0b2a267d8a8a2e5461f346cf0c23d1ca613437432a160525b6487dbb718afa51439d48d04": "0x040000000002000000000000000000000000000000001a4b7573616d6120537465616b2d4b696e67f09fa5a9f09fa4b400001740737465616b2d6b696e673a6d61747269782e6f72671a737465616b2d6b696e674070726f746f6e6d61696c2e636f6d00000c40737465616b6b696e6733000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471411eab7306fa8072a201551760e53240d8229b7c99fcbce0ade237854dff91796dd67c5a00cb43672": "0x0401000000020000000000000000000000000000000005636c696f000000156f746f67656f6e69636540676d61696c2e636f6d00000c4065617269617332383238000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471411edb4162e9b96b85ecc1b0043fe1fc18950cef3726fa74151bc41f77438ce924c11a9b43823ff43": "0x0400000000020000000000000000000000000000000018f09fa78a2049636562657267204e6f64657320f09fa78a00001940696365626572676e6f6465733a6d61747269782e6f726716696e666f40696365626572676e6f6465732e636f6d00000e40496365626572674e6f646573000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471411fbcd54abb1de419ce84f6cd845ac3fb2a009aae8e99b1a2fb64aa3e7ce1c7867f3ab2db0c9bc00": "0x040000000002000000000000000000000000000000000d6c696465727461626f72657300000018736f63696e796970657273696b40676d61696c2e636f6d000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471411fcae71b9124914ea2cf269fd21f2df6e71e5df234b1d1e5e05c145e02d40ddff3b6f0a7691c64b": "0x0000000000000000000000000000000000065768616c790000000000000a40796f756365617274000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471412060f617a53b90efa99c57636163b80492e7748882c27e82074cc76ae723804e0c8f222aa1c9879": "0x04000000000200000000000000000000000000000000144b726f6d626f70756c6f73204d69636861656c00000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471412340500c577b01cfefac151cf58a64b79b329b7ecf23bf592066f4af0cf1a17c61ab61f4d71cd63": "0x00000000000000000000000000000000000c5a657573204d6f6e6b6579000000186976616e2e7370616e6963333240676d61696c2e636f6d000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714123e32f295726d2f301075ea9032e7e039d63b38ea075a276cd2f0f7087ffbeb1eb4320213048955": "0x00000000000000000000000000000000000e50756e6b205661756c7420233100000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714126b274fcd441f701054d5e79d6343876329914f0e7264c1f7abb9ab83c6944a08d1e1c594b4541a": "0x000000000000000000000000000000000007486179746368010101156861737372697a6b393340676d61696c2e636f6d000001000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047141281300a3acf4a3efea6e9d55bb4b00962d6ffa48d1305b1e7c90f6cd08858ad5a7a2b86e6394470": "0x000000000000000000000000000000000011416c6578207c20444b2053747564696f0101010100000e40444b73747564696f416c6578000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047141281736c37e85f535829756f059fc06840d26ad9c75518aadfbf125314f9af67f67b7f5f66eeb97e": "0x00000000000000000000000000000000000b536f6265722048616e7a0000000000000b40736f62657268616e7a000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047141283d5fd7b76f3b26ee23b9c2e8092cfaf9a22eb3f6167f099fa3a0413cc379b666684e5e944f242": "0x00000000000000000000000000000000000a4c696c204d616e676f144e677579e1bb856e2043616f204e68e1baad7400001a6e677579656e63616f2e6e6861743340676d61696c2e636f6d00000f406e677579656e63616f5f63616f000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047141299152c90d9cc99f27087b92d180452a367b385c93e4ff2f9206ad87b172471a8d54b721d282910": "0x00000000000000000000000000000000000a6b756d61676f726f770b6b756d6120476f726f7700001b6b756d61676f726f752e6d756e61676540676d61696c2e636f6d00000f406b756d6135365f6d756e616765000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471412a2b27991e12dc3f4e082da663ec16019fc9db34386a4b0c4571ea758f19f75b5ed496817816c79": "0x0000000000000000000000000000000000044c784d11416c656a616e64726f204d696c6c657201010100000c404d696c6c6572416c656a000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471412a67a04b3ff6d1cb8e3827ef7f013ffe0684f2a2463cdb6d81a74dd0f34b0b7e0761105f0dedc45": "0x0000000000000000000000000000000000074a6f795a6574115365726869695f566f726f746e69616b0000166d696e697374723134303840676d61696c2e636f6d000009407a65745f6a6f79000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471412acf616659be35f9866ec0c1204773a4b95a1b374d838b5820f704a65deeaafb97f4ab96c351158": "0x0000000000000000000000000000000000164b6f6461446f745f4775696c645f52657761726473164b6f6461446f74204775696c6420526577617264731b68747470733a2f2f6769746875622e636f6d2f6b6f6461646f740000000009406b6f6461646f74000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471412b1ab7fbedaeb3e100c99beb21e35628a5e0d811d0e6637b1e43b5deba5b3e555ca78e071f4b803": "0x0000000000000000000000000000000000095761674d656469610000000000000e40746861744d65646961576167000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471412cc628ce2af21b01837232566f19190ccb14bf5a1e60a805398032d38e87eab9ee18f90aa0e721f": "0x0000000000000000000000000000000000096377696e656464730643687269730000136377696e65646473407961686f6f2e636f6d00000f4043687269733737323630343530000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471412dffed5472b77a54a9086ffb666eec156b216247f7daf9f5eb73806ee501ba87f7ec8f83a19d86b": "0x000000000000000000000000000000000005c2b06f2e00000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471412edd5e808c61a4696eac06549b02180ec91154820531dd78640a234d3f1f6efd9728f0416851f41": "0x00000000000000000000000000000000000f4275794869676853656c6c4c6f7700000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047141307eb650f06f8f7721cd1fe88d1d2df420564396ad478c84d9bd66447c55bb330a4e7d8d454057c": "0x0400000000020000000000000000000000000000000008477265616e63680000001667657274696b657274313240676d61696c2e636f6d000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471413102e0d3c1339e244135eb8cdc82a9fba31b0c628faa21e6a6cfc80396883a553a2766339b03078": "0x00000000000000000000000000000000000b4954417374616b6572730b4954415354414b455253137777772e6974617374616b6572732e636f6d17406974617374616b6572733a6d61747269782e6f7267156974617374616b65727340676d61696c2e636f6d00000b6974617374616b657273000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471413266de9c03a53de50b9bf10b8cffa9a694570ef350b8191d567cb46a04a361bcfa618716b78d715": "0x00000000000000000000000000000000000f4d6574617665727365204d616c6c00000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714132693d807f6c23df804dcab1236fb910768d4da27194a2e66172165d41f8b26d95a23e051d86c42": "0x000000000000000000000000000000000006526176656e1154696772616e2053686167696e79616e2168747470733a2f2f7777772e66616365626f6f6b2e636f6d2f74696772616e2e1440726176656e33653a6d61747269782e6f726713736865676930303740676d61696c2e636f6d0000094074696772303037000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714132a190b2bc6eb70a4f12c896b5de927b41124a79d0808d61c32f5c3105f58e80369321888d2a351": "0x00000000000000000000000000000000000000000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714133d012d7d60381ec218093851955159d042164ec55bf7aec8e4bb8754b34938dd58603322bed771": "0x00000000000000000000000000000000000f42494e414e43455f4b534d5f343500000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471413464ebee1a9be7b46c9c30fca4d06ed3cde1cd6ca25392fec9e27d6ef86f786118a53416401767c": "0x04000000000200000000000000000000000000000000124b7573616d617374617274657220526561000013407265615f63683a6d61747269782e6f72671472656173636865676740676d61696c2e636f6d000008407265615f6368000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471413470468a7a63147c214e403c5a7b459b86bcab68e6d21241c1bd20b91aee546c787e71b877bf460": "0x0000000000000000000000000000000000134d616365205468652050656e6e696c65737305416c6563010101000011405475636b6572746f7468656d6f6f6e000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714136bb08c596dddb97ce2421f6b3c80a00c8fa9476eddad55f7bb9cc2f54ad916b4969c103b5fd438": "0x040000000002000000000000000000000000000000000a48204120562049204b001168747470733a2f2f686176696b2e696f1240686176696b3a6d61747269782e6f72670f68656c6c6f40686176696b2e696f00000a40686176696b5f696f000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714136cca57f11634c0d29f3ce17cedb01b50312d7318ef8e9653d15682dd2511984fc963623bbdc272": "0x0000000000000000000000000000000000094f6a72614f6a726109416c6578616e64720000166f6a72616f6a72612e717140676d61696c2e636f6d00000d404f6a72614f6a72615f7171000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047141386b80bb27232f3b8060d01712e6c73c63d799537517c6eaa4cc91aaff645802c824ad857dd8e28": "0x00000000000000000000000000000000000f42494e414e43455f4b534d5f353200000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714138ed61d7d4e581400725cbb3eb7e1fda5b19c7ab123a08c1a28b16d17fb4d6d09f679012ba38c04": "0x0000000000000000000000000000000000055441592001010101000001000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714139cbe44f2633cf6d6793dc7dde7b0d936b3e1748e322422c6f61b0a88d009af3556118b28729143": "0x000000000000000000000000000000000005446f7473000a646f74732e70696e6b000000000e40706f6c6b61646f74734e4654000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471413a4e7699eebbe52e6ff88586d3166ca2400929db69f53a8c80f5aad9dcd88e2c2634596baeb4a0a": "0x00000000000000000000000000000000000b676261636920524d524b001f68747470733a2f2f6c696e6b74722e65652f706f6c6b61646f74626f6f6b124067626163693a6d61747269782e6f72671767696c6c69616e626163636940676d61696c2e636f6d00000840676261636958000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471413b3f7e5a93f07231888d8cd7f28c49bef8d47726228213023b7b83604937b9149df15278dad014c": "0x04040000000200000000000000000000000000000000194c6974656e7472792d5265676973747261722d50726f78790000001f7265676973747261722d737570706f7274406c6974656e7472792e636f6d000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471413cfcb660666c8624ce1f78bf64a21a6e2eeb43328484cb4be5f4e16487ea889ec097601ba8adc13": "0x0000000000000000000000000000000000056261687506737572796100001b737572796176616d73692e7065726c6140676d61696c2e636f6d00001040737572796176616d736930393132000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471413dd0435c4b8c522b4666c60cc9d87c3915b4baeca2d36c35099e9ca0ddf514d46af551fb0548b68": "0x000000000000000000000000000000000004617a6501010101000001000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471413ddb460718d6739042f0f21da287ed2ed87cff8265c769b29dcfbdb31ac0139f932e7995953d53d": "0x0000000000000000000000000000000000084e696e6a61203200000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471413e1cfc174c1683df6888bc9300f5ea591906c10ad794b79074905bff2bc972efd81a56a5223366e": "0x00000000000000000000000000000000000c7375627363616e6e6575720000000000000d407375627363616e6e657572000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471413e46ed7773b00617e2de5c0a266241928cf60949b2ed8069cc0485d93e4a1dd17ccfa3a28de8e32": "0x0000000000000000000000000000000000064d696e7a7900000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471413f09528ec25d9e786f5d655731e62ff3b27a5ded3e2615c01821d00362624fcde163a2d5d62de71": "0x00000000000000000000000000000000000b4d616368696e65456c6601010101000001000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471413f69efb52055873ec5b49a3746d88c99e3f3598bbc2ea84dd98ad0249dabfed2cd685b1ce636d5a": "0x000000000000000000000000000000000006475250564e0a477261706576696e65000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471413fb96176f3e8aa424c8acf190cbc2c5b2d9bc0df22d2cf0472ab02baa7ce7cb958c90e8a5b6e04b": "0x0000000000000000000000000000000000094f736b6172766c72000000186a6172616d696c6c6f2e766c7240676d61696c2e636f6d00000f404a6172616d696c6c6f5f766c72000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471413fba91067ee782aaefd2727ec65732fec6ebfc4a824345adb093436abfd5f53e0fe421c6f5cdb0b": "0x0400000000020000000000000000000000000000000006445053544b00000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047141404625c59d62180187c76f60b8e91032091aacb1ec79764af51e796a0c962bd2f2e766e9e5ade45": "0x040000000002000000000000000000000000000000000550494d450000184070696d6574617261646f783a6d61747269782e6f726700000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714140d4d149491fcc516789770d4f032a7a6a43d03493704e8750ffd67090f8d763874d1934dc65b66": "0x000000000000000000000000000000000008446f746369747900000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047141440cbe3e601dca1749e34ce23a7934f79736024a100897a95873e4234e9fb64da3526a3c1cfd60f": "0x000000000000000000000000000000000004545132010d74713262656174732e636f6d01147461717561696e747140676d61696c2e636f6d00000c405461717561696e545132000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714144ce51a8d1e9d772004a0ca9db782903ecf235bda84dc084ee57ace3183dd9c52ecb1f4384a2108": "0x000000000000000000000000000000000009506f6c6b61646f7400000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714148446d6e27ad179566511e3d396022cf986a5a86d09bf77db45af3ddbae12a8bd78948072505f4a": "0x000000000000000000000000000000000009546172656b6b4d4100000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714148fb0f115ad9c603c36970e4f759294ab646c7f67b040039321069951f955e3e9daae8c0df00e7b": "0x000000000000000000000000000000000006474d41373000000014676d616f71756940686f746d61696c2e636f6d00000e40476572736f6e5f416f717569000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714149ddb66d3286a35ec7afe6fbfc9947fd177ed118016e403dbc14803a0432bfaf0337e3bbc3c820b": "0x00000000000000000000000000000000000853435954414c4500000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471414a3752d9508a99f06ea5e92916cd4db2e18257272c868997978f28b079366197242626da7e86837": "0x0000000000000000000000000000000000134c6564676572776f6f642053747564696f7300000018667574796f756e676d6f6e657940676d61696c2e636f6d00001140776f6c666f6663727970746f73745f000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471414a9d939bb55ac3e6eb452fa37b17f70343b605f204004392380def7958b0743c14fee14e8feed54": "0x040000000002000000000000000000000000000000000667616d626f0000001e616264756c6b6164697269626e69647269733240676d61696c2e636f6d00000c4067616d626f3030303034000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471414b749bf7b2b2249c4727ccdf094ab0897e53c8c3a9537a78109daccc48241b5b991295d7a511432": "0x0401000000020000000000000000000000000000000006444552454b0a444552454b20594f4f001c406d656368616e6963616c77617463683a6d61747269782e6f726714646572656b40707572657374616b652e636f6d00000a40646572656b796f6f000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471414d831e44cf7b70cd800934b3567595ef527a3ba5f962f8594024a870ab4f25ed9ca51de8006e01c": "0x0000000000000000000000000000000000064454444944001868747470733a2f2f6c696e6b74722e65652f6474646964124064746469643a6d61747269782e6f72670e646f744064746469642e636f6d000007406474646964000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471414e7f5695bdcfeb7fca6074f8a41b2f8b52e71dcc4273c4012ebdd8701d3ced2e64332475f7b3175": "0x0000000000000000000000000000000000076b617a6b617a0101011a6b617a756b696b617a75746f31313240676d61696c2e636f6d000001000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471414f43fb7c9ca8d300cf88657e8a5e5005c67c0ae58b0ea1137b817f32d30d80aba618a70b13bcc66": "0x040000000002000000000000000000000000000000000d504f4c4b414348552e434f4d00001440736f6e676875613a6d61747269782e6f72671b706f6c6b616368752e7374616b696e6740676d61696c2e636f6d00000b40706f6c6b615f636875000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047141502f6b55d13fb36ae619a936ca92134102dfb470cdf8529756bf2270e661cfe322b1851f151e370": "0x0000000000000000000000000000000000035641000000000000094076615f735f7661000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714150b14558bc6ee972ec748871d5079ed3d19a3bd8bb029f8b02d6ef1820fe786c703ead515b52d33": "0x0000000000000000000000000000000000094c69736f756e617300000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714150dc822f025a4b3ac2306883197ed88bc2b4c27541c85b0b7754e4f8cdc6b2ca8c1d06f23eeba35": "0x0000000000000000000000000000000000104d61726b5f56616c65726576696368054d61726b00001b6d61726b76616c657265766963682e6740676d61696c2e636f6d000011404d61726b5f56616c65726576696368000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714151958930b5ee93dbe40e9fb89b6a296813c638eeaa8e0cc3d04acc3edb8c55db7691da053576a32": "0x0000000000000000000000000000000000186461726b667269656e643737207c20616a756e612e696f00000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714151f26dae857e5e4640ee7e0735e1e7f68ce1d600f9eafbccc311cb1bb25542721dc6d6432d86971": "0x0000000000000000000000000000000000074d6172696e61074d6172696e6100001770616e7479756b68696e616d40676d61696c2e636f6d00000e4070616e7469756d6172696e61000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714152b5d77fe21288c1cbb9921ee063aecedec0d33588aff5943da3374e172a78395a75228e82215bb": "0x00000000000000000000000000000000000a4942502050726f787900000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714152efa862046d2aea2421e1acb1f1b912f1a020979c61899f1d53e6d967760f7446b660858485a27": "0x0000000000000000000000000000000000074d616865736100000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714152f5e61256c5cb31a95c3968b83520b8e43f82edb0f050b1ce7281873a93bf9c0798efd50f5c41a": "0x040100000002000000000000000000000000000000001243727970746f6c61622e4e6574776f726b1243727970746f4c61622e4e6574776f726b1e68747470733a2f2f7777772e63727970746f6c61622e6e6574776f726b144079616f6873696e3a6d61747269782e6f72671568694063727970746f6c61622e6e6574776f726b000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714155ac70cb4838b627acd5cd13cdbaebd17c3118f06484e10d23fa25554b5da3e5b088c25f757e737": "0x0000000000000000000000000000000000074459443433420c44656769204475646165761b68747470733a2f2f747769747465722e636f6d2f44594441454200156465676964756461657640676d61696c2e636f6d00000840445944414542000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047141566fd1ee1ca92c40cf6f55eafa3e54268f4de745c8e50afdaebddde55f33a4dd19d0a93e552dc05": "0x040500000002000000000000000000000000000000000f41736875746f73682053696e67680f41736875746f73682053696e676800001b61736875746f736873696e676831304069636c6f75642e636f6d0000104041736875746f736873696e676768000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471415693d619c1eaa27282a304d8c9425a79907218152427905b9e49974b64da3cfc2eddeea71958559": "0x00000000000000000000000000000000000c4465722053616d6d6c657200000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471415712b2ff79535e5c273794ac33c95766fae2316b99e80398db94d6fb5a7ce605d729d2024bff14d": "0x00000000000000000000000000000000000748617573656e075275736c616e00000000000a4068617573656e7561000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047141574c008249b324302ea6389f75ff1996c75777891c4b0464e1b50ef040fffb1e0f86bd071324d21": "0x0000000000000000000000000000000000000000000000000f405379726f74614e696b6f6c6179000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047141580ba7f98ba82640a6919d7771b79bd1100c2c98d53b391faf80eefca6849ba7c55270f31163f7b": "0x000000000000000000000000000000000008417573416c65780000000000000a40417573416c657835000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471415903495cbc91581406bbe4ba309d9a5347d0e04eff4f03970a9eb55f2dfd146029375cf3ce66f2e": "0x000000000000000000000000000000000008526f757374657200000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047141596b645522e66dd2c4f99c0f8272e38f7169e264234dc13a4da815517564a538382e5828f61fc28": "0x000000000000000000000000000000000009706172616c6c656c00000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047141599a0b4e7422a9ed67f7ef8999964790cf4e6c0815b1a7015e0c55d87f9a25d692d30f54a20a976": "0x00000000000000000000000000000000000742334e4e3354000000000000094042336e6e337441000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471415a1183d2b1701e754981a7d9f137487f5a99c7b9b65beb94d2bd9c7f157550334eb020164dfa27d": "0x00000000000000000000000000000000000c43727970746f4c6f7665720d5a6965642048414f55414c410000136d61696c2e7a696564407961686f6f2e667200000a405a6850616e616d65000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471415af92d249d5d2bd828ac4562ae8e39f5d5b11dc1025a4cafcca85bb229a393ecad83ac2d26e6a09": "0x000000000000000000000000000000000000001268747470733a2f2f317061722e636f6d2f0000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471415c94120ac277390b621338096828389f1fcb1e0141a937060a7fcaf834c7661c0fd57acc1fd5554": "0x040000000002000000000000000000000000000000000c53554d4d45525354414b450000184073756d6d65727374616b333a6d61747269782e6f72671673756d6d65727374616b3340676d61696c2e636f6d000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471415cb248f0f9af445fe56be5933800b45a21ee8e9817eae9f49099fdf4a20076718497092ed43c62b": "0x04010000000200000000000000000000000000000000064875746368114368726973204875746368696e736f6e00174068757463683a776562332e666f756e646174696f6e16636872697340776562332e666f756e646174696f6e000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471415dcd927177e5b7aaee65bf22cdf1f98c91b6c176854d8072f1328e027d2e84d23607b517b1b9429": "0x00000000000000000000000000000000000d446567656e204c656e6e6f6e0000000000000a4044617a6c65514254000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471415dd7df6ad3b6cb94457c23aeab0f27293a09da367f8b8dd0a615c19e6025a2e896d255158683851": "0x000000000000000000000000000000000008766972747567720000000000000d40766972747567726f776565000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471415edbcc783a17ddece01379052888c89928e0352e33dfef3078c9f6401965e0371e87ac1cbecc83a": "0x00000000000000000000000000000000000850726f776573730c49616e2070726f7765737301011963727970746f70726f776573734069636c6f75642e636f6d00000f4043727970746f50726f77657373000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471415eee78443792d00346ebc3380be6816f828d1d1df372c51fbe99c95a321d7510403bb98f067695e": "0x040000000002000000000000000000000000000000001450726f6d6f5465616d2056616c696461746f7200001340616c65782d6d3a6d61747269782e6f72671c706f6c6b61646f7470726f6d6f7465616d40676d61696c2e636f6d00000d4050726f6d6f5465616d5044000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471415fb3d63dadb3c7cbebc314286e78316762fc56c14d7472f22197b227cabfcc894d8a5895ca94662": "0x040000000002000000000000000000000000000000001047494749204d415354455243484546000015406769676965736d633a6d61747269782e6f7267184749474945534d434070726f746f6e6d61696c2e636f6d00001140676967695f6d617374657263686566000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714161735619834be83b8be96d986897797d117987e4368640ffdf32bc967ba7467d012136c22dca33c": "0x000000000000000000000000000000000005636c307700000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714161ff3e3a856b4f6f45d6d4a8639fe14436a978b8a2e5aa3ff7e66273e765498e94c4aa29c8fd41d": "0x080000000002040000000100902f50090000000000000000000000000000000000000000000000000000000c7777772e6973672e64657619496e666f726d2053797374656d732047726f7570204c4c431d68747470733a2f2f7777772e6973672e6465762f706f6c6b61646f74144069676e617465763a6d61747269782e6f72670d696e666f406973672e64657600000d40696e6673797367726f7570000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047141623a7cb16b84b252c01c386876d1675bc75dd5d14e83568ff4b7da0b2a3ed4e85dd5bed380ef143": "0x00000000000000000000000000000000000c43727970746f477561726401010101000011404e46545f43727970746f4775617264000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471416241458d0b2403010f9466b8cd5c4011f48acddbe50369262afc63c91341e75b43149f26e03c732": "0x040000000002000000000000000000000000000000000770616e7661640000134070616e7661643a6d61747269782e6f72671669616d70616e766164696d40676d61696c2e636f6d00000b4069616d70616e766164000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047141624238a93c8c530a242df8ab59ef53f106f818046753ef02bdf49a9d4ca25f1037ef77eb1556b00": "0x00000000000000000000000000000000000c4368616f732050616e64610c4368616f732050616e646100001e6368616f7370616e64612e73696e67756c617240676d61696c2e636f6d000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047141627a7ca07c7aef778dc106e241524180b2594b639d2f0eca4d41b1eb7f9e973c253402a7cd2ed4f": "0x0000000000000000000000000000000000076d6179616b61000000156368657a696c69616e6740676d61696c2e636f6d000009406f72656b6b6969000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714162d191a925aa718de943b956ea058ad55b4ec09eb895a3a9d1034bbcd9c98757d041740b39c3125": "0x04000000000100902f50090000000000000000000000000000000000000000000000000000000d4c65616465724b757361465200001740737461727461726f6c693a6d61747269782e6f7267166c657361697264726f707340676d61696c2e636f6d00000d405441525441524f4c495f53000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714163390f116bec9ccc82b9f35aa042379ed3d348d95985dcbf148e38621ffc7cdf7efbc9a03a9a729": "0x0000000000000000000000000000000000047062650000000000000e405061756c6576656e64656e35000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471416446fc5f8e8b0567e982817a217352323d960736af202f8f9b69e57f213640302862798d2575031": "0x040100000002000000000000000000000000000000000c7a6c7563686b61796161610e59756c69696120536e696879720000167a6c7563686b617961616140676d61696c2e636f6d000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714164b9c1fd02f19d330599dba50b5f3ba0b36f856a761eb3c0aee61e830d4beb448ef94b6ad92be39": "0x040000000002000000000000000000000000000000001043503238372d434c4f554457414c4b001168747470733a2f2f637030782e636f6d1640696c6c6c65667234753a6d61747269782e6f726714696c6c6c656672347540676d61696c2e636f6d000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471416530c8e1e5dda93b43ec7322956d133d41e28758fc64d2da34d2888d93af64eb41f7afa26967961": "0x00000000000000000000000000000000000741727475727312417274757273205374726f67616e6f767300001941727475727374726f67616e6f7740676d61696c2e636f6d00000d40415374726f67616e6f7673000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714165d81fde4784f18e2c0bbb663dd3508bf5538c94db4505f736c8374071934ff8de4b38522620016": "0x00000000000000000000000000000000000101010101000001000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714166843d53ac1c5d58a0219142b23ba0a4ad6d232fbcc3e6f0959a357d40f53ef4635714cedb24c28": "0x0000000000000000000000000000000000204d495353494f4e20434f4e54524f4c207c20434f4d4d554e4954594e46203300000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471416709400d558465ddc20836f2e4b88c1858d1e3f918e7358043b4a8abcd2874e74d91d26c52eca2a": "0x0400000000020000000000000000000000000000000005476162650000194061727275646167617465733a6d6f7a696c6c612e6f7267186761627269656c40696e76617263682e6e6574776f726b00000c4054696e6b6572476162650012406172727564616761746573233239383900", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714167c929df558b1f3c6d12fd424e6cef84c929c04dfe79ac7172fc84db2db0d0b607158d97cf20b38": "0x0000000000000000000000000000000000054354525000000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047141683ada1ddb8e9cdd8a79369cc8a25a7c8dfd684bbd27aa8545cdb458e615ad53d5ba91aa32b3729": "0x000000000000000000000000000000000008406461656c786500000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047141690453f12c9d5688876fc0567bacb2e5e78fe3ab4b8c711343d3d0c6a54e33bcb038dc3d542ae3e": "0x000000000000000000000000000000000017486f67204c6f72647a204e46542054726561737572790c4b75726f2043727970746f117777772e686f676c6f72647a2e636f6d000000000a40486f674c6f72647a000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047141693037ad1bbc4c910eff714e067c3037940f23485a42500956a5997bf5a0e6d80285a165ea7ff72": "0x000000000000000000000000000000000009737567617275666300000013737567617275666340676d61696c2e636f6d000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471416a09d0fe8fce61c09a7a5c8cf9ac932cc4a84b295319371769b54a19d6dae4b0b92778133a99b77": "0x040100000002000000000000000000000000000000001b444f542056616c696461746f7220416c6c69616e63652044414f001b68747470733a2f2f646f7476616c696461746f72732e6f72672f1440706d656e73696b3a6d61747269782e6f72671b646f74616c6c69616e63654070726f746f6e6d61696c2e636f6d00001040444f5456616c416c6c69616e6365000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471416b87c95a1b585d36a98646b16346b02b1be34f9274ff4a42b76521796aefe30fd12bab2e5aafd18": "0x000000000000000000000000000000000003572e0000000000000b406e6f6d616e6f736565000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471416bb7ddd33f15b4828bcee6bb03eccb17bdda4e9ae32a520be410dd8e99c23145c067f93bb342e16": "0x0000000000000000000000000000000000104a6f686e2044656172626f75726e6500000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471416e8fafb94c43111fa6520668dd6ae84ebb91735e7e5086a16873a11256c58d4a2609e69b171974b": "0x0000000000000000000000000000000000075279616e2056125279616e2076616e2064656e20426572672068747470733a2f2f6175646975732e636f2f7279616e766f6666696369616c01177279616e766d7573696340686f746d61696c2e636f6d00000f405279616e766f6666696369616c000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714171684044d2e7dcc72544d5b200e2e791aa6afa994b8bfbcfc51ebe00ad850a01a9977353a79d527": "0x0000000000000000000000000000000000054c6554690000001056767431393836406d61696c2e7275000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714171ca88a3597ca4a1097c82198eca584e8d9bedca6a5ffc1f1eac3c1fb91d0ef4ef313b842b04c3f": "0x040400000002000000000000000000000000000000000b50726963656c6f676963000000196e656875656c6e72616964616e6940676d61696c2e636f6d000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714172675ad2d8df76c947c59725bff412592b6c1ea91e7b356bbaa8dc7412834bfb2a4c81c069e810e": "0x0000000000000000000000000000000000184d61676963616c2041727469666163747320546f77657200000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714172c6fa97a3aa682e494cd7bf392e1b283b46af06353294fc463b52fd5ff8a3655ef7fa57ae82738": "0x0000000000000000000000000000000000084d6174696c64610000000000000e40547275654d6174696c646132000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714172f5474abcf5643a8b5707defe6889dc178861ea7b68861fd0ab5427b54119950e6788afe1cad2f": "0x0400000000020000000000000000000000000000000006596172696b00001740796172696b736c6f766f3a6d61747269782e6f726717596172696b736c6f766f406f75746c6f6f6b2e636f6d000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047141733b5dcae3127ad6c8c82eae6fd28b35a4f5dcac9f1abd1ddc48f2558995de75647a5d628221b4d": "0x040000000002000000000000000000000000000000000a486164657241726365000013406172636530353a6d61747269782e6f7267156a6f656c31306172636540676d61696c2e636f6d00000c40617263655f6861646572000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047141734c607245624b99429cd7476ba80dd82059e739251a8700e975927f18aea27455223e0155a8b34": "0x0000000000000000000000000000000000044d5853044d58531868747470733a2f2f617263686976657273652e6172742f000000000d405f56756c6e337261626c65000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714173c712e406fc7a20a54e1448806b2c0cbdfd5da73198f12554bc972045fc9dd3f2e22b6c5a97c1d": "0x040400000002000000000000000000000000000000000a4665646553616d6d790000001853616d6d796638354070726f746f6e6d61696c2e636f6d00001140466564657269636f53616d6d617233000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047141753ca6a40031261f68651982a6ea4d1308c93fcf09afe6715991f38e750d577f2a264a50a44ce2b": "0x000000000000000000000000000000000005496e5f4b04696e6b127777772e6c696d696e616c6974792e636e000d726d726b40696e6b782e636300000840696e6b786363000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714175f30d1aa274e0cc6017764e7f85421a0fd04dd3c2b916609ac77049eec9d33178dc51ea1d03b5e": "0x00000000000000000000000000000000000d4d6f6f736520506c616e65740a42616c692047616e670000176d6f6f73652e706c616e6574407961686f6f2e636f6d000010406d6f6f7365706c616e65744e4654000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047141768730a1a57b3f1621c276f370bf87cd2a2f783b068d77f5cfa93e40aadee1467eea589ae000624": "0x04010000000200000000000000000000000000000000096b736d6368616f73000000136b736d6368616f7340676d61696c2e636f6d00000a406b736d6368616f73000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714176ef9e475846411e84348ac16a3cb2d199bd5cac4e10f3e304428552c44203ed54919b04e80af0e": "0x0000000000000000000000000000000000075265706c76790641727475720000147265706c76796b736d40676d61696c2e636f6d00000d407265706c76796879706572000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714177d87d70120c0c15a9e357de87525b67cf9ed1d0f06a15a6363665ca1c9f43ff527c87c0945597c": "0x04000000000200000000000000000000000000000000114341504954414c4e4f4445532e434f4d000000126a6b656974683440676d61696c2e636f6d000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471417933400a0288c12e486d93536b8055694c790badd03ad1c868ce5a6624740dfddad1d30e4e60735": "0x00000000000000000000000000000000000b4a4a204d6972616e64611d4a75616e204a6f73c3a9204d6972616e64612064656c20536f6c61720d6a6a6d6972616e64612e6964000000000b406a6a6d6972616e6461000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714179dd96996e1932802e9b1c0fa28781e31ace481a848fe28de05f52d5b4c3889714eddbf1f411974": "0x0000000000000000000000000000000000104c657069646f70746572616e417274002068747470733a2f2f6c657069646f70746572616e732e6769746875622e696f0000000011404c657069646f70746572616e417274000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471417d1a13d5f1f6edf700e71acb30246769cfcd04fdecb96b35bfaa74a629a6515c0031043582d0323": "0x0000000000000000000000000000000000084d4f4d5f484b4f00000013646f6b746f725f31323340756b722e6e6574000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471417e2bd7d0c1ac830dc147d01e94744113a08f1eff356f9a55fa0fee362936cead0d0238e3f395356": "0x00000000000000000000000000000000000000000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471417e4668fc5316ca9661a725c195aef6d9c12fea11f866cb0ea649ee958ddb2de88b4e561295d674d": "0x00000000000000000000000000000000001253656e73656920436f6e74726f6c6c657200000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471417ea820fcdf6ef6efc6a2f393e7206dbccb882cc74dbc1e96a0d678b4990ad768f6e0bcdf3951733": "0x0000000000000000000000000000000000094a75616e6d6130780000000000000a404a75616e6d613078000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471417f2428f049676136029b5b2d1d0ff3a0a4aed8721f480386c8c866d79d86386e5780a6454cd7f24": "0x04050000000100000000000000000000000000000000000000000000000000000000000000000a5f65636172646f356f104564756172646f20436172646f736f00001a65636172646f356f406b7573616d69676f732e6f6e6c696e6500000a4065636172646f356f000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471417f938a8129122a8284492a0069965cc3f671d9e4d583cdee2bf11356546da5fd6a0e0c19f50f93f": "0x00000000000000000000000000000000000641726173680000000000000c4061726173686472653231000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714180b27ec3ca0969990c85597a7a30b57bc3c2a76ea47c370d708dc8879ecbd51c7997ee88feb2576": "0x00000000000000000000000000000000000b4c6f737420536f756c73010d6c6f7374736f756c732e696f0111646965406c6f7374736f756c732e696f000001000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714180fd664cccfede652408fc260667fc591756cebc976059023dc79231650ad542fa0af5f836a2c74": "0x000000000000000000000000000000000006436f636b73001568747470733a2f2f436f636b734e46542e636f6d000000000a40436f636b734e4654000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714181824b302aefc4e54eea4ff693f65e8c7e7804593d04a14abcdd1af82a3a4671ff17fbdb8f03873": "0x0000000000000000000000000000000000114b4e524420636c75622073747564696f114b4e524420636c75622073747564696f0000154b6e726473747564696f40676d61696c2e636f6d000011404b6e7264636c756273747564696f5f000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714181b85c49f4a19a78e8d9c0952b54c45d0483df33c8fa020079cd1787a6e2c5f7425bde850058524": "0x040000000002000000000000000000000000000000000e3136384e6f64652d417269657300000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047141857664d3a630f31ac4e247ed1b3e51a17ab049447b706dd7e9d0e3735ef7e62e155d006cbc0a846": "0x0401000000020000000000000000000000000000000009736179615f6f72670d5175616c697479436f696e730000197175616c697479636f696e73383640676d61696c2e636f6d00000f405175616c69747943727970746f000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471418871df8131a10a56041e8f550869197a24ed9e968eae648692cde7bbc04077114639c249cc0a043": "0x04000000000200000000000000000000000000000000074875626e65740000001461756b6572696e636140676d61696c2e636f6d000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471418a693a77c144adf0cfe5be1f2fa7957855cdeb45af84f6598c581c13644650468d56d162580062f": "0x000000000000000000000000000000000007446174446f74001468747470733a2f2f646174646f742e6f72672f00166e696e616272657a6e696b40676d61696c2e636f6d00001f68747470733a2f2f747769747465722e636f6d2f646174646f746f72672f000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471418b39c8e20e6adbea2c727e5b643684209178c8b6ec45b5ad4567edbe8ea5bd14f2e87ca853dbe39": "0x00000000000000000000000000000000000a4a616d65734c696e6b01010101000001000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471418b47e3024d66dfe628f36dddf8cdb0242104a2531e7d3efd4860a9a4633be69aaf30f63ccb25a5e": "0x080000000002040000000100902f50090000000000000000000000000000000000000000000000000000000b537769737320426f6e640000001c7377697373626f6e64706f6c6b61646f7440676d61696c2e636f6d000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471418b666b3bc75a17480947c3d3093c4b634138253abe071bdc1086af52ac8aae1afe79a7b60bdb030": "0x00000000000000000000000000000000000c524d524b204576656e747300000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471418c421afc6f1c1d600f41077d32f48fd9bb2ad2561fbb6cecd1f19a99f68a50838619534436ce342": "0x00000000000000000000000000000000000741757374696e00000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471418c42cb719c881dd6ed537e76f1ef68764d7544cd7a8be19cbaba2ef8af181090d281d80105fd963": "0x040000000002000000000000000000000000000000000e4c4155524f2020e298aeefb88f000000156c6175726f677269706140676d61696c2e636f6d00000c406c6175726f6772697061000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471418e1b02fb972087a40c6e021d4d80b9b38d850b1c5334ea88b2bcc148d07e83f5be1b45b8ceb3740": "0x00000000000000000000000000000000000e6b7573616d61536f63696574790753657267696f000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471418e56cb66eec57a80acc4b263efe14a089124745b4ae3ccf89eefb0cda261e8b876a7464120d634c": "0x0000000000000000000000000000000000144e5249207369646520696e766573746d656e74044e5249010101000001000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471418e9b69f585d7a7d3c10da0654ed968b149f27cf9db0203337c79b6d86f6741f156598fb7699ab78": "0x04000000000100902f5009000000000000000000000000000000000000000000000000000000074c6179657258000013406c61796572783a6d61747269782e6f726714696e666f406c61796572782e6e6574776f726b00000f404c61796572586e6574776f726b000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471418f0062e466404f0976ce4203c844a11164d1b3f8342ad16a4cc5d99ac8eaae5cd74f4b1cc68c764": "0x04020000000200000000000000000000000000000000085355425343414e085355425343414e1868747470733a2f2f7777772e7375627363616e2e696f2f14407375627363616e3a6d61747269782e6f72671168656c6c6f407375627363616e2e696f00000c407375627363616e5f696f000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471418fa2b57a84d2e6d28d64ebe3a8db9cf3e59929c85a4a049fdea156a9c6df6e94c34bfc08d104f35": "0x000000000000000000000000000000000013414c49434941204b5553414d41204341534100000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471419099c64f6b6cb0284aea4a8a382252eaef972d54ddce03f274004d28fb542d41d9dc2d1789c175d": "0x040000000003000000000000000000000000000000001b4b534d202d20446f7473546f4c696e6573204d756c74697369671b4b534d202d20446f7473546f4c696e6573204d756c7469736967000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471419411887ef1bc949ca4a9b2c4e29603522c99d328c25a962c45aaac963fe90a916c02dce24404f09": "0x00000000000000000000000000000000000c204d616f20736e61696c7308417368204c656500000000000c4063675f6173685f6c6565000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471419522f0465b284216cb2a6e7b4c6451a1a1fcf05a4545dfbda0215f15ad77851be9f7f7e94171e6c": "0x0000000000000000000000000000000000094755535f5441564f000000126775737461766f4074656d706c6f2e6363000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714195e7803308f4eaf7e5f11c88bb727fe14d78f2196451ee57bfe065be7056e4328a3ea68a4139716": "0x00000000000000000000000000000000001050737963686564656c696320417274000000000000104050737963686564656c6963323939000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714197cc6b330ccc49f1cd0839b944fa3be33e09d4248cff45f9ba0c69b3c4063534bbc891026946477": "0x0000000000000000000000000000000000000000000000000b40426c75654775697461000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471419818e7a5e77f11fce81499c6c1257670571c97382c0301d19122da7168495a09546b7e53b28db4a": "0x04000000000200000000000000000000000000000000064d61726b6f000017407461636f747572746c653a6d61747269782e6f726700000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047141984b2e10bc954a21c7a70feac4745c20ffb33960e4b64f9a154ed22fb58fec6ed0a0db885046869": "0x0000000000000000000000000000000000087564697669616e087564697669616e0000167564697669616e7465636840676d61696c2e636f6d000010407564697669616e5f63727970746f000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714199500833949f719f60db3c614a6d05747e20325a2dbdd4e5551c19964410b4f4c669dda1e82f97a": "0x04040000000200000000000000000000000000000000084a6f686e2057750000164068696c646f6c6672783a6d61747269782e6f7267126a6f686e406c6974656e7472792e636f6d00000c40426c61636b33546f6675000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047141996041f72713a580a1e687a718e1ee0ce04385054cd2b23b8f73e0a73b5ba8ce0bba59bed388178": "0x00000000000000000000000000000000000456697408566974616c6969000016766974616c696b3236393840676d61696c2e636f6d00000c40766974616c7567617a7a000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714199f24e2487e567b321ec507203650141d2ec630b967b76ec45dd53d852b9cb25f220dd3a3fa2e51": "0x04000000000200000000000000000000000000000000084e4f564f534942000014406e6f766f7369623a6d61747269782e6f7267176e6f766f736962726672757340676d61696c2e636f6d000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471419caab1fd4cdabfaf287534dd5ead6c0247a1b0d3ada5588e578602c2ed64caa6f6fc2a5efee6f23": "0x040000000002000000000000000000000000000000000d4272696c6c69616e74696e65000000156461726b6d697361343340676d61696c2e636f6d000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471419cdaeb61f1cf1fb9aaa22e75104164e85637433e174dfeed603a9aefdebdcca5d27ea2a445c1e72": "0x00000000000000000000000000000000001054484520415045204f46204e2053541054484520415045204f46204e2053540000167a6163687a69676779393340676d61696c2e636f6d00000d405468654170656f664e5374000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471419cffb91b0e9f1d9e2131969a7a7e3fb17cfabeaaf24e4ffd9648275a675007df661d81594b3e05e": "0x0000000000000000000000000000000000084d72526567616c145265697a612047616c6968205065726d6164690101010000104070616c6f6d61636172626f383032000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471419e56ebac4e0e2b6deef1b2ff187a7da287e1bb52d607937e42d625fc973d4cd06438639d70bad4a": "0x040000000002000000000000000000000000000000000c424c4f434b20414547495300001840626c6f636b5f61656769733a6d61747269782e6f726717626c6f636b2e65676973383040676d61696c2e636f6d000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471419edb33b4c8af5aeaa738e7a216d2c1ce1428e0a27d92d13c04226dcc6b7a7b19db8f5defaa41a64": "0x0000000000000000000000000000000000066b752d6b750000001369722e627579616e40676d61696c2e636f6d000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471419f3c2d4255caa6f62728347d414dc13c2cc74cd0d13e817efd069147654f1ffbcfc90b34e1e877c": "0x0000000000000000000000000000000000104765745f526963686172645f536f6e1143617365792052696368617264736f6e1968747470733a2f2f696e76617263682e6e6574776f726b2f001d436173657972696368617264736f6e34353040676d61696c2e636f6d000011404765745f526963686172645f536f6e000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047141a163f442e4b2bd9aa4852c7108621b0eb5f5f8f8cea3234047089a41e843aec51548bed8135dd5e": "0x000000000000000000000000000000000005546f70650000001574626c61636b363940686f746d61696c2e636f6d00000b40647574776f7272656c000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047141a3b45ae59c7404966b69f1a4704f62fe379ce2ff60a139520330dfb53ab5fb94455c928fae88403": "0x0000000000000000000000000000000000054d61696b01010101000001000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047141a3e1d1d8b70566f4ccb039d696dc732bd51d48022d1cdf4d8efffa839025086962614436c01ff25": "0x00000000000000000000000000000000000673703463330000001c63727970746f7072696573744070726f746f6e6d61696c2e636f6d000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047141a67626b57e204fcd4a31711fb281fc5ed03fd717e4528ac92faf96c204eedd0d6243c144cc7e067": "0x00000000000000000000000000000000001142656e6a6f6e692052696761746f6e6900000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047141a6a978ce3d0119272e18096821e06203efc1c77555b2776299b24b3c73602dfd5bcc6690781a12b": "0x0000000000000000000000000000000000074b75706570650000000000000c406b75706570655f6e6674000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047141a80421515da8bfffcc72d3d698e28a48179a368defd26f420b7dbb123b91405b03ae150f0c18069": "0x040100000002000000000000000000000000000000000d444953432d534f46542d30340e4469736320536f6674204c74641a68747470733a2f2f7777772e646973632d736f66742e636f6d154064697363736f66743a6d61747269782e6f72671876616c696461746f7240646973632d736f66742e636f6d00000e4044697363536f667457656233000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047141a8ac12411fafdb1ccd85718c89027a619892e7abba120a79ed4450f4b782f59cce83ceac03a864a": "0x00000000000000000000000000000000000d5265686162204b7573616d6100000018746174746f6f6973742e65746840676d61696c2e636f6d00000d4052656861624b7573616d61000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047141a8d88fdf65d76e7fefee61c97340537e49fdf7be4ebb5e6f16b2a30e3b8cc54c96f703353e0d270": "0x0000000000000000000000000000000000055465636806666c6f6f72000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047141a8ff977452cfabf1666ca0ab5164b168be0188697042111e9185ae90c13d4a6c197c7209338a34b": "0x0000000000000000000000000000000000065a6571756900000000000008405a657173696c000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047141ab9ea3b498f5eb6424bcc780141fed6ef6cf2d08091a1a98055bd04d7c10b9007d04894b520d729": "0x00000000000000000000000000000000000f53686f776d65646163727970746f010101010000114053686f776d65646163727970746f31000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047141ac1fbed207ef96bd640e992a6d2d245f67a7307f6fb14a4d0481284217b99444dc9b6c9cb3f6844": "0x00000000000000000000000000000000000d4a6f616e4b696e67f09fa4b401010101000001000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047141af418c70ecd35e54e4ef936dae8a5cc6cdb24ab8022a7cd037e618d7bedaa0ea669610ba5e0e07c": "0x00000000000000000000000000000000000742727568686801010101000001000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047141b2d52234edc009738f45bd8f6341dac4486eedaf00f2357cd19b8d4b8f0271c7340d56fe02bca72": "0x040000000002000000000000000000000000000000000c53746f726d5370697269740000001b6d696c64726564616e65796d6579657240676d61696c2e636f6d000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047141b2f4ad5ff2cc79f808b67e6130479626822fdab4428ed964bdf693a1117c2423fd1bd5a1ac57a2b": "0x00000000000000000000000000000000000000000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047141b3451eaa48abc21fe7ebc934f2a7d948b99c431a8fd8a7d79b072ed207de36a980c95e45390442c": "0x00000000000000000000000000000000000673616e696b00000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047141b59abca638b56cdac646de777448f2e8286434406f2491c335604874953bb2276c068be20838222": "0x00000000000000000000000000000000000a4b7573616d2741727400000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047141b8ed26348cab57d4eedde4b28175a6f6f119e646dfd4e47fde33e63409bb06e1f33b1217245fa2e": "0x00000000000000000000000000000000000000000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047141b9caf038b0533985ef5ac84c374d36cf366dd2bee433b8e98b205b9e3abba931f9131bfed3df862": "0x00000000000000000000000000000000000b526164696f4b6e69666500000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047141bae1c6e2aeffc6736e5e3c157d3d1fe30f47d4317fd8f984ac02d891d3f15b18e49fa6de5ed6123": "0x00000000000000000000000000000000000943617074544b313300000014456e646572544b313340676d61696c2e636f6d00000a4043617074544b3133000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047141bbd03cd3ab6347c6817038f23e3b1e7d91f641929205495b7be633fc2247d0bcc5a6f9709a8f82d": "0x00000000000000000000000000000000000bf09f9088e2808de2ac9b00000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047141bcae011029977921b0fa0b1a8e6d3ca06224ada945bd41785e55822a36102e48d584ddbb03e9573": "0x0401000000020000000000000000000000000000000009506f6c6b61424f54001c68747470733a2f2f6769746c61622e636f6d2f506f6c6b61626f74001b63686576646f722b706f6c6b61626f7440676d61696c2e636f6d000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047141bcec27087365f75b241c5dcdd41f564d5ffbc53b8936742796f1d0ac688e42c76233281183de826": "0x00000000000000000000000000000000000a6c616e64736c6964650000000000000e407370726f62696e736f6e3935000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047141bd7316875d7fcf8a0340d617b2e5fecf5813d12bf441eb025f610edf738af8f79a98a9e168f690d": "0x040000000002000000000000000000000000000000000b54616977616e203030310000144079616f6873696e3a6d61747269782e6f726700000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047141bd93ac250c3d818068678e139a4ee538b249b95483d330fae73b3cdb1bcf98394341448e2254c19": "0x000000000000000000000000000000000006415045203204496f6e00001466657261726938333940676d61696c2e636f6d00000d4050756e6b324d6f6e6b6579000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047141be2a3fab16ae5e58429c11f2ff4fc700087c7fdad402d6e97c6df5e73988c3a36c2b6fde7daee21": "0x040100000002000000000000000000000000000000000c5a4b56616c696461746f72000011406172726f3a6d61747269782e6f72671668656c6c6f407a6b76616c696461746f722e636f6d000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047141be91660cfdb5962765d8a5b7f3b10122cf3e3e010bd993eb2f61b47e306fe7cefc8b1fecf6ca579": "0x00000000000000000000000000000000000c6a616b6572756d626c65730000000000000d406a616b6572756d626c6573000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047141bf7451ef7153ca24cd019a2da5b645d6477d1c0237c7c8c36c7bf692e8b89d12a5858f97396194f": "0x04000000000200000000000000000000000000000000074175726f7261000018407374616b656175726f72613a6d61747269782e6f726700000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047141c018fecf61bedd2f7034438a748412760539f824f38f3f9ecbf77ced8716de97c5ade5d2444c8c3": "0x00000000000000000000000000000000000d4a61636b20456e74726f7079001968747470733a2f2f6a61636b656e74726f70792e636f6d2f18406a61636b656e74726f70793a6d61747269782e6f7267197468656a61636b656e74726f707940676d61696c2e636f6d00000e406a61636b5f656e74726f7079000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047141c2d8deb6a6e3afd008cb31b41ba9432b9bbfb2928d7f18dd71606168df3130d56406ccb4e1d1514": "0x0000000000000000000000000000000000085250565f4e4654001472617269626c652e636f6d2f7270765f6e667400126e66742e72707640676d61696c2e636f6d000009405250565f4e4654000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047141c41a9e87e8a611f3667dba518c61e944f337affedc80902c018f24038d71bd055b4a591b783e351": "0x000000000000000000000000000000000008597564683336300000001579756468697368333630407961686f6f2e636f6d0000094059756468333630000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047141c41dc4bdfec08cd34cd97eea8d7958109c6db5e35eb407390555d9d07313768c374358cda816412": "0x000000000000000000000000000000000004434150000000000000094073756d5f636170000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047141c445a00466b4840ee56cfc4d1c1d71960386cd613829467a547ff9e30e060f95291378188c5d21a": "0x00000000000000000000000000000000000000000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047141c60a329d8935ce844cacfd17802a80e37f5db9ef661010285b5bd3c52530edcce377b2188912a36": "0x0000000000000000000000000000000000046b736d00000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047141c62d323cbfdb49f6c80b666f924d2789063014747b0b9f68ba2944a5a837ed43b01cbfc7f626230": "0x0000000000000000000000000000000000074d617269616e114d617269616e6f20426572746f6c657a000000000011406d617269616e6f626572746f6c657a000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047141c7999ba22fd7e800682ab4f191b4213a69ab58265de100201a6589461006c4c415f253612895c65": "0x00000000000000000000000000000000000743424e4b4b540743424e4b4b540000000000084043424e4b4b54000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047141c8477920524dc7b0ea98f531883490cdf295130f08044ec2a2db498f07b8005194a96ff561fd82d": "0x0000000000000000000000000000000000135468652046757475726973746520326b32310000000000000d4043726f75744d6963686f75000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047141c8e5b0e240c90b788faa93b49dc999c0d466cd7f50fcd6f20f31bdd90aa6dc74d082de84763c43e": "0x000000000000000000000000000000000009417175617269756d09626c756520736561000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047141cac1a7ef3f230dafe5958a79fa0df10dd6462aa2bff168669b1254d53d22e435e0190f8736db843": "0x00000000000000000000000000000000000753746f726d7900000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047141cc61414be64fa4946781375b828cd1e774103d484f3c54877b8e88d9689db40ac0e3285fdde4b05": "0x00000000000000000000000000000000000a4b696420446972747900000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047141cdb2accf576d950527361b149506f93445192fa012f9118b4ecf0db2a1570c7cf8a4104db9e7758": "0x00000000000000000000000000000000000552756479105275647920436f7272616465747469001640726366726f6d636c653a6d61747269782e6f72671a72756479636f72726164657474693440676d61696c2e636f6d00000b40524346726f6d434c45000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047141d06728f5cf68e4a96815bbe365675730b16ac7f3d50224673ac974f548ead737ef65e6d6a51c965": "0x04000000000200000000000000000000000000000000094369707269616e69000015406369707269616e693a6d61747269782e6f726719746865406369707269616e6961636f62657363752e636f6d0000094043697072694941000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047141d2126e97da297743a969caac23093c1575d9a76f274406e59f2b1422f52930924b47ea87e641960": "0x00000000000000000000000000000000000b54657874437572736f720c5465787420437572736f72147777772e74657874637572736f722e696e666f0015746578744074657874637572736f722e696e666f00000c4074657874637572736f72000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047141d235a8aff868b2764038661dba05e6560cd16e0e7f6a3c6aade4438b3206c656b198c447f8a7a7e": "0x00000000000000000000000000000000000000000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047141d2375e335e2ffe0c000439b3c05aee26b38c1116874efa9e7cd6cb73633c9aece8287d79ca84927": "0x00000000000000000000000000000000000a43726167204861636b01010101000001000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047141d2acfefd1a8740906d588674d7859e56ed1ddcd2e5bde1d56ae61294b842a2ede11f7cab494771a": "0x0400000000020000000000000000000000000000000014474f4245524e414e5a4120504f4c4b41444f5400000019676f6265726e616e7a612e646f7440676d61696c2e636f6d000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047141d31100cfcfa2db62c01c4cef5058330f7f9641903c18f4faadfaf6f7756eee49d27b9ed38cce66c": "0x04000000000200000000000000000000000000000000067a6c617461000016407a6c6174612d6b6d763a6d61747269782e6f7267147a6c6174612d6b6d764079616e6465782e727500000a407a6c6174616b6d76000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047141d3a4b2bf76f654ecac24813f1c9e61fc9cc2500bf4eb8b8d9af7548714cb0b1c1ba4785b46bb37f": "0x000000000000000000000000000000000007486f686f686f00000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047141d462405631809fa2aaa5497ddea7e16416a7e7cd668565cf10f67763d0a9143dbbbc1104cb19817": "0x00000000000000000000000000000000000a44756d625f42656c6c00000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047141d4d1c3fe955b6e940c6413e8373b0e702dd0e04ecf51a6c785e76dd910b5907512969f3cdb9702a": "0x00000000000000000000000000000000000000000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047141d4f0e009a9528d0f2695f946087950cf6d6082c331294f31d23ae54ab2dfc3739fb4def83676e23": "0x0000000000000000000000000000000000054d65746100000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047141d6bdd6d8cc672c232ad1a9e5ecaa5b5f3b88bf41e24eee2591dfd5d3a53d9c09a73bac517f28a58": "0x0000000000000000000000000000000000066b7562657201010101000001000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047141d7259e4eafa026b88e89854ec5f225c9a3b8889d4b1afc0cf6cf473d4265a96463c08cccf38905b": "0x0400000000020000000000000000000000000000000008316b766e6f6465000013406461766534343a6d61747269782e6f726700000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047141d77b5b5e1a11bfd62a79f3b924342c4f634d8ebdf77f50ac051d41387a72d22f2f38155762c125f": "0x040000000002000000000000000000000000000000000a4c6567696f6a757665000000146c6567696f6a75766540676d61696c2e636f6d000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047141d7c0832ef85bb40ac8861de74cdf782c8261d2c36d27cdec982688f6d03311e53cfd65402211856": "0x00000000000000000000000000000000000000000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047141d9735b2d16e21311c11f14c57d6a787a9a317691e40481a394591b7af72e22407016b498737ae38": "0x00000000000000000000000000000000000101010101000001000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047141d9986fc3246a26b4aa5e51e6ca0b24646f378404ad16b7f1fe9e0ec864147011db66265813fa02e": "0x000000000000000000000000000000000012566c6164204973204c6f766520f09f92950000000000000b404372797074756c6c6f000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047141d9e0e4a748d5f2cc805058130871797c503fd545ffeb106c470953d95f88c6814bf2ecbc0c9986f": "0x00000000000000000000000000000000000c42756773794d61726b32320000001662756773796d61726b323240676d61696c2e636f6d00000d4042756773794d61726b3232000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047141da8bd150ad49b557886c5a642b89daceb2744feb76cf20cc06603fa2a652cc8be5e5e155f57e33f": "0x00000000000000000000000000000000000c61657468657263726973700000000000000d406165746865726372697370000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047141dd245eb6059ff64e29c5c2a82d191bab4e3d4a573d0e5743b19cd8ccd2b4a978bdc1784d5af1c7b": "0x00000000000000000000000000000000000f42696e616e63655f6b736d5f33320f62696e616e63655f6b736d5f3332000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047141ddfd86abf974afab47109f622b8dbf0bbcf84277b807130c085082546669b0d15c739843e09c109": "0x04010000000200000000000000000000000000000000086b796f73616d6108626fe288826869001440626f646869736d3a6d61747269782e6f726715626f3668694070726f746f6e6d61696c2e636f6d000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047141de11c43602580500e15e7844eae688a5a8d5bb2239878e14e49c73534a0a3fe258e0869e9ed6727": "0x00000000000000000000000000000000000f506f65706c6527732048616e642001010101000010406c616d61696e6475706575706c65000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047141df3fc920874707bdc5d17441dab98682c0b6d8819768ce2aa4674fcb1ad68f609b7c620ad45ba4b": "0x000000000000000000000000000000000009706974696d696e6900000019706974696d696e692e646562756740676d61696c2e636f6d000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047141df6123c2d60f917b2471fd517548674e0710bcdc4961033f6240c4c5c94cfbe38cd032a493c5e74": "0x00000000000000000000000000000000000a4c6f72696c6164794f0000000000000b404c6f72696c6164794f000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047141dfc2330c656d5231a890513e2c8835cfc12813248806f24436f757f0dbcd8696a7f56bfa2c3f17f": "0x040000000002000000000000000000000000000000000a4541524e5354415348001a68747470733a2f2f7777772e6561726e73746173682e636f6d16406561726e73746173683a6d61747269782e6f7267146561726e737461736840676d61696c2e636f6d000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047141dff89fb25833ea0a616a89a50c3a144a2af6202dd4550d067dce77c8775cf713cc6e34b93a00b45": "0x00000000000000000000000000000000000b417274656c6c656f757301010101000001000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047141e0159188b70dcf6941f8d212a457540ff86a877ea367c1a74c43a58e7d3382a987ca12cae0f7524": "0x000000000000000000000000000000000011446174205068756e6b79205661756c740f546865205068756e6b79204f6e65137777772e6c75636b796672696461792e696f00147279616e406c75636b796672696461792e696f00000c407468657068756e6b7931000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047141e023a512a423fadae0d9af68f58dde7e3279b2dc61e51c29509b10e29605dbb6df2fcddd083ad22": "0x000000000000000000000000000000000009776572747971323000000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047141e1bdb5f0bc06203e8072c43338f9819be9bce372ed1afd9e945d4c827d4e3e02cfb7b32122df764": "0x04000000000200000000000000000000000000000000094e616b6570656c6f0000001862617279636865762e64696d614079616e6465782e7275000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047141e402acb5899dbe10ccbbc7077de681489e3548876c3106219899576c0b9e3a9abfc93559449da61": "0x0400000000020000000000000000000000000000000008476f6e74696a6f00001740676f6e74616a6f6e65733a6d61747269782e6f72671c6172747572676f6e74696a6f4070726f746f6e6d61696c2e636f6d00000e406172747572676f6e74696a6f000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047141e495b9d3175bbcf109e87a012b2754d0b23501fe1fa775db374927f09c228f07948f81ad84bf617": "0x040100000002000000000000000000000000000000000e5061756c2057696c6c69616d73105061756c20502057696c6c69616d7311687474703a2f2f7061756c772e74656c13407061756c70773a6d61747269782e6f7267147061756c40626c6f636b736d697468732e636f00000f407061756c7077696c6c69616d73000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047141e517fa60da3439f60fee6404e47fe7fc88c2df8f2ccbafcc2bb76501c0f082cedac9586cb7cfe3a": "0x00000000000000000000000000000000000b53706163654d696461730101011961626f6761646f7363726970746f40676d61696c2e636f6d0000104044616e69656c3636363332353734000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047141e5ed2f050989443765e6df27b038557938e92d267e4d3e9a7826f3e1c628443b72c54ccb2530f7b": "0x00000000000000000000000000000000000c4269742e436f756e74727900000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047141e6c109558238bfd8cf8184ab08b4b112452b90cfbe958b9573939bd0dfd0dc78b77f3248f28c025": "0x0000000000000000000000000000000000000000000000000c4050617261436861696e7a000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047141e76c389661c3a415cbf9588da096c69d2c6f3cdedbbf146d31f0f43f39d251d09f9b368aad1a852": "0x0000000000000000000000000000000000076c696267656e104c6962726172792047656e657369731368747470733a2f2f6c696267656e2e66756e0000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047141e81c54a25bd302dc09ed6b82e56f934bddde307fd655fc512c88c9a66ab77325d6d8d804de95e0b": "0x0000000000000000000000000000000000054861687a0b4861687a2054657272791568747470733a2f2f61727672746973652e636f6d000d6861687a356440706d2e6d6500000b406861687a7465727279000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047141e88363895c100068c4bf3ba9633b121af862532bb08432c3cd450f363e04a2862b07d50abea775c": "0x000000000000000000000000000000000005616c616e00000017776a6837363232393032313540676d61696c2e636f6d00000c40736c6976657266666f78000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047141e9839b3a4a537a7ee8d75dede514ed1aab7fb1db5e6a959c3ee250062aaae12d463a7b8329d1224": "0x000000000000000000000000000000000009536b79204b696e6709536b79204b696e671c68747470733a2f2f736b6d702e7375706572636173742e636f6d2f0012736b79406d6f6465726e73746f612e636f00000d40636f6e73756d6572736b79000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047141eed9dff4cea873e1635a4853f034ba42d82dee7d8eb4eedead8c2350de115251dbd6d4e3b65c713": "0x00000000000000000000000000000000000b4e46545f5061756c6965001d68747470733a2f2f6c696e6b74722e65652f6e66745f7061756c6965000000000c404e46545f5061756c6965000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047141f2628d8321b371238be8006279f7e6c45bea9c49ec6148ff405719f6b66357308246a04d8f8dc70": "0x00000000000000000000000000000000000e506f6c6b6120506f74696f6e730017687474703a2f2f706f6c6b61706f74696f6e732e696f000000000e40706f6c6b61706f74696f6e73000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047141f2feeea09705452f6dc9f6798b0673697a24cc012c6c63b2634557893f3231ac186afddbb421435": "0x0000000000000000000000000000000000000000000000000b40656c63696432303737000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047141f4321336da7ceadf4d95d4c5c0131969148d3a16b3d95ab3d051771d971a1955d7e745b0a3a4f16": "0x040000000002000000000000000000000000000000000e5044505f56616c696461746f7200001440706176656c64703a6d61747269782e6f726718706176656c2e627574656e6b6f407961686f6f2e636f6d00000b405061756c4241636944000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047141f48bf37f549334442c6245ef5eb308a001e79ad19006295ca4f647f53cf848a654986bcface4042": "0x04000000000200000000000000000000000000000000064942495a41000013406962697a61313a6d61747269782e6f72670f7265672d67616e40676d782e6465000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047141f4abd8814aa23d512e468b6c0ef22342134f181810fc0adc14a6aa964e9d2e8d6d89840b69b603c": "0x00000000000000000000000000000000000d53656143726561747572653100000000000011407365616372656174757265686f646c000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047141f5112fb03b23ddef2a85c638724c62596fd6b39b96940e8469b445fe79c6416e00d055ee895f211": "0x00000000000000000000000000000000000000000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047141f5305062ef877dbe24f4ca2f10d6a709a24b0cc692ac7be7f8d273b20301b48ad9ed4686b7fd319": "0x00000000000000000000000000000000000643495649540c4f73636172204369766974137777772e6f7363617263697669742e636f6d00156f73636172636976697440676d61696c2e636f6d00000b4061736369695f626974000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047141f638d3271ed7e11f246c69b8f8c849cce66563b2e98d4d92c3d310f0a71c961f52d998faf83f67e": "0x0000000000000000000000000000000000084f6479737365790000000000000e404f6479737365795f4c616273000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047141f7fe908aea4a3c53289d9f38247655a5018d093324d3fd1b9daeccca5336b69577ae6b466576b1c": "0x00000000000000000000000000000000000d414d45524943415320322e30002168747470733a2f2f747769747465722e636f6d2f416d6572696361735f325f30000000000e40416d6572696361735f325f30000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047141fb2ba94e04f61c026a31499d0df85f8053df28ee11f7c0a3715892fd57a92b4edcbbfa322475a4e": "0x00000000000000000000000000000000000664696b6b7900000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047141fcece1cdd847b0ec86205a2ca8d23217fda44d2d969447b9c02ef7949442473c2991a6e60212f04": "0x0400000000020000000000000000000000000000000009475247544e534b4d0000000000000a40677267746e736372000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047141fd0382f79e2a2d7ba55c080cad203ee8e64deb867ffd6c628a36159aef2bd90e1ca99669218d566": "0x0000000000000000000000000000000000064a756c657301010101000001000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047141fd33ae9ac7ec1387e3301e524b5134478f3705cf85e4999ae44f8ecf7732884ae18c3480e2b9a56": "0x040000000002000000000000000000000000000000000b5374616b6520466f7274000015406770617468656c613a6d61747269782e6f726715676f75726176407374616b65666f72742e636f6d000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047141fded061878099ed6cbce2cc9280bff6f25382a49f2f6ae459d8c96e53e72fbb7de120955918df14": "0x00000000000000000000000000000000001042616e6e6572205468656f726973740b43686164204368616f73000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047141ff46b051efecfe4806369b4f04792b7bd1a0d8586b7aa528591ba732362e3fb3d52d7b01e741b18": "0x040000000002000000000000000000000000000000000773336b7269740000184073336b7269743a6661697279647573742e7370616365000000084073336b726974000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047142018212ed22c14c0a44871a6a8764d496fe18d5f9044e3c62cee35d0b30ed9e707227bfd8a9c0711": "0x040000000002000000000000000000000000000000000b636c6f636b636861696e00001740636c6f636b636861696e3a6d61747269782e6f726717636c6f636b636861696e687140676d61696c2e636f6d000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047142022778741b4653e1434dd9ad7d65aa4fd7befb0af4819a25a022402d55489fa8c290c97b38df230": "0x00000000000000000000000000000000001a456c656374726f6e69632047616d696e67204361706974616c000000000000104074686567616c6c65727931313131000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471420326aeae6bc2643a4c7753db70defc6fdcc8efc9c9c050207648b35b7e52213f8963b03e4f56c0c": "0x040000000002000000000000000000000000000000000a736b79657264656b6100001640736b79657264656b613a6d61747269782e6f726714736b79657264656b6140676d61696c2e636f6d00000b40736b79657264656b61000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714204538a0dc29db896ad41858c3abc9bce8dc8ed3b789112bad138dbf9c62472aa881c6ce1b985204": "0x00000000000000000000000000000000000c50523046495442554c4c59000000000000114050726f66697442756c6c7931303530000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047142050d45992f4c9ef2652c2a0824e6d3803d9616e5499b32741fe224108363f2423e5063978885f07": "0x0000000000000000000000000000000000074b7573616d6100000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047142055e641717d8d1e567c29ba7c8504fcf16d91413a5a71f8e81c33752c743506cd26198997f48421": "0x00000000000000000000000000000000000467756100000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047142056c8f9b2090920dc64ebe91ae1dd904651525eb5fd91eb0abf458cb0f5986158803e0075604153": "0x040000000002000000000000000000000000000000000a546f5468654d61727300000018746f7468656d6172733230323240676d61696c2e636f6d000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047142057c2e1894e9a819e92823bda563f6821bc3b7af00917608d454dfa89de101414ee0b51ac3ab57f": "0x04000000000100902f5009000000000000000000000000000000000000000000000000000000045450420000001a676572617264706c616e656c6c657340676d61696c2e636f6d00000f405072696d6572426974636f696e000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047142067c893ca23078d2899477496b6c390ee6a83d1e533d860d1ed9d3093e9f74103185879c65de25b": "0x000000000000000000000000000000000007726f694c656f00000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714206b45f2fa65a57512b21d2798eeaa9401e833534b50cdc8cb63dba399374d291f223b691b35de23": "0x000000000000000000000000000000000009736861323261727400000000000011407368613232626c6f636b636861696e000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047142073848901eac9089068ef7e2275c53204ce2f7fdc06eb8c5b2b7d6e67a137738dbf9708f207ff23": "0x0000000000000000000000000000000000064a77617769064a776177690101146465636f6c6a656e6540676d61696c2e636f6d00000a404172744a77617769000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714208d340a192a7ce08433eae795936e63871cbcf0410517d1dad4755f2da4a6d88c1cc1c589b8e86f": "0x0400000000020000000000000000000000000000000013535452415742455252592d5354414b494e4700001740737765657462657272793a6d61747269782e6f72671d73776565747374726177626572727933303240676d61696c2e636f6d000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714209e98ff9424a50460750d915c81e3c139cffb0418c1c712b3ed7486694f4ab51032735d4a7bc628": "0x00000000000000000000000000000000000c6b7573616d61686f6c69630000000000000d406b7573616d61686f6c6963000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471420a0096c7425466822f00d3001f42ca632c44bc08b5832edfc5b68f71bba9a5489e72bbf36759675": "0x0000000000000000000000000000000000134b656e6e792773204b696c6c2053686f74730c4b656e6e2053686f74747a0000156b656e6e73686f74747a40676d61696c2e636f6d000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471420a09cd983d185ada625107ed5deb9bca0d319ec0614f4cec7442d7d1d834c94edb2ca33dfefa041": "0x00000000000000000000000000000000000c4e696b6b69205269786f6e124e69636f6c61204a616e65205269786f6e0000176e696b6b697269786f6e407961686f6f2e636f2e756b000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471420a8c6d581b4662724bd4f1c895eeef95b593114f9f5ba0abd74c95532defed6a94e56fbf4aba642": "0x00000000000000000000000000000000000a46414333205354523800000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471420acc90488da905fc699cbb879646f36ca046a3d26df97d1c83ed24d2a4975d823ef00ca4c94f509": "0x04010000000100204aa9d10100000000000000000000000000000000000000000000000000000c4465736372696265646f740c4465736372696265646f741d68747470733a2f2f7777772e6465736372696265646f742e636f6d2f00166465736372696265646f7440676d61696c2e636f6d00000d406465736372696265646f74000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471420e84b09cc5488ab56025b6817d74310f334c8c7b2baa3cf708f6c1501aec104d91d951751f88643": "0x000000000000000000000000000000000007422e492e432e13736972206261736564206964656e74697479000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471421101bd08c63245f043a5cddc14c4ad1fbf90999e4efe595993c71e0be149400f5f1e6b3e073050d": "0x00000000000000000000000000000000000e4a6f20706f6c2077616c6c657400000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047142132d2b9d69b1260a8300f53d9cda28b136491a9b18b937eae584f7f08fbb6aac29e0ea38e38f864": "0x04000000000200000000000000000000000000000000104c45545241534352495054494341530000001a6c657472617363726970746963617340676d61696c2e636f6d000011404c6574726173637269707469636173000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047142137b4e662fa80a05a37c441df3f0fed7ddef5581ff70437b00fb071e0b09537caca8adc4354913e": "0x0000000000000000000000000000000000094e696b6f76657261135665726f6e696b61205361727661736f76611668747470733a2f2f6e696b6f766572612e78797a2f000000000a406e696b6f77657261000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714214241a7a6830640485a526526a8eafc2c5705aa658cbe9c28fa11d29b0595e9117631ad7b370f61": "0x0000000000000000000000000000000000086c554f536b736d05416e6e61000000000009406c6f75736b736d000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714214343ca4a50f9b586b151fa5df9e1c7f5530a1ce12aeb4957ffb6d2e15304fa6b9b5f40bb3ff31b": "0x00000000000000000000000000000000000a4e696e6a614d7a666b0e566974616c6979206c6172696e2168747470733a2f2f73696e67756c61722e6170702f73706163652f476562583600146e696e6a616d7a666b40676d61696c2e636f6d00000b404e696e6a614d7a666b000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714214a284ee9e9b01cd61813f456c8f11087d572921c67afff25605aa712899d6a6b04cc42c3d2d417": "0x040000000002000000000000000000000000000000000647335251300000124067337271303a6d61747269782e6f726719673372713076616c696461746f7240676d61696c2e636f6d000007404733525130000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471421545827f452a76be49cd2b1bb9e68033d664d63b4776bc51f900147cdeb6f009fffa8c1d497ae3d": "0x040100000002000000000000000000000000000000000d536f6c6f53696e67756c61720000001c736f6c6f2e73696e67756c61722e61727440676d61696c2e636f6d00000e40536f6c6f53696e67756c6172000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471421610a341cde1430ea466b06c8c16712d05c5f607b740a39b72f8356f175320697df6f2a73dbcc4f": "0x08000000000100902f50090000000000000000000000010000000200000000000000000000000000000000085669746135363700000017766974616c696b647a656e6e40676d61696c2e636f6d000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047142162588dd88d3a33aa48a9775be7af0521acefce054dc7e9e461814dc167a5cabf52aef8534d8249": "0x0000000000000000000000000000000000194c6520436f6d7465206465204d6f6e74652d43727970746f0d4d6f6e74652d43727970746f0000126d6e746372707440676d61696c2e636f6d00000e405f4d6f6e746543727970746f000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471421667555f2586f1cc852bd64d95e1c2fc164ba7ee6c2cce6e87ff8cef81c60940d46f710ed712b7a": "0x04000000000200000000000000000000000000000000066b6f757469000012406b6f7574693a6d61747269782e6f72670e6b6f757469406a6b76632e6465000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714217d6680e09965aab2b62cbf89a7a9265639614f153be16189006b3c0b51cce22227f4af703c9e1b": "0x00000000000000000000000000000000000d4b7573616d6153656e646f680a416c656a616e64726f00001a616c657465636e69636f706331303740676d61696c2e636f6d00000b404b736d53656e646f68000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714219805b19867f93320fee6eafec3719729d9c5ca944da46b05443e2e8f6bf199e0011cd0e2c7e148": "0x00000000000000000000000000000000000f506865656242206f66506865656200000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714219c4cf4d922a8a65e6943dbb9c8cfd53377a67307290efac1aff4aa23f2862bd8640af3756f792c": "0x0000000000000000000000000000000000174b72697374656e207c20573346207c204576656e74730f4b72697374656e204ac3a46767690000186b72697374656e40776562332e666f756e646174696f6e000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471421aad0a24a729734c0b881e2db47fb95982cd5c364b87e6cdf5a5c8a336d980156623b53815c597b": "0x0000000000000000000000000000000000054b494c4e054b696c6e1068747470733a2f2f6b696c6e2e66690010636f6e74616374406b696c6e2e666900000e404b696c6e5f66696e616e6365000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471421bd505b865a64bf380b24a4886b392ee4659b85f5605cdfab3eadce66eaadd848c37f4fde65fd06": "0x040000000002000000000000000000000000000000000c474d2050656e6775696e7300000015676d70656e6775696e7340676d61696c2e636f6d00000d40474d50656e6775696e7331000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047142200b6e2483bae501aaf37daa4afffeb0d84c47f52330d8293ea648e1bba5fe0e35355057e63c167": "0x040000000002000000000000000000000000000000000773656c6265720000164073656c6265725f61693a6d61747269782e6f72670e6f70734073656c6265722e6169000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714222fa12fb4681a4d0e47ff458bb2f80c4bc89a6a7bd022a555e9c1bc719726f475f8a1841428832f": "0x00000000000000000000000000000000000761706f6c6c6f084e6568656d696100124e6568656d69615f736f72616d69747375186b72616d65726e6568656d696140676d61696c2e636f6d000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714223452b8432e93285edc25673a48cda235c2d234b8cce6fc441c1f2edaca141226509d4e34443f32": "0x00000000000000000000000000000000000d50726f6a65637420495a415205495a415200001b70726f6a6563742e697a61722e6e667440676d61696c2e636f6d00000e4050726f6a6563745f495a4152000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047142237b569888e1b73789b24f57aaf20f362378bb7b2e560920a5c09e18d292ae991365283fbb63d46": "0x00000000000000000000000000000000000a6b7573616d61676f6400000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714223a4a6652ff6ba41ec5e682f355b27a4d5a5cc933edcdf3a4909fab848b5c36ca82c6ed9518404e": "0x00000000000000000000000000000000000000000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047142246a94b347c9dd6d4af1aa1af17d814c5da505868f6c55d53371fdf90d774e5d61d6e02a29bde35": "0x00000000000000000000000000000000000c467453342e2e2e664653300000000000000d406b696e676d6f6f73616d61000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047142246aa733317c875da16e9adb79c6c6264ff8c115577bb33b4ee54e8dc9abe25a91ca670b61bd552": "0x0000000000000000000000000000000000116d6f6e6f62726f776d616b65726d726b01010101000001000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471422501e6d8f21e9dd5e97f331813198763da88ad2b1f5deb3f42373a93e8895c43de399aa6255da47": "0x040100000002000000000000000000000000000000000e47656e657269632d436861696e1554776f20506562626c65732056656e74757265731968747470733a2f2f67656e657269632d636861696e2e696f1a4067656e657269632d636861696e3a6d61747269782e6f726716696e666f4067656e657269632d636861696e2e696f00000f4067656e657269635f636861696e000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714226c1e0df53526ed80460dbf1dcc3ed518c81067d27eb8278a7a1abcd834ffc79dcc1c35e4a9b64e": "0x0000000000000000000000000000000000064241444552001268747470733a2f2f6261646572792e636f0000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047142285d6ef6ff9cb66120dbd220521490559af15d7fb3b6cd95c313d06180901d2de5a54e63d9cfe22": "0x040000000002000000000000000000000000000000000f395374616b65206279203947414700001840397374616b652e396761673a6d61747269782e6f726717397374616b652e6b7573616d6140396761672e636f6d000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714228f1b7216fcfd78ecbb4ad02852dc96234c83eb42528d08e17ef8e787f503caee5fa0d687d74025": "0x00000000000000000000000000000000000e416c657843617074517561636b0000000000000f40416c657843617074517561636b000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714229b18b3f2754f1a429599ba5f521844f2332524dec987f9cfb116a2570f83b2417184af0c74ab13": "0x0000000000000000000000000000000000064772657461001768747470733a2f2f6465636f6d3838382e7370616365000000001140526f636b657442756e6e79426f7373000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714229ce4e5e00a4f0b1e6ea78e3190ac2cfde9c0041ea7a0e1f7b89d52f4a58f01f69258150b782466": "0x0400000000020000000000000000000000000000000006736e61696c00000013736e61696c407473657276696365732e6573000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471422b4e5d0ac25c3f4f0221438819364133d39e26672983929d4656719d10ab15c8f974b8856daf664": "0x000000000000000000000000000000000005466972650546697265010101000001000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471422c077d1ea9a54d260f2cec43064a352b55aec95917a2935c01ae5d9ddaa47d8063991d65b4b9450": "0x00000000000000000000000000000000000a46616d696c796d616e00000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471422d261d77c92c974201f968f24fc0df93fe98dab905ff103d00a9a232329bfe78c22663dbe60a12d": "0x00000000000000000000000000000000000b4441524b464f5245535400000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471422dad67368716274fa24d4027d0a467580d44b1c89896a8bc1bb9c77d1a29f555c4ba85b7241d84f": "0x0000000000000000000000000000000000095468652047616e670000001674686567616e672e6e667440676d61696c2e636f6d000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471422dc4c22ba0bc0065c05d5f192c927b30b33c85470b53474f2a736a01c3c5da905384329a430f22e": "0x000000000000000000000000000000000007446a7562726500000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047142305e79ce427e9ee14173ee9728c9186c8e72b474dd743f18b0169106f8d63e2973bd9563882347f": "0x00000000000000000000000000000000000968616d616b61676f0000000000000b4068616d616b61676f78000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714230d1532b07653236895ad261e06f09bee24fbadb2586f4c5ef811ab95debdf1c683025e12665858": "0x00000000000000000000000000000000000f42494e414e43455f4b534d5f31320f42494e414e43455f4b534d5f3132000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714231960a7d766214bac5090f086d4848d1830e5aa59349a24ccfa5dc9bbcbf97580c26371df64d904": "0x00000000000000000000000000000000000766347573743001010101000001000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047142319f3e78aede826d4621034776e25cee77bb87bc6a14a8e0f74dc45ec194bfb8ce7fc5f97c42406": "0x00000000000000000000000000000000000a486f6f6b61486f6f6b00000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714233517e12f6d46687ef6ecff86959a7b564427a3b66d0352b3f513c990accb1a836a41322d08d311": "0x000000000000000000000000000000000005526d726b0000001a63727970746f7477696e4070726f746f6e6d61696c2e636f6d000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047142337f11734e7573816e0eeb71e92b68959e490c6e0c5dd54a61fb9faabbdfbb4fd7a6ae353dcf573": "0x00000000000000000000000000000000001653616e74612773204c6974746c652048656c70657200000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047142340baacf03bc2b65865da029ac7366bc43ae9d19382b3a85f49d2a660fef29259f9bdd742767d0c": "0x040000000002000000000000000000000000000000000b4541524e535441534834001668747470733a2f2f6561726e73746173682e636f6d001367726f77406561726e73746173682e636f6d000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047142340d0950ebd480968fae6be10c90d572388d42129e074005005baf68d116a993073c5648ec78865": "0x0000000000000000000000000000000000064b414e525900000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471423439dff64c47d6062f21f6587843801d599ed5855ae0ebdd2a84c822919e80cd6f12899e5088772": "0x04000000000200000000000000000000000000000000064c65676f73000012406c65676f733a6d61747269782e6f726711706f6c6b616c65676f7340706d2e6d65000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714234aecb53dfa52ee846537d237047bc2784332bde7c2495a8ced463b2470834c989ab0221880b53e": "0x0000000000000000000000000000000000084d414347414e470000000000000a404d414347414e4778000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714235333782a45d3df229f2896c2bd6f30162c9cc0f5899432515f2cffed36a4dc6b42d48bd2b2910d": "0x00000000000000000000000000000000001044454144424c41434b434c4f56455200000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714235e6cc48616ecf948df9c1a60044840351ef0fbe6b9713ee070578b26a74eb5637b06ac05505f66": "0x00000000000000000000000000000000000e537472757473656e6b6f415254074e696b69746100000000000f40537472757473656e6b6f415254000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047142366851b398c75ad02f6ed445ee9bf4e2f4b4c017439de5df61f85059a05faf2d0bce28d7ae2a755": "0x0000000000000000000000000000000000055333335200127777772e736565722e65786368616e67650000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714237b203fe8adc4e71c351b39b792e67cf1251e87877511ce1d302a4048202a7a66f130324c39c171": "0x000000000000000000000000000000000008535552494b4f560000000000000940564f4b49525553000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714237b38e4959de64e265a775a6d7ba9de83f9584dafe39e8329019c1e881b4c5097048fa72d392369": "0x0000000000000000000000000000000000057272656d00000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714237d0c1537de97bd0cbdd520a7494178d304b7cd4d6b5ab879a78153d9e594f4900b615caefe5908": "0x0000000000000000000000000000000000175468696e6776616c6c6120496e766573746d656e747300000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714237dfece766977faf655bc5071b58f4e4789e92567ede362496ffc8ef0f0d9ebc00c2ad4c57bfa7f": "0x00000000000000000000000000000000000d74776f70626c7374617368311654776f506562626c657356656e74757265732e696f00001b61616c624074776f706562626c657376656e74757265732e696f000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047142380d19831504ba65a2d8e3ab4f6b9d9e0f920d4d2b6877be7ee0b1b28c2f6a8d83751a143510b1d": "0x0400000000020000000000000000000000000000000011686f6c64706f6c6b61646f742e636f6d00001d40686f6c64706f6c6b61646f742e636f6d3a6d61747269782e6f726719737570706f727440686f6c64706f6c6b61646f742e636f6d00000e40686f6c64706f6c6b61646f74000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714239d9993b7848d1956f5560a9a7cebbc2b81e92c3f080f384fc7bc0cb8a20484bc42cdcd423b7863": "0x040000000002000000000000000000000000000000000b5354414b455a494c4c410000154064637a6f696361733a6d61747269782e6f72671364637a6f6963617340676d61696c2e636f6d000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471423c2022a748dbc54406bfcf1fc5e75a39525555d86756e304fbc7fb4d74f49feca2f02cee457167b": "0x00000000000000000000000000000000000879696e7a68656e00000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471423d4008003cb78a9582c6d97aa93263387550545127dd79d0bb69e0b2f792867660b8761b8551a1f": "0x040000000002000000000000000000000000000000000b4d59544849434e4f4445000018406d79746869636e6f6465733a6d61747269782e6f7267166d79746869636e6f64657340676d61696c2e636f6d000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471423dccf7b667b32e5dc399b0b033525131eac94bf1432ec9112cc69862dac20a16c3462ae8c64c017": "0x040100000002000000000000000000000000000000000e4b494c542050726f746f636f6c0d424f544c61627320476d62481068747470733a2f2f6b696c742e696f000d6b696c74406b696c742e696f00000e404b696c7470726f746f636f6c000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471423e2879b116fb58ca6e782e566e272302b2f81d98f84a883eca8dcd86ff3c05ba0a98599fa86a516": "0x0000000000000000000000000000000000044a65680945766768656e6969010101000001000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714242a4e67e17b982ad890e8221d99486fbacc20023108a5a1411cde82171d65a531495b7a47d5bc76": "0x00000000000000000000000000000000000c757365726d6f642e6e65741447656f72676520416e67656c6f706f756c6f730c757365726d6f642e6e6574001367656f72676540757365726d6f642e6e657400000b40675f757365726d6f64000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714242d0d33e8dcca4f40137e2016218754a9ff93a24dcf522a8533be538402e496929ac91f7c9e5900": "0x00000000000000000000000000000000000844656c6761646f00000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714243536f899777cccb892b5e5793918855e5fe7c16b78b94bcbc4bcabf6936ec3edd1c0043a026545": "0x00000000000000000000000000000000000a496d6f62696c697a650000000000000f40496d6f62696c697a655f6f6666000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714244c1487133d32acf2718a102c908ff26947b45596237f761fae16f30499dd9e9ad99370f38d490c": "0x000000000000000000000000000000000006757262656e011668747470733a2f2f757262656e2e78797a2f6172741240757262656e3a6d61747269782e6f72670f757262656e78797a40706d2e6d6500000740757262656e000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047142465e11c805e40714487e71c1a15539cabdf996a4383b96221d6c4afb071b29e5e344c085c1cb706": "0x00000000000000000000000000000000000000000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714247b27e4de021f0e443f4ac4d297be577e7db2e5ec57eabd33c10dac033e9482b33c508d1c2e6878": "0x0000000000000000000000000000000000097873616e746d616700000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714247e5b51518dcd9f7ca164245d48ed5035eb6fecd7557ec58ac8869c54855c6663b8a3439960d611": "0x0401000000020000000000000000000000000000000008415245534c6162064b657269631868747470733a2f2f6172657370726f746f636f6c2e696f0015696e666f406172657370726f746f636f6c2e696f000011404172657350726f746f636f6c4c6162000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471424883d27e305ffe5f89d4c543e6cd62e62136614f7b98a423cedb9fd863584a2f4ff887259432437": "0x00000000000000000000000000000000000963796265726e657400000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471424899ec201da1fbef4f9224c619c930a1c5d86b01cd4bd1d454809ee83031f1442fabf12355b426e": "0x00000000000000000000000000000000000a5072696e636970616c00000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047142489e525189c647aa4e129cd956559c21c899e2b0acccb250e14a8c072d03a2cb3e4625f8c9ea171": "0x04000000000200000000000000000000000000000000094d7973746971756500001740726f62696e2e686f6f643a6d61747269782e6f72671f726f62696e2e686f6f642e76616c696461746f7240676d61696c2e636f6d000000000c726f62696e2e686f6f6f6400", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714249c9b2b424049dd50d6ffaad41dc59e96f29914ae09f4f618d8d24a649ade27491dc74b09945a70": "0x00000000000000000000000000000000000e5665737065722044657369676e01010101000001000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471424bca730e73f4adb967cf83e4ac7ec8f62925eee4b90e459522a323fbd50b5408561657562546531": "0x00000000000000000000000000000000000962726f772e7765730744616e69696c2068747470733a2f2f696e7374616772616d2e636f6d2f62726f772e7765732f001564616e2e7261626f74613131406d61696c2e727500000a4062726f775f776573000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471424c80eb0f73c29c48402585743ecd763fde5b8582caec19198b04ba1b6b57b86855203203ffb2b33": "0x00000000000000000000000000000000000744696d612041000000137569383766696d6340676d61696c2e636f6d000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471424c849079ee8bde4921d3fe712adae750defcd81cbd13fc63226c907ec2961204617fb4620f4ba15": "0x00000000000000000000000000000000000753494c56455200000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471424cca5c49a0392d3a6ae3f09425544ce2f852a638e82b8a9ae49486b34583e77436984f13b824754": "0x000000000000000000000000000000000010426966726f73742046696e616e636510426966726f73742046696e616e63651868747470733a2f2f626966726f73742e66696e616e636500166b6569746840626966726f73742e66696e616e636500001140626966726f73745f66696e616e6365000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471424e34420f18ed441e8fe2f9cd7b9e68790ca9ffbc328cf496162907a526bc335cb51cb5118f4c43f": "0x00000000000000000000000000000000000761656d6f6e6b000000000000094061656d6f6e6b31000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471424e872fcdd80ae390229fda198aa937ca03036032b9b1680acf37d6366ac18a5133d414e7448890d": "0x040000000002000000000000000000000000000000000d4775737379204b7573616d610000001667757373796c616d626f7340676d61696c2e636f6d000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471424f00986851bb8956af63165579ca558359619fe514fd5b89adcaa5710bd25ebcc789c2fa7602270": "0x0000000000000000000000000000000000047975750000000000000d40365f73656e73655f6e6674000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471424f992f424aeeefd1455048def79ccb4e4bc0d59baaf2a8a0d2e734ca0100bb8040fe7ab8aac1e30": "0x00000000000000000000000000000000000b4a696c6c204a6f756c65054a2e4a2e1d7777772e696e7374616772616d2e636f6d2f6a696c6c5f6a6f756c65001b6a2e6a6f756c652e73696e67756c617240676d61696c2e636f6d00000c404a696c6c5f4a6f756c65000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471424f9bfe2f5f566ba2a69669a1ed766923a30b1e7cca2c9826f8a0e488afda158de90d7d5bb3f2c24": "0x000000000000000000000000000000000009696e7465726e4c460000000000000a40696e7465726e4c46000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714250ef6a5cbd72bfa16b034f4bf8ab3117bf2bf4feb2babb28379bb9899870303ce71c91dd0d48355": "0x0400000000020000000000000000000000000000000018556e69717565204e6574776f726b206f6666696369616c18556e69717565204e6574776f726b206f6666696369616c1868747470733a2f2f756e697175652e6e6574776f726b2f001568656c6c6f40756e697175652e6e6574776f726b00001140556e697175655f4e4654636861696e000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471425235c4616852bcaa6c197a5b757309578dfde7a02e19aa9922b8f81a60e81bb0c6b7295090b3456": "0x0400000000020000000000000000000000000000000018564953494f4e5354414b4520f09f9181e2808df09f97a800001840766973696f6e7374616b653a6d61747269782e6f726715696e666f40766973696f6e7374616b652e636f6d00000d40766973696f6e7374616b65000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714253268461f29d2acccb0f65823925167071b3eb927035d1343bfaf8cf417b92797a6ed086e89a102": "0x00000000000000000000000000000000001070696e617475626f2d7061796f757400000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471425353340b14f223feca02a9b52d76d20af3ae90bf5b94103c133d5527e16efd65a35dfaa37985d19": "0x0000000000000000000000000000000000085469656e2043501b466f756e646572206f662043797072657373204361706974616c1668747470733a2f2f637970726573732e776f726b2f00000000094043617962616368000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047142543c8452e8934bd38772a0fd7eb47babc5fb6c790dec561f05e2adfad50dd61c8b8d173af2be865": "0x040100000002000000000000000000000000000000000d4464656d6f6e20706f6c6b61000000186464656d6f6e2e63727970746f40676d61696c2e636f6d000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471425469260aabde91ea8c5c990641c47a3a8469c4ad213eeb46f2801980b10dbac0e9017cfb33e083e": "0x04010000000200000000000000000000000000000000114d61746575737a207c2046656e6e656c001b68747470733a2f2f7777772e66656e6e656c6c6162732e636f6d16406d61746575737a63613a6d61747269782e6f7267176d61746575737a4066656e6e656c6c6162732e636f6d00000f406d61746575737a5f706c617a61000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471425551d356c585aa2ccce0525a37c12d0fac63ea107465b64b4c17a3909264bb6bb415d12afbe5233": "0x0000000000000000000000000000000000054d6174740101011f7472656e64666f6c6c6f77696e677369676e616c40676d61696c2e636f6d00000a406d617474686c6962000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047142596b8a2c5a7ae9c3e7b612fc6c728479e6abddf22f53e7069268b1f87dedc584bb4912fbf42da0c": "0x0000000000000000000000000000000000084d61785f44455600000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471425a03b4e2357699ce0b8c79103a2b1c659912f45ebadf84a78b84562ca27e3b5cfa4af706be20a56": "0x00000000000000000000000000000000000f4269676d616e74696e67313939350e4b696572616e20436c61726b6500001a6b696572616e636c61726b6530323240676d61696c2e636f6d000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471425a7fa8b48b0dc6e1896ac947535ee6c006b54dbf3e01a0de2b718ba3b38b14f540d8d71e86d2d4a": "0x000000000000000000000000000000000015546575746966204b7573616d61202d204d61696e00000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471425b4120dcbbe9fbe2e3f0a9ceaf7d69fed8e15a7e2b1477ca3f16195815d09b9508dc87cfef97203": "0x000000000000000000000000000000000003444400000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471425b4af64c3e38cbe46996819b24f30d5fd5dc85ae9d4c7b7943e72f4070bd9f2a87ac77198ee5f48": "0x04000000000200000000000000000000000000000000076368746f6c6900000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471425c679865a91ba59c66f4d91ebc7dd0065a5a2837014e5f4cef5d36d36d4ba7c915137d885dd7640": "0x0400000000020000000000000000000000000000000016626c6f636b6275732e636f6d206964656e746974790000001a706f6c6b61737570706f727440626c6f636b6275732e636f6d000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471425dc4c79b17138074041c5f5872efdc4fb7b09ec7b6e68b6ce3196c799ad3de2982d8ebc9baca81f": "0x040000000002000000000000000000000000000000000b4e6f7661537068657265000017406e6f76617370686572653a6d61747269782e6f72671673686170616d6f6e69636840676d61696c2e636f6d0000114074616d6f74696e6563313737383938000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471425e76612e7693e49429de6ac8a65ed9b4c69bbd0f2ee9c1bfd11128756886505fb8bcdbf6fa79d0e": "0x00000000000000000000000000000000000000000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471425f12f3d544b80bd34b05254d36fc7ffe4b638171bb90a9b468c3de832375d46880204b9ff253d53": "0x0000000000000000000000000000000000114f75747374616e64696e67204f776c73000000157468656b6f696e62657940676d61696c2e636f6d00001c747769747465722e636f6d2f4f75747374616e64696e674f776c73000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471426211b2f2f0598491e104b112afb4a9f23112f3eeb28f0e7a707b5a05d9a2d135b6022fc4b01bf25": "0x00000000000000000000000000000000000e537065637472756d204c61627309436172696d616e421d68747470733a2f2f737065637472756d6c6162732e73747564696f2f001c737065637472756d6c616273747564696f40676d61696c2e636f6d00001140537065637472756d4c6162736e6674000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714263009f5614f119d3aaff7070b2622937cc10f63da0c5ce84b487bd2c83eae3bb7054e7089a9dd05": "0x00000000000000000000000000000000000b67662d6e6574776f726b0b67662d6e6574776f726b1368747470733a2f2f67662e6e6574776f726b0000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047142638a30dc57d656ec085d0dad974c2fc1e90f79317b3703c5161f72e5d22bef963287f6ef23cca44": "0x000000000000000000000000000000000007506f6c6b613200000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714263e102005892ac7f8d2eedd093b0a70e25c5a48bf9a499d146ed4992658523e97b3ff165768cf6c": "0x0000000000000000000000000000000000154152544f4245205820504f554e444d4f54494f4e01010101000001000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047142643c0564bb7e30e26842927c98a50ab1d439ab45f21c5beb6970556e1fd7b52df44977e4344b148": "0x0401000000020000000000000000000000000000000011447261676f6e5374616b6520f09f90b20c447261676f6e5374616b651768747470733a2f2f647261676f6e7374616b652e696f154064657266726564793a6d61747269782e6f72671b647261676f6e7374616b654070726f746f6e6d61696c2e636f6d00000d40447261676f6e5374616b65000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471426539dd1197511f342669bcaafd39bc9125bbd0199a6cb98ee674008cd2920b82c8357207753e803": "0x0000000000000000000000000000000000054d696b65010101156d65746177696e646f7740676d61696c2e636f6d000001000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714268082072d3e2d0b9421c10cb74e62cb8f5e6ca928c519587c563f9516037cf193f720f0a882e930": "0x00000000000000000000000000000000000b4c656d6f6f6e6b61746500000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047142695e8a0520bfa9dda6b80813a57b98ed3b95c6dfa6c5b0fedf8ed8547bca16e7310a7354f85d35d": "0x00000000000000000000000000000000000a63727970746f6e696b01010101000001000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714269ee4e3b1539dc2acbe56e4e00aac105c15e7cde200eac5232b9ee4f0d8122b02f847134bfc136e": "0x000000000000000000000000000000000012426c61636b736d69746827732053686f70000000126f7065776b6f4069636c6f75642e636f6d00000f404f705f4b6f6e7374616e74696e000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471426a2abbc21cd770cd88a4b558274e57737ffd3fc9741848596199a29d77fe511804d20810cb76050": "0x040000000002000000000000000000000000000000000d5374616b65506f6f6c323437000019407374616b65706f6f6c3234373a6d61747269782e6f726716696e666f407374616b65706f6f6c3234372e636f6d000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471426a6a8ae22d0110eb2586fbb5db54f99a3aa3a99b2c87fda3498df4f30f8fab356fc86a842dec01c": "0x0000000000000000000000000000000000124d616e6672656461735f4576726c6f6f740000000000000d406d616e6672656461736d69000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471426adffd4419ace43f6fa0cf7d27491e295e6a4f2709e8eb8927a97c46f7dae68626cbd313684191b": "0x0000000000000000000000000000000000064d696b797300000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471426b35cf487044dfd1ea3706798fbbe6699c767dab7560171c3ad1ad972987d18e63c23c9bd736369": "0x00000000000000000000000000000000001041686d61642e6773204b7573616d6100000014646f7564792e31303140676d61696c2e636f6d000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471426df78e6ebcd1d0c3662167b8a0a620ff11573a953f92c9da6245a263efcaf2b61af65019ee3e55d": "0x00000000000000000000000000000000000a626f6e676368696c6400000000000008403078426f6e67000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471426e7f4ebcd01d4dae6dd0a94c6dc8091d357cf0092af2f8e108daf432d02d27dcb7ffd019d98a509": "0x000000000000000000000000000000000007496e64696b6f00000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471426e9d47393173c428a65f2773ad69cccedc0a58ef7ebd2d446b882231b4b97044105b2035a8d9546": "0x040000000002000000000000000000000000000000000950524f584641524d0000000000000b4050726f785f4661726d000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471426f51cf99f66fce5e41f9361b1bd23844ab32b6f1b635064ff5c99769c05eb09f5a3c9fa00de150b": "0x04000000000200000000000000000000000000000000174f6e205361696c7320f09f8fb4e2808de298a0efb88f00001440616e647265793a6f6e7361696c732e636f6d127374616b65406f6e7361696c732e636f6d000009406f6e7361696c73000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714270aa664dc019028d02c1edcd16c17e8e1a9b6d3bf8c20df4c1427225868599d0e11da1442eb297b": "0x00000000000000000000000000000000000000000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714270f33fa5ffc88e7fe98d7eebee0a3c28cbb5b7449632fe9b13cae934d94d81e586c2ea9167c906f": "0x0000000000000000000000000000000000086179796c6d616f00000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471427183e524af681e5420a3bb7932c1b6694b1c93d9e9790850e2078b8cbec088a627ca8b9b5dc6967": "0x00000000000000000000000000000000000f42494e414e43455f4b534d5f31360f42494e414e43455f4b534d5f3136000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714271ff91c2b1791ebb441c495bb40425f2fd7462637cd29bd01c9dc55ca02a673ef072c7a9bc77c7d": "0x00000000000000000000000000000000000000000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714272d85207cb7341e54563af23dac19e85f9bd579b947129c25ebbb716f24cc68c969f722ba417622": "0x00000000000000000000000000000000000642757368690b487970652042656173740c6361742d64616f2e636f6d001443617444616f4e465440676d61696c2e636f6d00000b4043617444616f4e4654000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047142730809323ff3aebc29ac3c17a8bb1145487c9f80bc86e6982b95bfb522b6e191ab95ad8f248f07c": "0x000000000000000000000000000000000005486f6f6e09486f6f6e204b696d0000106d61696c40686f6f6e6b696d2e6d6500000b40686f6f6e737562696e000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047142738f0604af4e9680c641da3001395ee6a8d44faed230e8cc7f039191fab991021ca58dad3172b60": "0x00000000000000000000000000000000000744696e657368010101010000104074686564696e65736870696e746f000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714273e2115b33b2f4960a964547185528c66b393c996dd1ea1a2fc678ccfa4f28e03d60827f49b6542": "0x0400000000020000000000000000000000000000000011536f666969615f56616c696461746f7200001740736f666969612e6b6f6e3a6d61747269782e6f7267136b736f6e696e393540676d61696c2e636f6d00000b40536f666969614b6f6e000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047142759a5301fcfb0872e9416cca9f463361a1bf01b274de3e4af349dbaa8132ac4a9e5566c5dbef43f": "0x00000000000000000000000000000000000000000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047142766b6d320142106cefea2b648a56b300b4511b7feace87a8dff2b99f163ac2ad17cbbea3432ab45": "0x00000000000000000000000000000000000b4c6f6e64757a626f756201010101000001000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047142777a559c125897fb8897a746ceaa53376946a3da353c1c987df8c0caa4395ac0eaf0e6c74874054": "0x040000000002000000000000000000000000000000000b4a656c6c6965644f776c000017406a656c6c6965646f776c3a6d61747269782e6f7267156a656c6c6965646f776c40676d61696c2e636f6d00000c404a656c6c6965644f776c000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714278fa2422dbf57da1a7905c207ba3df34886df12a314267e511c90f8ef357424cc6af0477661a37c": "0x00000000000000000000000000000000000953696d697374657200000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047142797bb0bbacd54cfa8eafa89c9862249c89e31d6d78bf5392b4659fd33e66016a789653677f9125b": "0x0000000000000000000000000000000000086c6553717261780000000000000a406c65537172617831000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471427bfec468e3649a946869d994ac3ddc5d2ce93cc76f9f92b675b41ccc7b31fb60d9fadd663084552": "0x000000000000000000000000000000000005486f646900000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471427c0c7503f888af4507c59dd084108f16b86c906157a8249cf5f750652e76b937a22e3f551a5ae31": "0x00000000000000000000000000000000000870756e6b4d757800000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471427dc7bc51117cc44d46e6f10cd59b0f6d7082dffb33d27c9f29801233f8e28fe3f5edf2d51762c6a": "0x00000000000000000000000000000000000b4441524b464f5245535400000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471427e3665867fc087e60653ca4d287e643df8f9486e158c6eafa04e5d8feb9769009ab627ef1dd5f2d": "0x00000000000000000000000000000000000c4261626565617a79417274054d6172790101166261626565617a7961727440676d61696c2e636f6d00000d404261626565617a79417274000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471427e9a7919c98f38360052cf9f18f47b46ea52cf4473db3ca3c959b2112b819a60c1d0f36ebccd61f": "0x000000000000000000000000000000000006756e7a656e00000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471427f56a6db2b3eecc9451838c59891cd58256365f2d308e0144ef49acb3cbf5596367c8afaef0db66": "0x0000000000000000000000000000000000095a6172746861617800000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714282a8872a6cadb12700066767b3608dcde8ee2786b93d9c2e165713b53b6cda62ea106816fd99275": "0x00000000000000000000000000000000000b54696d65202d204e4654085469782e6f582e1c68747470733a2f2f646973636f72642e67672f3432716876613452000000000d40456d626c656d5661756c74000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471428850aae739e89a2387d4dd17e44506ef67c50ab4b10bb102b9666ad954a3fb1977aa46eb6ec5928": "0x00000000000000000000000000000000000a466f726573746f6f6d06416e746f6e00000000000b40466f726573746f6f6d000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714288be1c561b186005c4704c11534f0e15a863cc2cb28488c9b8ae614d1fb783cc852e39751415423": "0x00000000000000000000000000000000000d526f636b585f4b7573616d61001668747470733a2f2f7777772e726f636b782e636f6d0012737570706f727440726f636b782e636f6d00001040726f636b785f6f6666696369616c000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471428a876cad533fcb536677e8e5d84c1a25bdac951e9055abff3df4c7a656abd841197a8726ff29a3f": "0x04000000000200000000000000000000000000000000094c656e677569746f000012406c656e676f3a6d61747269782e6f72671530786c656e677569746f40676d61696c2e636f6d0000094030786c656e676f000c4c656e676f37233236363400", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471428cb5aade7584f6236d7b7a05501f3e93e7eec83c53739147dd9824554e4907136371ca062820e3d": "0x040000000002000000000000000000000000000000000c4d414d415f4b5553414d41000016406e61737461736979613a6d61747269782e6f726714696e617374696b6e6e40676d61696c2e636f6d000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471428da33985b8d542b60db22642e7a1b7f871e2013ca39ab20b15b9416a5b7e9ee91e1e17fa92d5393": "0x0400000000020000000000000000000000000000000015416c746169722062792043656e747269667567650000001468656c6c6f4063656e747269667567652e696f00001040616c746169725f6e6574776f726b000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471428db6c1e91cbc43002385caf9a08b92ca458a0b817a8cc303cefd5a0c6e108cb939e04242b9e007d": "0x0400000000020000000000000000000000000000000014537562517565727920436f6e74726f6c6c657211537562517565727920507465204c74641968747470733a2f2f73756271756572792e6e6574776f726b001d6a616d65732e6261796c794073756271756572792e6e6574776f726b0000114053756251756572794e6574776f726b000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471428e36dda90f16500f4589b70331ebfba6b8234b1c07b16147d6078068532b53c1a6cd8805e69e851": "0x0000000000000000000000000000000000084c6f72696d6572104c6f72696d6572204a656e6b696e731b68747470733a2f2f6c6f72696d65726a656e6b696e732e636f6d14406c6f72696d65723a6d61747269782e6f7267146c6f72696d65724077616c6c6574792e6f7267000011406c6f72696d65725f6a656e6b696e73000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471428fb6c72ec6fc14e848c56fc8974dae17c36f18d1e913ded6985fcd583df94391d0fc4a50a1c0924": "0x00000000000000000000000000000000000e546865546f6d69657374546f6d0754686f6d617300000000000f40546865546f6d69657374546f6d000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714290aec17ae7c197466fae573cabe4172bdfc60dfd00dff703a4323854715c151f868293db828190c": "0x040100000002000000000000000000000000000000000d4a61636b20456e74726f7079001968747470733a2f2f6a61636b656e74726f70792e636f6d2f18406a61636b656e74726f70793a6d61747269782e6f7267197468656a61636b656e74726f707940676d61696c2e636f6d00000e406a61636b5f656e74726f7079000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471429318d8841335dc7701eaba887e5794e19bde970c93ba68b9ea14c2d48be3f2d9a12a789f2902c27": "0x00000000000000000000000000000000000a496861766563616b65034d6f010101000001000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714295296813f75420be0499159353e5c5651dea2347d516d5ffb1e3496e62a6a087f7439b222d1e665": "0x00000000000000000000000000000000000853747564696f4a0000000000000a4073747564696f6a5f000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047142960a5a23c329652582e9acd4386d60a8d3de206a575ab9ab0c383f3b4ee88d2a2ed144afd356504": "0x040100000002000000000000000000000000000000000b696e74656772697465650e696e74656772697465652041471b68747470733a2f2f696e74656772697465652e6e6574776f726b0018696e666f40696e74656772697465652e6e6574776f726b00000f40696e74656772695f745f655f65000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471429654c28b22ab06086c19b8337e75a61904cb730732c64c378b2922700da9818668a94ec35829e0e": "0x0000000000000000000000000000000000056473746e0d44617374616e2053616d6174000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714297025ac0a2861c0fcef6b2f12605598c64baa5ec72a1db7a6e7654360badcd2e67dbd1d2b2d9256": "0x00000000000000000000000000000000000000000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047142982470e0bf01d0a9af05930538bcbd3d1528f59c4df5d615040cbe411289089cfe743ca48be7319": "0x0400000000020000000000000000000000000000000019f09f8f8e204e4f444520464f5220535045454420f09f8f8100001440776f75746572643a6d61747269782e6f72671b776f7574657240706c6179696e672d67726f756e64732e636f6d00000a40576f757465724466000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714299784d2cc9f99090e29197ee74a3422dda534d19a173a3dae9afc1773191a37c85590d25c67be4b": "0x00000000000000000000000000000000000d66726f696c616e63727970741346726f696c616e20546f676f6e6f6e204a721a68747470733a2f2f66622e6d652f66726f696c616e70746a72000000000c406670746f676f6e6f6e31000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047142999edd4b53f027ecc91bf4a6540ebedbe7ab2bb1a2ee957ad2fcbd832598cbe4e9854d5157fae11": "0x00000000000000000000000000000000000b4f7a7a7920426f62627900000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471429a258cec4ae7bede4791bfac251c2d421fc66581de126c16b072150c9af2700fc1350b948184819": "0x000000000000000000000000000000000021536565722050726f6772616d204e4654204172746973742053686f776361736501010101000001000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471429b138c94f24ba807c4e144380357ad3e690e74f5b7bbbe4b7d6ab1579d4c6d7c844ef003cad9a24": "0x04000000000200000000000000000000000000000000094d65676154726f6e000000166d65676174726f6e407473657276696365732e6573000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471429b9b611bc58a5c6b85a4656256013cfb7410f0febbc9a1ded0f040b7e5b7b865eb0ab16a5742b2f": "0x04000000000200000000000000000000000000000000064261736d650741647269616e00001f62696c61736576736368692e61647269616e406f75746c6f6f6b2e636f6d000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471429c4999a48e5667768f6e4f77f043dfcb9fe88519996ee25ccae674ccda259bc49efec6b6eeb9607": "0x040000000002000000000000000000000000000000000769636869676f0000154069636869676f39343a6d61747269782e6f726700000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471429cca489d7d2fc39fadbad8979264e72d837f2b49a43abcd743143676bbe11ce1cdfd879c5def616": "0x00000000000000000000000000000000000f42696e616e63655f6b736d5f33300f42696e616e63655f6b736d5f3330000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471429d473e4b9c6ee4e2cb14594939f2e2e92e4a59865b659d80be0098ac588dc505f23a9a920cad53b": "0x000000000000000000000000000000000008536161616161610a426f79616e67204c490000163234637572696f7369747940676d61696c2e636f6d000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471429d8b41991794e5af304702103a2e260caf32e751ad3118da93f5d63fd2df34d2e712cdc73fbd885": "0x00000000000000000000000000000000000d746f6b656e65636f6e6f6d7900000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471429ead3ff3726eb80ca4b7bbbeac7ff1d48696fb7cdf933462c6c88a7ebe705f9b78f6ca1118a847a": "0x000000000000000000000000000000000006547963686f01010101000001000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047142a034e76d17b70ce66823a843da63136d51a51334c6a771685c15258684e29d2821c3c395646187b": "0x08020000000203000000010010a5d4e80000000000000000000000000000000000000000000000000000000b44616e205265656365720000154064616e3a776562332e666f756e646174696f6e1464616e40776562332e666f756e646174696f6e00000b4064616e726565636572000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047142a0c6cd2b29fcf6d60c48535dc707316c51bd853d9b05b977a3760c501706ce9478115de6559663f": "0x00000000000000000000000000000000000a4b7573616d61446f74001a68747470733a2f2f7777772e6b7573616d61646f742e636f6d001468656c6c6f406b7573616d61646f742e636f6d00000c4063726f77646c6f616e73000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047142a1134d83a717cc23ca3ed66a374595d4e050482af14bc60b90bb7d8df76188c71d634ee96c35d53": "0x040000000002000000000000000000000000000000000e50657266656374205374616b6500000017706572666563747374616b6540676d61696c2e636f6d00000e40706572666563747374616b65000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047142a1320a99290f3dd9ecdab6f55231e079a117c5f06f01bb8bf0cb3b67c376852d8af206c355b191a": "0x00000000000000000000000000000000000f547269636b79204e4654204172740f547269636b79204e4654204172741768747470733a2f2f747269636b792d6e66742e617274001e6f6e6c792d747769747465722d646d2d406e6f2d6d61696c732e636f6d00000d40547269636b795f4e465473000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047142a185e7f1e6a0461ac03820d55ca72a6676284bb540a1d18c7746371f450998a5ca3e0b1354d5e13": "0x0000000000000000000000000000000000074b656c6c657200127777772e6d6f7573652d64616f2e636f6d001f6b656c6c6572636f6e6e656374696e67646f747340676d61696c2e636f6d00000f404d6574614b656c6c65724e4654000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047142a251205d65518b0e6b912626c9dfa3cd9e65b4412b19eb9d123edb1aa22d492a58a88091c483a7a": "0x00000000000000000000000000000000000e506f6c6b61686f6c69632e696f001668747470733a2f2f706f6c6b61686f6c69632e696f0013696e666f40706f6c6b61686f6c69632e696f00000f40706f6c6b61686f6c69635f696f000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047142a3601b2926d2aa7ee5472873e774a1879d8fe0912f0a136413ff823109b9c068e8a7cd4bd0ead28": "0x000000000000000000000000000000000005686f6c6101010101000001000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047142a5c73c6ad046c7c067b80b3c8b6fb55b60cb6521bdba3d1ff34daaabbe4644e3ae75c8e7bccff28": "0x00000000000000000000000000000000001145636c697073696e672042696e617279001a6d696e64732e636f6d2f65636c697073696e6762696e61727900196d61696c4065636c697073696e6762696e6172792e6e657400000c4065636c697073696e6762000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047142a65c9799fef41adec3d304da58d77a4384fced1c59dd3cbc9618dd1ec92e6feb64293147272a21d": "0x00000000000000000000000000000000000a526f636f20536170650f526f636f202f20446f7463617374000017726f636f63727970746f343140676d61696c2e636f6d00000a40526f636f736170650009726f636f7361706500", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047142a71ae4fc6878ea9141511ed1278bc4166aefccb1eb7b6d8dcde86cfd02dd6e618107ba76f6cc905": "0x000000000000000000000000000000000009414747454c4f533100000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047142a9b352e5eaaff5751f78769768fc88c83546881a768523b3c70c2500159047a970ac4ef16768af6": "0x040000000002000000000000000000000000000000000a436861696e5361666517436861696e536166652053797374656d7320496e632e1568747470733a2f2f636861696e736166652e696f0012696e666f40636861696e736166652e696f00000c636861696e736166657468000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047142aa13e08bfb58aa40e4022c39c8e100f36455fc8ef6a2a0999baef80c518e806adef3ee7608e2218": "0x00000000000000000000000000000000000a496c6d6972204d455806496c6d697200000000000840746865773071000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047142aad13c977c6bc57764ae05560f633f233c4aeac3330e9a926c32ccfcb57f901467a4dafa879752a": "0x0000000000000000000000000000000000084761627233616c0000000000000e406761627233616c6d75736963000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047142aada661b281a2ddf299e83c04aff581d1178bc3dd281429d9943509d7eae0324bf8d78584fda712": "0x00000000000000000000000000000000000a486f646c2e4c616e640000000000000e404c756d6265726c616e643839000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047142ab19abf6982483e78d53a2db8434656a5620d77fb78b554ad096691357fec6d7fa8da47a2478e22": "0x00000000000000000000000000000000000f464f52455354204457454c4c45520101011576616e6176616173656540676d61696c2e636f6d00000c4076616e61766161736565000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047142abb6322ab12c37de80dbb410667a153e62d495a9e0f9bd4b903879e531fefa123aad127e8d33f67": "0x00000000000000000000000000000000000961766568756d616e00000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047142aca435ad8607d4a7a53e11bad682523eb4fa9d18bd1dbdc84b50162e2005c0ee93b1cb235414732": "0x04000000000200000000000000000000000000000000076879706e6f7300000015696e666f40706f6c6b612d626c6f636b2e6f726700000e40636861696e616e646d6f7265000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047142ad59b47893766e9a215ba2d1b408fd5350b93f2566124331dabc06e94c16d7080d3cd5771d59958": "0x04000000000200000000000000000000000000000000124265737456616c696461746f724576657200001e406265737476616c696461746f72657665723a6d61747269782e6f72671c6265737476616c696461746f7265766572407961686f6f2e636f6d000010406265737476616c69646165766572000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047142ad67d457f83cdba42988a08e2e4e44a78abcc93d99d458eaf9cb23daf6de093ca2aaca1b2111025": "0x0000000000000000000000000000000000096c6f7265666176650000000000000a406c6f726566617665000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047142ae9d42a8da3cf5b1cc30a09ab89ebd5c6750f7df34378d6d750a2fd3be256735fae11dd04412f6e": "0x0000000000000000000000000000000000086d61636e66747900000013646d61636e66747940676d61696c2e636f6d000009406d61636e667479000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047142af56ffa9ecf488b30743e11bca3faf36dc95314e5640f330c12669b9d90a800fe2c1fa20c890777": "0x0000000000000000000000000000000000084d722e4c696f6e0000000000000b40636c656d6f6e635f63000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047142b031c075ea343ce443c76dcde19df9387486ded7845c6d85ec2a4c17f38f8b1e7a0a14de7968d7d": "0x04000000000200000000000000000000000000000000064b414d454c0d6b616d656c7374616b696e671968747470733a2f2f6b616d656c7374616b696e672e636f6d19406b616d656c7374616b696e673a6d61747269782e6f726719636f6e74616374406b616d656c7374616b696e672e636f6d00000e406b616d656c7374616b696e67000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047142b0cbf1e0fccd13f6e829382b887d84d8fbb444ae215bac5c1b639e7c5cae2bddb49f35110b16213": "0x040100000002000000000000000000000000000000000b5368616479626c61636b00000016626c61636b736861646565407961686f6f2e636f6d00000c407368616479626c61636b000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047142b14414c029d53fe7e02cb4148b7af9c92f176daf919bbc75df1ba8de7446788d07846817a9ab85a": "0x0000000000000000000000000000000000076b6f6d6f7269114d6178696d6520546973736572616e641d68747470733a2f2f736f756e64636c6f75642e636f6d2f692d772d73001573686f76736f726940686f746d61696c2e636f6d00000b406d61786b6f6d6f7269000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047142b1965d612c430d2087a435025db114c8c7f0778e86efd968ee4a60bfcee8dcecd19099e28daf46e": "0x00000000000000000000000000000000000101010101000001000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047142b2a875868c6b85caa32859a54b9ea9d36cf5af9ed03febea761fb5d9f380b6d517874b96d87866f": "0x000000000000000000000000000000000007616461636f7907616461636f79000013616461636f79313340676d61696c2e636f6d00000a40616461636f793332000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047142b6e818ad6aaf2194425333101d35f55eccfe16b28f0e65007a0076ca42eecb050405f6e0ac4737e": "0x040000000002000000000000000000000000000000000475616900000018616e6172636879636861696e734070726f746f6e2e6d6500000f40616e6172636879636861696e73000e616e6172636879636861696e7300", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047142b732c11caed7a5626902bc2f712f4c3fe8d6180e162376ba644cc80ba99e84cb9bb8e50c20c546a": "0x0000000000000000000000000000000000094e65772041656f6e0d4c656f2056696b746f726f7613687474703a2f2f6e657761656f6e2e72752f0117736974652e6e657761656f6e40676d61696c2e636f6d00000a406e65775f61656f6e000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047142b757a72ee144495f0d30ae836bb1d44542a6ceeeb6ce03aa7313cc47b96a4ad19160074bed83621": "0x00000000000000000000000000000000000c4b7573616d61427265747400000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047142bab42363fea46ad00f52ade889dac25285059b639359071c2aad88e3f1f60593f86cc460ce20213": "0x00000000000000000000000000000000000b4441524b464f5245535400000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047142bac4814c142df16f89d49e97071dfd7f8971ed816c0fc60a34aa6a8d0b1af8f7c6922659dfbd789": "0x00000000000000000000000000000000000d63796265726e6574776f726b00000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047142bad7c5b850e0c22423a671a90c3fe2169dbaf169d5446c1470985ba05bee19614f2afef4eb2f15a": "0x00000000000000000000000000000000000945475245474f5245011a7777772e736172616867696c626572746b756e73742e636f6d011973617261682e67696c626572743840676d61696c2e636f6d000001000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047142badf2d7418dbc94fa2ee018998f963b05d05b960d10a8b47043ef1fa552415e0f128e239d9f4a17": "0x0000000000000000000000000000000000095a69676775726174001f68747470733a2f2f6769746875622e636f6d2f72756e7a696767757261740000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047142bc21eb1a6e88498ea524b9e0dd9bd336d31e71bc1a172388b10d4b6571ace5e7e6e836483110216": "0x0400000000020000000000000000000000000000000009446f7420506c757300000016706c757373696b6f6e64654070726f746f6e2e6d65000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047142bc675823ce5a7ffb49815cebdde0943433b0670fa66180bf2b957cd6ebe203be6e581149fc38113": "0x000000000000000000000000000000000007416e696d616c10416e6472656173205a7573756e6973127777772e426162654472616b652e636f6d1840616e696d616c6f756b6f733a6d61747269782e6f7267126961676f73383140676d61696c2e636f6d000009406961676f733831000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047142bce7bc79ded2adecaf177ad58c772e31f10a83e8b76e4905bb78d5547e8976e19ca4c3366609015": "0x0000000000000000000000000000000000094172636f694b756e00000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047142c044452e691b7312c2689f3c9b59f32f1730cd3bc8c54fe55ba31d2525cd7ec80a3dc6726809240": "0x00000000000000000000000000000000000453616d000f7777772e706f756c70732e636f6d000000000a405f73616d5f617274000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047142c09493faa9e924efc5d04e7ff3965c8285a2c23aa573117deeed886bbe5e3be0974f1cf0a2ff216": "0x0400000000020000000000000000000000000000000012e29880efb88f536861776ee29880efb88f00000015736861776e40706f6c6b6177616c6c65742e696f00000c40536861776e5859616e67000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047142c0e09d90be40d90180da4776d78804652df766f9f002b4f448f183732eee12da7c3816f02031e64": "0x00000000000000000000000000000000000866756368736961086675636873696101011867616c6178796675636873696140676d61696c2e636f6d000001000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047142c157c9e312512df503fbcd2efb481dccbbb4c6d7ce0c60700e0fd3c81bc126372d6e8efcbe2bb2a": "0x00000000000000000000000000000000001148656176656e734c617374416e67656c0000000000000e4048766e734c7374416e67656c000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047142c1a489d7e391b077c64f959f2bfd05207d426c9e28b0bdfda70d0fdac821107c426570205e67779": "0x0000000000000000000000000000000000084150452058323701010101000001000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047142c1efb90638974dc0c30a71e750654bc69b1e570c34c27c623f3e42f94632e3e1508f88bf97a1d5d": "0x0000000000000000000000000000000000074b5553414d4100000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047142c2dd4393185b96676d76166add74cc4fad0151e7780acb5555dc57e14ce131251df83de6a5fe841": "0x00000000000000000000000000000000000c6c61692070696f6e65657200000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047142c3ee724586db259eaab0cb55c147ffaf184a4c00513e85f6d5bb6416994fbdd0dd168f3c59a291b": "0x040000000002000000000000000000000000000000000c437970686572204c6162730000001d6379706865726c6162732e636f6e7461637440676d61696c2e636f6d000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047142c74588f39d962f18813e7282320dc3025353a1dfd830f346e4d1440636185949584211859a75a75": "0x0000000000000000000000000000000000074261726b696500000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047142c823c435a39d571c8a863618f72322a02f9d0028e6a6b907326041ee098e3259b39193a0cac5a41": "0x00000000000000000000000000000000000f4976616e2052204d6174682023320000000000000b406d6174685f6976616e000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047142c870467e584bae74292ae067e7aba72e9d415daa26425b96c13c059b76a9cacfd1edb2e1563be0b": "0x00000000000000000000000000000000000d50524f504845435920415254034a5400001970726f70686563796172746e667440676d61696c2e636f6d000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047142c8d642db83d4b3caeddba72d260d2a9d78d169f5a6762909502702e9b2e9bc7722c51cc5eb8dd31": "0x0000000000000000000000000000000000054b616e79000000196b616e7963727970746f383940686f746d61696c2e636f6d00000c404b616e7963727970746f000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047142c9114f608ac39a9a45d1c3020272172fdb2238d4b68c1f8d6178dfbf4a80404dcd01da024dac33d": "0x0400000000020000000000000000000000000000000009476162654b6f696e0000001c6761627269656c5f626f6e75676c6940686f746d61696c2e636f6d00000a40476162656b6f696e00114761627269656c5f564453233735383600", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047142c99d1fc868ada3d123fc89c054713d7d6cea09d68bba5e3c45d3267549c5af73c5be3950afd3370": "0x0400000000020000000000000000000000000000000007536f6e64657200000014736f6e64657240737769736d61696c2e636f6d000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047142c9bb7cb7587271684546cfff5fbfa479772bca48aad4222d5d56aea6027594293a87ae664c60b51": "0x00000000000000000000000000000000000442454311426f726564204561676c6520436c75621c68747470733a2f2f626f7265646561676c65636c75622e636f6d2f0019626f7265646561676c65636c756240676d61696c2e636f6d00001040426f7265644561676c65436c7562000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047142ca72e801f676e6fe034fb93b0d06e8a0db8dd5fac4edd8657c2cc78247ce5200e0b5c4ee6d55f3e": "0x00000000000000000000000000000000001e524d524b61626c652044657369676e732028756e6f6666696369616c29064d2e20532e00001a726d726b61626c6564657369676e7340676d61696c2e636f6d00001140524d524b61626c6544657369676e73000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047142ca762582cb6a0a95227e6087c3098806a03e82a5db0f33308340c7fdc3ab90cfd6f8be97ce28456": "0x00000000000000000000000000000000000a43726f776e6c6f616400000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047142cc588273271e0810837f57eb5dee33b7c8895a425116e9dcf32708397c630ca9a5cb1d71bd2d20c": "0x00000000000000000000000000000000000d43726f77646c6f616e2e6d650d43726f77646c6f616e2e6d65000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047142ccc8f3bf5790f3e7a5c852e5d78fb634282eccd5d38dc9b353a6c88841816710c12b4ee243ffe2d": "0x00000000000000000000000000000000000b4f6e6520506562626c650000001c6d61726e692e7261626173736f4074776f706562626c65732e696f00000c404f6e65506562626c6531000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047142cd98d2b43b99a0b6a325e3630266fda0ef7f7725ef8199726e29d569d609f3cf068c4db7e82591a": "0x0400000000020000000000000000000000000000000009444a5f416e6472650000000000000e40616e6472656d6f6973656576000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047142ce0ec76a2fab446d600c37c06c4c1c4fceca07e2a33e1db5f0958f4d36ce6b05fbc65d7d526c320": "0x000000000000000000000000000000000016486f757365206f66204b696e67732042616e6e65720000000000001040486f7573655f6f665f4b696e6773000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047142cf2c3bc9ddc0e47eea5168acc75ce334e39799ff680543ce0217605b078f22967448aa781ba6925": "0x000000000000000000000000000000000010506c616e6574204e656f20504e454f001768747470733a2f2f706c616e65746e656f2e636f6d2f000000000f40706c616e65746e656f5f636f6d000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047142cf3c07511b5dad1d9c958ec068aaa78b0d6256fea94a50cd19bdc1f82f905e88b4bd0bb5626ecf0": "0x00000000000000000000000000000000001253686f6b756e696e205472656173757279001968747470733a2f2f73686f6b756e696e2e6e6574776f726b0000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047142cfc30ea1aabc0e1d0cd1d5442f98ef9105aeadc08f225b4df5ebcdf62479ec5b0e540b57c313a3f": "0x00000000000000000000000000000000000000000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047142d287fe916fe23dc925000bd5b83d502f56c49f2a91e3532af9f919d6eb52d750b72539c6b62d45b": "0x040000000002000000000000000000000000000000000a4b534d2d736b756c6c00001540646f74736b756c6c3a6d61747269782e6f72671268656c7040646f74736b756c6c2e636f6d000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047142d294ae179111e4afa0099be3ab25140ec53154e141885c824f52fc67184630153baa07e1fc1c10c": "0x0000000000000000000000000000000000056476736c00000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047142d51e75bf4f0eb6a367371f79b82ad8954a69d5bfdde1c06489909c9a12cb8501b949f58b6a03926": "0x00000000000000000000000000000000000b42794d6978616f6f7073084d496b6861696c2168747470733a2f2f7777772e61727473746174696f6e2e636f6d2f6d6968616900136d6978616f6f707340676d61696c2e636f6d00000c4062796d6978616f6f7073000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047142d52491d0ed316bd6ccfe70c7201bb25d4c6d73cabc89a8dc1d76dc165b691db825c3f4b19889129": "0x0000000000000000000000000000000000064265657a7900000000000009404265657a794a4c000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047142d52913dfdc412f8103b98301a063f5153c46f5c1afa1624ba72db328f8a76b3144eb7d6aa646330": "0x00000000000000000000000000000000001548756d616e2047656e6572617465204e46542773001c68747470733a2f2f646973636f72642e67672f685a464b68426354001b68756d616e67656e65726174656e667440676d61696c2e636f6d0000074048474e4654000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047142d60b5c259d3d208620cceb8ca6241f9ad974b5719a46a33cf158e2e4ebc86b0771f909d4ff2ef62": "0x0000000000000000000000000000000000094e46646f63746f72084261747568616e00000000000c404e46646f63746f723033000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047142d697287022039ece6ba43544c8cb8f23a0d86e506d37cd74b63f07ae99714c3915068b4d0c7792d": "0x0000000000000000000000000000000000124b7573616d6120436f6c6c656374696f6e0101011c6b7573616d612e636f6c6c656374696f6e40676d61696c2e636f6d000011404b7573616d61436f6c6c656374696f000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047142d7cf31d9f27e677ccd583d619471f2ecbdca885d80a949e38c6c5b4c3ac8ea86837a45407530658": "0x000000000000000000000000000000000010616e647265735f6f6e5f65617274680000001b616e6472657369746f39384070726f746f6e6d61696c2e636f6d000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047142d859f3bd54b349892e02ce87428939cfbb7fbeeb1ee758b749a5854a1bd3ae9ce36b3bcb753010c": "0x00000000000000000000000000000000000b4441524b464f5245535400000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047142d8a3df03fe6535f0815155bdc6775c63aceb731d5ebe8d55043b8598d4ed1308b4666bf0e66ba05": "0x04000000000200000000000000000000000000000000135468652052756720436f6c6c6563746f72730000001b746865727567636f6c6c6563746f727340676d61696c2e636f6d00000f40527567436f6c6c6563746f7273000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047142d8b973a55fc6b24b4e398d5f14cefa2a00e1f9faeb8f2fdbe5ff83638ff3e1711301c39eca6e553": "0x000000000000000000000000000000000010446f6e7079726f2e4b534d2e444f5417526f6d616e6f20446f6d696e676f2041617264696e67000014726461617264696e6740676d61696c2e636f6d000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047142d930a562d1da7c24cb651038cd04fc360e95c5db473d3236c69fd68e57ce9ffa6bec307c450b038": "0x000000000000000000000000000000000012414a414c2047414d45532053545544494f12414a414c2047414d45532053545544494f1e68747470733a2f2f7777772e616a616c67616d65646576732e636f6d2f1640616a616c67616d65733a6d61747269782e6f726717616a616c67616d656465767340676d61696c2e636f6d00000b40616a616c67616d6573000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047142dca72940cf66478a25c9b1c6ebb2832b2ccf7812a405dced6866efa8ff595fbfc408a4091b5631a": "0x040100000002000000000000000000000000000000001050696e656170706c65587072657373000014406f6b6f6a616d6f3a6d61747269782e6f72672070696e656170706c65787072657373314070726f746f6e6d61696c2e636f6d000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047142df274fea56f1419fc659bba6d3985002708101d9c2aea9155bd520c105688751281cb40e4d37163": "0x040000000002000000000000000000000000000000000a524152455348495053000000147261726573686970734070726f746f6e2e6d6500000e407261726573686970734e4654000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047142e0a33dd13e78f0efbaebc5c7327144be51df35bb50ff8612c8c9ad73fc7b60b4382b979563de20f": "0x04010000000200000000000000000000000000000000094b6972757368696b0f4b6972696c6c2050696d656e6f761368747470733a2f2f70696d656e6f762e636319406b6972696c6c3a6d61747269782e7061726974792e696f126b6972696c6c4070696d656e6f762e636300000a406b6972757368696b000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047142e15b07440923f7648fad007551dd2cf911c9ab936c50be87a01cbee939cd9bc5ba6fde3064cd515": "0x00000000000000000000000000000000000e54484520434f4c4c4543544f520e54484520434f4c4c4543544f5200001f4c414e44534f4349455459524d524b4070726f746f6e6d61696c2e636f6d000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047142e31c7d323f7b00deafa84f0fbcc838d944b1375c809bc99f800d225286b7f25edbdc33f6c469b16": "0x040100000002000000000000000000000000000000000d444953432d534f46542d30390e4469736320536f6674204c74641a68747470733a2f2f7777772e646973632d736f66742e636f6d154064697363736f66743a6d61747269782e6f72671876616c696461746f7240646973632d736f66742e636f6d00000e4044697363536f667457656233000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047142e338a8ddaef9fa642fa2391ee121af5f64b30bb2b63d9764735ac422fa2fefb0dfac90ee03a512f": "0x040100000002000000000000000000000000000000000d444953432d534f46542d30380e4469736320536f6674204c74641a68747470733a2f2f7777772e646973632d736f66742e636f6d154064697363736f66743a6d61747269782e6f72671876616c696461746f7240646973632d736f66742e636f6d00000e4044697363536f667457656233000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047142e61081843efc3b7105c06afbe01ff98801bf3e46b96d61d0d7aeadf7af7d6c39a20dbf946b0fe41": "0x00000000000000000000000000000000000b4441524b464f5245535400000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047142e6833257186cc32886267a39c2dd0cd8175ac3e50d353375c694874ba6f48d6aaa4bb9e88ce3930": "0x04000000000200000000000000000000000000000000084d79706c616e410000001464656e6665726d383040676d61696c2e636f6d000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047142e7e56460089fc7a54c473bf199d05b878ab34e9a37d17d0a8bf70498edb5c759672e984fa38b432": "0x040000000002000000000000000000000000000000000f4170706c6965644243204c61627300001a406170706c69656462636c6162733a6d61747269782e6f7267186170706c69656462636c616273407961686f6f2e636f6d00000f406170706c69656462636c616273000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047142e872013d9376606ac9ffd09502123eba056c7619c9b96bec443840450e7759bd0a9817abbbc1a33": "0x0000000000000000000000000000000000066d726d743300000000000009404d724d74453231000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047142ea6cb65218cf1ca90c6619c6ba60125e49e75e1ea5d9b46431ba834d005319cc036104c94fcfd34": "0x0000000000000000000000000000000000114576726c6f6f74204f6666696369616c00107777772e6576726c6f6f742e636f6d00116c757575406576726c6f6f742e636f6d000009404556524c303054000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047142eb239de2237ff4464c92fbc08d8d3594de7a9eeae4ef24891cf7e8330faf07ed804cd0045e49e6d": "0x040000000002000000000000000000000000000000000a53686f7274795f33350000000000000a407273686f7274656e000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047142eb552e15974a83bc96e8af1ad79932da28f515b436b020afdfd6a389631609ab07c2fcf2e140d12": "0x000000000000000000000000000000000019506f6c6b61646f7420416672696361204d756c746973696700000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047142ed50d6c1327ddbc1cb5dafe7d8501739003634d34c9e44c526cff633093841194dcbe98ec229920": "0x0000000000000000000000000000000000106d61756e616b65612d7061796f757400000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047142eda38798820d6b442b5e9dc13290ed285216681dfdf7e2a948b541a618830bee3387d34bd23e262": "0x000000000000000000000000000000000006536163686100000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047142ede9598e62bc86e52e4df0f3307bcc319ff009b0390f8225293b344ef27dc328a0c341d842bb23b": "0x00000000000000000000000000000000000000000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047142ee91b64f947da118e8bb8ffed82a876768d15ac8dc37d613d3d55abf82c23f9dc644b4c1d3a2513": "0x00000000000000000000000000000000000000000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047142eebecf8e65e7682b8920b8c8220efc9c49ffa5271b5e5356fbeca4f9bfaf73e2b887613d2cc4966": "0x00000000000000000000000000000000001151554152545a20425920554e495155450f556e69717565204e6574776f726b1768747470733a2f2f756e697175652e6e6574776f726b0012697440756e697175652e6e6574776f726b000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047142ef08ea2ef087797ee50f5c29bb5a49cf456ef7717676a8d905eef37031a02eafb99b203edefb92f": "0x040000000002000000000000000000000000000000000b48697370616e6f446f74000000136869737061646f7440676d61696c2e636f6d000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047142ef7355afce0085c3a68b37cdcb55285eb9e76ee8744cb3c47c62b6bb07b104116077df4b8460573": "0x00000000000000000000000000000000000a626974736176616765077361766167650e7777772e61646f72732e78797a0b4062697473617661676500000010407068656e6f6d656e616c6d61726b000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047142ef7dd71f889f0050c841e6aea307d8704d5b7b7b71afad58548ce47dce090e25d01b84925e5c48d": "0x040000000002000000000000000000000000000000000a43616b655374616b650000174063616b652e7374616b653a6d61747269782e6f72671f63616b652e7374616b652e73756273747261746540676d61696c2e636f6d000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047142f01f5b6d9f688b11245242cb72fd4a3b8a7423d647e0463df0017eb7539ea511bf6f7e68b3dbd22": "0x0000000000000000000000000000000000054a70657800000017706978656c6f736f3035323740676d61696c2e636f6d00000e405069786f3632353735383835000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047142f134a0eed4de1af79454e81bd1c5d52ba72c96494e83f33e2aa22e93d3e500843857b6a7815a11d": "0x00000000000000000000000000000000000000000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047142f20db1fb9bc54324c042cc1451781f79ff3bc34cacd5329b21591b2b2d82ad57426a5079ad1c455": "0x040000000002000000000000000000000000000000000a53686f746d616b65720000001c73686f746d616b65722e7374616b696e6740676d61696c2e636f6d000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047142f2145cd985eff31bcb916e7a7ef77dd1f610ed27ec519b4ec226028eb8edade41f95b217f89f620": "0x040000000002000000000000000000000000000000000df09f97bb4261736563616d7000001840776f6c667374726f6d32373a6d61747269782e6f72671b6261736563616d702e7374616b696e6740676d61696c2e636f6d000011404261736563616d705374616b696e67000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047142f317d0ceefcb30d381612c21d537305340416604931c9d1c99a50c3f99c794f75d84db494079318": "0x040000000002000000000000000000000000000000000c4a6164652057616c6c6574000017406a61646577616c6c65743a6d61747269782e6f726718646576656c6f706572406a61646577616c6c65742e696f00000d404a61646557616c6c657431000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047142f344d81d36d4b7e7403af740812442eb174a83b37da8d7f8dc2d8b6cde6e7ff968b5cb4b07ffe68": "0x00000000000000000000000000000000000a4e6175777573616d6107446d6974727900000000001040446d697472793632383633333737000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047142f392ac03e9ede7930dedb2a379560d56675e977ced75752b912f35165ca8380499f8be7b74d426f": "0x00000000000000000000000000000000000f42494e414e43455f4b534d5f31330f42494e414e43455f4b534d5f3133000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047142f42d98a8e441c40566fdfde57471dd26ff6213ab7190765d9d10b135cf911b45508a009a95fb03a": "0x000000000000000000000000000000000011647a6c7a76207c20537562737175696411446d6974726969205a68656c657a6f76001240647a6c7a763a6d61747269782e6f7267000000084064697a68656c000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047142f694a8c100618ce0209638912655716404e7787a88325ab80a7b0ca614aa5b8e3daea1cae0e1c31": "0x0000000000000000000000000000000000084b72697076616c000000166b72697076616c65786d6f40676d61696c2e636f6d000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047142f77a540c5c2d555742717df0d5932f1d83ab0400a162e39e93a0823f8172cb880c46e1b6dd09c72": "0x000000000000000000000000000000000005416c616e01010101000001000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047142f816440610f862600ec9f324035cbb3d86ef51a32b5ca578c65271dcd882036d03e77601745d807": "0x000000000000000000000000000000000009416c65786269746100000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047142f8e9f741508842470cff2a79754a54f7dfcc423111dd79554320512a153f45df50abac7e6f9d20a": "0x0000000000000000000000000000000000096368616f73626f6900117777772e6368616f73626f692e636f6d000000000a406368616f73626f69000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047142f8f1ddeb924bbdf5cadb1617794ea8d20a5b0bf1e3275a815229a34c834c9eb6383602ad47ecc55": "0x040000000002000000000000000000000000000000000d504f5354434841494e2e494f000000116b736d40706f7374636861696e2e696f00001040706f7374636861696e646f74696f000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047142f93d78dfd49d0a462d9d0181b12100f1740ab9260827746eac283a626d77755c56bea5ddf3f097a": "0x000000000000000000000000000000000005416c616100000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047142faeb9cc9f49512f1ea25dc95281641f4b7fd9b8c8d7b970fbe764ad49b2ca1b4402baeb8eb32d04": "0x000000000000000000000000000000000009736974752e41727400000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047142fbfebd49e947bc8decb110ce95c05a22ef28e342b54a2a7efcba5b6c64fa8ccec033c1f5ebf9504": "0x00000000000000000000000000000000000c426172657944657369676e12446d6974726979204166616e617379657600001664696d733930323338393540676d61696c2e636f6d000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047142fccfd4d73aaadfef8c309d6472fab1a89e619867d57934db759e5d76d63b9e67968e36f02787335": "0x04010000000200000000000000000000000000000000084d72457863656c134672616e636973636f20416c626f726e6f7a0000176672612e616c626f726e6f7a40676d61696c2e636f6d00000a404672416c62726e7a000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047142fdab663781fbd7a162f163b179ad5c7c13073565aeb1272868861738802c33bc921b69a9e0e8a6c": "0x00000000000000000000000000000000000748617273686107486172736861000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047142fe1803695779c79b2636043fc3b8dfa608167a9fb6fb9d065b9f2f5821dc4bfc9785a244b24a92a": "0x04010000000200000000000000000000000000000000044a6f650e4a6f6520506574726f77736b6900000f6a6f6540706574726f772e736b69000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047143020cac001d284991a0d2dde7dd9defc8db6f97b28e3c6a8b4a6887f27a62f60268f6061553fc719": "0x0000000000000000000000000000000000144b7573616d61205374616b696e67203230323100000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047143036130cfabe43d906a991c8e9af2d6e2422d0909ef0aaf0dbd5cc8c9985fe2967cb159a0f9d906d": "0x0000000000000000000000000000000000094b7573616d6f6f6e0000000000000a406b7573616d6f6f6e000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471430364fbaff46f65ba081e51d00d0908deeac6cfb45d3e977f37085d2905be73e32c4b9e6707ab754": "0x00000000000000000000000000000000001250726f7665726273204149205661756c741250726f7665726273204149205661756c7400000000000c40416950726f7665726273000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714303defe256c66ba0e0fb683f9ef19a5e932b6232272697fabd62213de02d7801aca1e94b03c0b23b": "0x00000000000000000000000000000000000c43495320466c697070657200000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047143046396b7c34c0b3eec4bd650a277342ebba0954ac786df2623bd6a9d6d3e69b484482336c549f79": "0x00000000000000000000000000000000000664617678790f4461766964652047616c617373691468747470733a2f2f64617461776f6b2e6e6574124064617678793a6d61747269782e6f72671264617678794064617461776f6b2e6e6574000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471430669b7d5c8f7c3ab23801b12140968daf5304a7c38e81dbf8d75bedf02b85ae0ca8b4fe394e8337": "0x00000000000000000000000000000000000e6d697368616e79612330303231094d796b6861696c6f0000176d6977616b756c696e69636840676d61696c2e636f6d00000e406d6977616b756c696e696368000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714306c8cf26d4e0d752673c96d918a62b9af204d09f3b8a9b984daf0abbd176974da17aa688f991a6c": "0x040000000002000000000000000000000000000000000857494e2d57494e0000001877696e2e7374616b652e77696e40676d61696c2e636f6d000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471430829bec9693a3c7581bddaf5249dcc6a055652c0654ba073e21bd622d8a5b2aec629a9bc8921562": "0x00000000000000000000000000000000000a53544153204c45474f145374616e69736c6176204c65676f73746165760000186c65676f73746165767374617340676d61696c2e636f6d00000b40737461735f6c65676f000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714308ca83512dc5d0c00c6fad38515e62f83f804861803773ae17af068898dec6d558c903663078754": "0x0400000000020000000000000000000000000000000004624c6400001340626c643735393a6d61747269782e6f72670000000740624c643737000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714308d9c16e268f1b512713003b0c7826f024d4517aae0e5dcbfb2b9ead74c4c668f572698d012b754": "0x000000000000000000000000000000000010536174616e69636f20416e67656c6f0000000000001040416e67656c6f536174616e69636f000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471430a74a4157ce4ce35c1be3d517926a6c194d42131d996140f3e8d7398764423cab176341b882ee7b": "0x00000000000000000000000000000000000d756e7374617465736c6f7468056a6f616e1b68747470733a2f2f786e2d2d64723868306474376b2e792e61741940756e7374617465736c6f74683a6d61747269782e6f72671c756e7374617465736c6f74684070726f746f6e6d61696c2e636f6d00000e40756e7374617465736c6f7468000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471430ac3f1c5457a413d602fcca19d55a03e44eb46202b906cca9d97b3e866b9b4ef584c957c135f109": "0x0000000000000000000000000000000000084761726261676500000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471430b98fcd88ab4d906463b8663469c48312ecb51fe6151c4fa1e91f93270cb23326ce9d8af3a80f01": "0x040000000002000000000000000000000000000000000a4b7269737469616e4b104b7269737469616e204b6f7374616c1a687474703a2f2f666969742e73747562612e736b2f3439303300196b7269737469616e2e6b6f7374616c4073747562612e736b000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471430d3bc09d2bfcfb50c7f10142a81fedec753f7c556f5b93a400c280805e7fcdff668719637b13434": "0x040000000002000000000000000000000000000000000f47656f7267695f444f5453414d41000000126a69673737303940676d61696c2e636f6d00000b406a696763727970746f000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471430e79056e8a84474ee06959ae4cf287f2e3dc249d46c25dc777851c755931b486d7fb552932da259": "0x00000000000000000000000000000000000b477579576974684c534400000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047143113d3db76841af844a91dfd908b2b82a43037d003c90f884d3e03e7ec64b460c7caa2c2f5dcf448": "0x0000000000000000000000000000000000104a6f654a6f736570684a6f686e736f00000000000011404a6f654a6f736570684a6f686e736f000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047143118f1715a74c330aef5e12ceb56767d94848a252a5d258186547a3e9fbc2cb1b4c916d8ac888554": "0x00000000000000000000000000000000000a4163636f756e74203100000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714314002c34f6b0e235818a8031736e2d320bb0c393bba318521b265f60a449e66567840734ec26c6f": "0x000000000000000000000000000000000013537562736f6369616c204d756c74695369670019687474703a2f2f737562736f6369616c2e6e6574776f726b000000001040537562736f6369616c436861696e000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047143149ce02bbbc85a0f809131fc9ebb8441aec7ae0c271a24d13d129266705fb0fef99aec4c1dbac31": "0x0000000000000000000000000000000000064167796c65000d74616c69736d616e2e78797a000000000c407374696c6c6167796c65000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714314edbaf8df5f693223e082b8fbcf1ff9271ee9630974f9807c33d3beaf0463d069be5e59f2e9e7c": "0x00000000000000000000000000000000000c30784669736865726d616e01010101000001000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714315041883e0df8a8da6a7b717c79a7c7737652894ae316e658fe616977042aa4b41bb9bb1b108371": "0x0000000000000000000000000000000000084d616d61446f7400000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471431511477c988aab2e875fa3fb75a0c715e26e7aceaae87e2c8a158b4e6cd5732985efb48b7023474": "0x00000000000000000000000000000000000645696b61730000001765696b617332304070726f746f6e6d61696c2e636f6d0000094045696b61733230000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714315b69d6d9952265924cf81bb5b38134cd8676c29a495f7277ff111b6a1bb6b22caf80d32a1b5c57": "0x00000000000000000000000000000000000c48656c6c6f204c75696769104c75696769204c75636172656c6c691f68747470733a2f2f6c756967696c2e61727473746174696f6e2e636f6d2f00174c75696769417274776f726b40676d61696c2e636f6d000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047143161b54cf940118e9aa6373b24df370b863773f45f2bed6ebd80c886c58b4232e655a9b130b6d615": "0x040000000002000000000000000000000000000000000a426567696d6f74696b000000157361617066697269756d40676d61696c2e636f6d000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047143168f24ac9fff4d65e576cdec1179c77d81cca7e34d35784bf47d6667300642a7697403deb967d37": "0x00000000000000000000000000000000000a7374726f6d626f6c6900000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714316c889b24fdb42688040f8566edb50fd272f65b2f232a8008fc9d1127b8d543b529306c4ab3ee65": "0x0000000000000000000000000000000000094d6574612d67757903416e000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471431747b68fd9a8689a0e1a33870981aa76012429e64409e7445f64ba6b3bf75a2e0c97ed51179a64f": "0x0000000000000000000000000000000000086e796d65747661000014406e796d657476613a6d61747269782e6f726700000009406e796d65747661000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047143174bf5b787aca25e277549039e36cc29f87b3faea4cdc1957238e41a88fe7702eb6486c618f4366": "0x00000000000000000000000000000000000000000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047143182c3bc7056e978c6c42b648b7ba1fe5c4395c5d0465b522e3fcb7b82d8839526fb4384a8d57130": "0x00000000000000000000000000000000000e53746572656f6772616d417274034d4b00001873746572656f6772616d6e667440676d61696c2e636f6d000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714318ee29c136c23ba24d6d7cd9a0500be768efc7b5508e7861cbde7cfc06819e4dfd9120b97d46d3e": "0x000000000000000000000000000000000012537562736f6369616c204e6574776f726b001a68747470733a2f2f737562736f6369616c2e6e6574776f726b000000001040537562736f6369616c436861696e000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471431946c413eb637175681edd930e8ed28fb6d74c6d4ddf28067e73e562bd0fe5bae97eb943fa07759": "0x00000000000000000000000000000000000e626c6f636b736272616e646f6e086272616e646f6e00000000000f40626c6f636b736272616e646f6e000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471431a1b217ee0ca06caaad489ec818806f0fe0474670170482c6c30c637cc9346895f4829799d3b73d": "0x00000000000000000000000000000000000a4b6f542d4b6f4b6f4301010101000001000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471431ab29bb118a97e0641fc26bf772a415828c28c203d3058b65171ba36adfae02eee832c6ae723e09": "0x040000000002000000000000000000000000000000000a636176656d6161616e00001640636176656d6161616e3a6d61747269782e6f726713636176656d6161616e40646d61696c2e616900000c40636176656d6161616e5f000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471431b2fdb72ea0daaebe0b3284497d66688f69f915798eb39419480581d8af1d947081cccf478c3a7c": "0x00000000000000000000000000000000000101010101000001000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471431b53430fbb80701a6b7a488577dc9c35aaf6fd9cdb6959eed7d73764ef4909330aeb3179315c921": "0x0000000000000000000000000000000000086772656e6164650f726f62696e207468696a7373656e0f68747470733a2f2f726f622e746e0014727468696a7373656e40676d61696c2e636f6d000009406772656e616465000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471431c600177e63ce4012e3ea2518656228d1b018a56cf4f968a33342cef3a03eb86a0d7d93cd1a856e": "0x00000000000000000000000000000000000b736164616d626f6265720000000000000c40736164616d626f626572000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471431c6b74df11dd22926219557f2597e5d6194b4c8f9b23570220d6cac37f05fe10e8f780dcc0c0a22": "0x000000000000000000000000000000000008736d74616e30780000000e6277354070726f746f6e2e6d6500000940736d74616e3078000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471431d0fa954fe513fec6f2b101590b7bd089df91f5c01093b83217ffcd1c6867c1512de33cff1f5e06": "0x00000000000000000000000000000000000d4d6178446f744465764b736d0c4d6178204b534d204465760000156d636b7261766164657640676d61696c2e636f6d00000f404d61785f5f4b7261766368756b000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471431d8dbf29af0af35f0b64148873fede866ca5f0c92fd48bf6eadbe447d71dbd331f83f0555ee044f": "0x000000000000000000000000000000000018616e64726540636f6465736369656e63652e636f2e7a6106416e647265000018616e64726540636f6465736369656e63652e636f2e7a61000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471431e2782ae179fbea3a2c6f9e020bc5b17dff66bf280199df9d76dfd0936d912bb75ee8275a64a733": "0x00000000000000000000000000000000000861706f7069616b00001a4061706f7069616b3a6d61747269782e7061726974792e696f1261706f7069616b407061726974792e696f000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471431eb5724c95ef0d7f883366aa0218141016c6bc826e0ec376bea1e39b119dc1f402ac6f5964e9f69": "0x00000000000000000000000000000000000c43756c7475726120332e300000001a736f6d6f7363756c74757261332e3040676d61696c2e636f6d000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471431f2c7371b41417c08be3b4777517573d95a82ce78b6833c4db0092078a6dabffddc699905a2f013": "0x0000000000000000000000000000000000096e62307564696162010101136e626f756469616240676d61696c2e636f6d00000a406e62307564696162000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471431f8c44fbe7173049c1bf5e2ebc5301283cfbc96e83265efa80b326b5fbf5a6845c2c26fbef17c3a": "0x00000000000000000000000000000000000f616e792d636f6e74726f6c6c6572000000186d6f6e657963656e746572697140676d61696c2e636f6d000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714320eb468db7ea3c7aeb9fc068a3340edead118ac3cf3decc6743724cd5fb11edebaa98b540a08f07": "0x00000000000000000000000000000000000a59756e672042656566001b79756e6762656566626967626167732e6d656469756d2e636f6d184079756e6762656566332e303a6d61747269782e6f72671a79756e67626565666269676261677340676d61696c2e636f6d0000104043727970746f436f77626f794f47000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714321d91ef1d84c6471ef2167f2d144a220bdd1dba23aca800112c04f027d5751f9518f021394ae515": "0x04040000000200000000000000000000000000000000135a656e6c696e6b20466f756e646174696f6e135a656e6c696e6b20466f756e646174696f6e1568747470733a2f2f7a656e6c696e6b2e70726f2f1840766963746f72795f76616e3a6d61747269782e6f72670f7676407a656e6c696e6b2e70726f00000c405a656e6c696e6b50726f000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714322c4a1c125cf6126053336ac8500f1ab1d771ba627a5d555d22eea84ad860a37a137aefa31bba4d": "0x040100000002000000000000000000000000000000000b414e414d495831303030001468747470733a2f2f616e616d69782e746f702f1440646270617474793a6d61747269782e6f726714616e616d697840706f6c6b61646f742e70726f000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714323ac9ca334c2bce400a075c48b7985fad91dda0b168b2185958c9fee280f145d2dfe24958a12737": "0x0400000000020000000000000000000000000000000017f09fa681204c454f5354414b452e434f4d20f09fa681001568747470733a2f2f6c656f7374616b652e636f6d15406c656f7374616b653a6d61747269782e6f72671974656368737570706f7274406c656f7374616b652e636f6d00000d406c656f7374616b65636f6d000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047143245cbbc0d5339b2f4158285b53521c4304c0524941fc1fc64ac08a54b48a45448045248cec18925": "0x000000000000000000000000000000000021504f4c4b4157414c4c45544d41494e284b534d292028455854454e53494f4e2900000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471432534b4132eff74f56d29c67120f126ad44692c0fba5dc3ca6562485bdfdac135c7e5fb549694545": "0x040000000002000000000000000000000000000000000a50695f3331343135390000000000000c403331343135395f50695f000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471432540ee9d648f9c790c68164d33e35017d4303436b705e60fa485573f6531d1eb503a6b0b863e63d": "0x00000000000000000000000000000000000859616b616d6f7a00000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471432667cae2c5726a94e544545258bffbd3739e69d0b3681ddfc7da593e4de4d3b709ba9625ad2a962": "0x00000000000000000000000000000000000f6b696c617565612d7061796f757400000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714327fdfd66e528b9662d8c4e1c6fbab57ba4df15b8120db4cec5c150371d0755d8ee5312382f47f09": "0x00000000000000000000000000000000000b435249534e475559454e002168747470733a2f2f7777772e6c696e6b6564696e2e636f6d2f696e2f7472756f1740637269736e677579656e3a6d61747269782e6f72671e7472756f6e676e677579656e3139373139393940676d61696c2e636f6d00000a40637269735f76636d000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047143295418a4c4962cf587a4c5c081f8bf812c0b3824bc9fbd42d39809323488a81769f4699ef2f0e51": "0x0000000000000000000000000000000000056c69616d01010101000001000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714329d31b54575b3148222952107095b593c6b7b300a4936b35d5064c55f7eded395c3022488510c58": "0x0000000000000000000000000000000000064265636b73064265636b73000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471432a8d229e117b02904588a18498ca81fc97612420c9268aee42e4fcd4d33bdcaf34c0246f787e659": "0x000000000000000000000000000000000007736875746b6f107665726f6e696b6120736875746b6f0000187665726f6e6e6176736567646140676d61696c2e636f6d00001040536875746b6f5f7061696e746572000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471432a941ceca936305eef0f6b882a5ab6c4798da18e4dace54e39a476e5299d7d6b5a84181b7495420": "0x04000000000200000000000000000000000000000000044b534d066c6972617900001461727573753239303640676d61696c2e636f6d00000d4070756b757075796f746169000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471432ae0c69a5fa3b31b4425e543594e2c64686f9be729eb42f8402f00485ba4d778c7965b0c70ffb30": "0x0000000000000000000000000000000000067175657463000000000000084071756574635f000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471432b4607867325af47e34eeb5e6312c8dabdf13264e7724f9eeda65214e8d45ef1aa63646bc90bd63": "0x00000000000000000000000000000000000d4b7573616d612041636964200000001273746563636f6740676d61696c2e636f6d00000c404b7573616d6141636964000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471432bdcffa7889f0078cb9e71e14f09dafab743396e139bead9dc662abafc0039c74cccfab1fc7346c": "0x0400000000020000000000000000000000000000000015f09f91bb4469676974616c47686f7374f09f91bb001a68747470733a2f2f6469676974616c67686f73742e78797a2f1d40706f732e6469676974616c67686f73743a6d61747269782e6f72671763727970746f406469676974616c67686f73742e696f000011406469676974616c67686f7374706f73000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471432e3ab575cc440288693796a66327edfad41d99ce9606316637ed9f553d61c43f0b4a658d6b4c170": "0x000000000000000000000000000000000008416c69204e46540101010100000a40616c695f6e667431000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471432ed1c932b701c300e993f475e1085cfe2d313b1089c3fbc33c78c178ed19bfc94be3d7937709371": "0x040400000002000000000000000000000000000000000a54726164657769736500000019726f6d616e61726e6f757837373540676d61696c2e636f6d000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471432f20048368ac529387f657be6913b17c0d5ad2eb24d10cbbd319e142f39c60a000b175744aaad42": "0x00000000000000000000000000000000000a42697474656e736f720a42697474656e736f721668747470733a2f2f62697474656e736f722e636f6d00196f7065726174696f6e73406f70656e74656e736f722e616900000c4062697474656e736f725f000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471432fa3d1c089ff9ebfe88f2849c8b51127fefbb618de330c811b4092da0b9272edf2b8b7fddc05c1f": "0x040000000002000000000000000000000000000000000a375468756e6465727300001640377468756e646572733a6d61747269782e6f726716375468756e64657273323140676d61696c2e636f6d00000c40375468756e6465727332000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714330184541fb770392c11ec1e01ccd10cc21bab08d2ce15deaba048bb86b1ddba8fc51e1a988d9a51": "0x00000000000000000000000000000000000b5374726174757332313100001740737472617475733231313a6d61747269782e6f726700000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047143303b463054555c594b84205e26b1239950cb66fad5f97873a7a3b60a5b8a0e5d648b07c936f451d": "0x00000000000000000000000000000000000a6c756e6172747970650000000000000b406c756e617274797065000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047143305daa457b057898c8448f9c214a50cf2419b6393994e0ebf1f6ecb2be98156fb611c9300f4075a": "0x0000000000000000000000000000000000064375726c7900000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047143308804a76f50044ce6e3dc917919ccb44e66c8a5d4c693b96265d5e7072433971fb38d083d0587e": "0x040000000002000000000000000000000000000000000a546f6b656e6765617200000019726f6e6e656c73696d6d6f6e733640676d61696c2e636f6d000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714330e295310ab558958d00cc86df5a4d8320764ef4b5f0cf4ff21ebba4355b58a8845814102060d53": "0x00000000000000000000000000000000000b5a756b6920426c617a65000000154a746f6b616e363940686f746d61696c2e636f6d000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714330f2a703c07a43ded1d56154af1862efb63fc12298d73411b024a7b5312346ca95effe7011efec3": "0x00000000000000000000000000000000000e4a6f73696168204b6f747a7572144a6f73696168204a616d6573204b6f747a75720019406a6f736961686b6f747a75723a6d61747269782e6f7267184a6f736961686b6f747a75723340676d61696c2e636f6d00000f404a6f736961686b6f747a757233000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047143319feb5b0bf9d1f5001f6559f948d59e184101e646c568bb7ef13efb4db683d7a7ec3addc20913d": "0x0000000000000000000000000000000000084c656d7a79706f00000000000009406c656d7a79706f000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714331a1a8d88aca78396f39b336285f5069eae5651dd6f48e1552d55939e6175f0321becc3f1b2ef72": "0x00000000000000000000000000000000000954656154726970731154657265736120416e746f6c6968616f197777772e626568616e63652e6e65742f746561747269707300197465727279616e746f6c6968616f40676d61696c2e636f6d00000b407465615f7472697073000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471433370a1e53cb424dc47e87dfcd927cc014340f95d4a35f94eab0a418753ef596364955a0ffd85e00": "0x00000000000000000000000000000000001d4c6f6e67204e65636b204361706974616c204d616e6167656d656e7400000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714333ac2982066a85918363192e42fe9184f072cb098189ccef8150287fbaf0014859917c0aecd4e65": "0x00000000000000000000000000000000000867656d626162610b646f72756b206f67757a127777772e646f72756b6f67757a2e636f6d0019646f72756b6f67757a4070726f746f6e6d61696c2e636f6d00000b40646f72756b6f67757a000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714333c08553d75ed2cdab8ba7a028d62fe9a5088e46acdbd2039f01abd8baa7c695d9377661c3d406d": "0x040000000002000000000000000000000000000000000664616b6b6b0000124064616b6b6b3a6d61747269782e6f72671464616b2e6c696e757840676d61696c2e636f6d00000840646167696465000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714333e68c5f182853d28dd66875b9cd452d1d72193557b6b3dd0d90b32ea9c9e3f45657cf0add29919": "0x0000000000000000000000000000000000035430000000000000084054305f4e4654000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714333e840aee386d7c1e0cc20dbeeb37538f83781aec7f2f707c665037681183092a9066d0a7c8dd20": "0x0000000000000000000000000000000000105461746f696e65506f6c6b61646f740f5461746f696e65204b7573616d6100001b6165646a656e6775656c652e69636d7240676d61696c2e636f6d000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471433446753bac3f7d8d49e16d1c4f6a051815c5865058cb218fe7d460fa893907bd0cf8596b493f45a": "0x040000000002000000000000000000000000000000000a676c617373666973680000134064616d6173713a6d61747269782e6f72671a676c61737366697368406879706e6f7469632e67617264656e000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047143356311bfa9f24835225293d2cd9e6ded0d8c2326e3e83db641db1660dcf04cabf1996e3bb586654": "0x00000000000000000000000000000000000a42554444494553c2ae001e68747470733a2f2f646973636f72642e67672f39485362515137677077000000000c40427564646965735f5374000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714336272cd90b6e25af6ef7d80dce5697e079078de31bf5d55ec6b9b19b999062fbee55172c48eae22": "0x00000000000000000000000000000000000e4a42204b534d2057616c6c65740e4a757374696e204275746c65720000186a62406f726967696e616c6368696d6e6579732e636f6d00000a4069616d6a62757473000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047143370e35af77dde916cf513881f519aa8ffa7b6631e934e954afba13b14629e9683c20d697fbf5d5a": "0x0000000000000000000000000000000000064d6176656e01010101000001000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471433816f27c89df87b3c10f599d47ddb88464f7785a359a32f844b08df8b934a997c6dd8c355beba03": "0x00000000000000000000000000000000000a4d6174742049736871104d6174746865772048696c6c696572000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714339633d10397f8728c4631b84124de831cc1d9c74c40b9ff4408faa6ee9bc04dbf133afeac872f41": "0x00000000000000000000000000000000000d4b414e4152494120323135300000000000000d406b616e6172696132313530000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471433b7c4e68d541ee54c8510f693bac7c4f1b5eddabe8b18acb255bfbe7d9822f4fcdca22f94809b05": "0x00000000000000000000000000000000000a2e3638204661726d730d44616e69656c2053746f6c6c000017706f696e7436386661726d7340676d61696c2e636f6d000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471433c1a1b7b16e21902cb7a7443e82f0510532b184fd139194ea5d179542bedea10a473c504ac0ab69": "0x00000000000000000000000000000000000550656b6f07596f68616e6e12687474703a2f2f6e6c742e726f636b732f0016796f68616e6e2e6d65706140676d61696c2e636f6d00000b40736f566572794e4c54000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471433c7715ceb944ae1e6583ee03e4f19d6ff1fa84eb9beec7aec0d96a4114a484b5e7a63350144f42d": "0x000000000000000000000000000000000004456b6b0946756e6e7953756e000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471433dcd2db3d5bedf0c68a732184cd98dbf750752cd4ddfef8435da930c06bcd207c8a1059bea0ad49": "0x04000000000200000000000000000000000000000000046b6d77000000147a6c6174617574736140676d61696c2e636f6d000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471433f0f3849914660f162eed692523a2755714b288f9b18c4775c3673da41a7935f7bbf669bc5cc27b": "0x0000000000000000000000000000000000114d61676769652074686520426c61636b0000001b6d61676769652e626c61636b406d61696c66656e63652e636f6d000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471433f1232919bc79e13a81aea610fd2332295967d1c7846599774a112f2d6cf7e3ebe92392b7b17779": "0x00000000000000000000000000000000000661f09fa5a900000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714340a8e74a21cd5fa14bab5b2a35355fbaa601d9ec4976e05b881f53b5df7e61c56b7a41d0b987733": "0x00000000000000000000000000000000000f48797065204d7974686f6c6f67790f48797065204d7974686f6c6f6779000019687970652e6d7974686f6c6f677940676d61696c2e636f6d00000f40487970654d7974686f6c6f6779000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714342142ada362a590fccd142fbfc7d9a3b55795804456d22d515ad559a57d7e6e2d95c10b42e30c1f": "0x00000000000000000000000000000000000b4f6e697a756b61313731054d616e7500000000000c404f6e697a756b61313731000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047143422f12ebd49b52714cae80b8974ad74a47ee2f104c029601bde0cb7345bb040355a0f89d9745f4d": "0x040000000002000000000000000000000000000000000d4169722050726f746f636f6c094a6f7267652052451061697270726f746f636f6c2e6f726709633474616c797374166a6f7267654061697270726f746f636f6c2e6f726700000d4061697270726f746f636f6c000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471434268d32efe050e902c28aa0f96968db5317f8a199297ba47b1d11cee314125f12fa09cd1e5d1147": "0x000000000000000000000000000000000006596f68616e0101010100000940617269796f6170000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714342d10fd36c3ac43cec9484c231e2d686bc8932300191a43fa515f95c02ceebda09ad8d8f5fc5305": "0x00000000000000000000000000000000001754696e6b65726e6574205465616d204163636f756e74000000000000114054696e6b657250617261636861696e000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714343126692e3c2e4112d49078cd721faa2f041d0cf96e0d8194561fdcb4ced457270e52f209e76c0f": "0x04000000000200000000000000000000000000000000064c6f67616e000017406c6f67616e3a776562332e666f756e646174696f6e1378406c6f67616e736165746865722e636f6d00000e406c6f67616e73616574686572000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047143446a63253264d390c44b382fcf02cb9140cfe395af7409c9dcf90111a4178c91f9f4b72c0bf6527": "0x00000000000000000000000000000000000c537061636520526f737369001b687474703a2f2f7777772e7370616365726f7373692e636f6d2f000000000c407370616365726f737369000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047143480366b70f0bdd226bde67388e055556db32212b34a6b54863a68bde20ee8ac3237c2f8c7e0d748": "0x04000000000200000000000000000000000000000000096e696674657374790000134065656e6e6f6f3a6d61747269782e6f7267116e696b6c61734065656465652e6e657400000a406e69667465737479000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714348d4ac14c12c66a52399f4bea6b67b35c699fa9e62d9e0dd0df8e6b77827f3a597ad59ca120436b": "0x000000000000000000000000000000000008666972656b31640000000000000940666972656b3164000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471434919c833ac161e16244de863562c83bef71d904006f17e4ac8c8d48aa254488993a007ea3293c67": "0x0000000000000000000000000000000000065265656365065265656365000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047143493fe8d1494832ec62cf673ac24528062ca2dfebb72f5d32a0b562620536abe72a8fb7fcdce2c54": "0x00000000000000000000000000000000000854617261676f6e01010101000001000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047143497da8d6cf4d6517ef2c40e61477ca83ac11a69a7d3700758cd7c80fd351b942f33a9860bef5c57": "0x00000000000000000000000000000000000a56696e796c73616d6100000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047143499871fa32ffd0568060f25d5e2559890850d9e7f3090d2892da1bf44ff49e08d879139569af157": "0x0000000000000000000000000000000000066a6f616a69001570617261636861696e6d6173636f74732e636f6d0000000010406a6f616a695f6e616b616a696d61000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471434a85255605692712c9ff1d449d4a433f155b6e0da1c283fab4c3269e4495779ad6f0a29cdf6b170": "0x0000000000000000000000000000000000095061646479626f7900000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471434bafa4989ae96d2126d0c2d4f0884c2e829cd7f63235323c66f7c19cec693117810ac06918297f2": "0x0000000000000000000000000000000000055269636b144d79206361747320616e6420726f626f74732000001b317261662e636f6d2e38382e3838383840676d61696c2e636f6d000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471434bd1b4448aed1acf00168a3d082a8ccf93945b1f173fdaecc1ce76fc09bbde18423640194be7212": "0x040000000003000000000000000000000000000000000d506172614e6f6465732e696f001568747470733a2f2f706172616e6f6465732e696f164070617261646f7878783a6d61747269782e6f726715737570706f727440706172616e6f6465732e696f00000b40506172614e6f646573000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471434c19217b89473a6fcf0d5eccb7d0f8a0aa8a7b204db27cb8428c6576ad7bae55f194238c2aea53a": "0x00000000000000000000000000000000000a456c6f6e204d75736b01010101000001000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471434cd31c4c02baaf40845506f4ace125170d1d1861cb0deac761cfe2b3538d3b80fb4feb465d9885f": "0x00000000000000000000000000000000000b497361616b204c69656e0b497361616b204c69656e1d68747470733a2f2f626561636f6e732e61692f697361616b6c69656e0015697361616b6c69656e3740676d61696c2e636f6d00000b40697361616b6c69656e000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471434cdf837d56a264302302a200a9ead164617576a79dded74ccf9094d6222cdf93ed575422e9f5837": "0x04000000000200000000000000000000000000000000136f6b74616e6f646573206b7573616d6120310000001661646d696e40736861646f776e6f6465732e636f6d00000b406f6b74616e6f646573000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471434e1695e7aec00cd2470066d3011ff4f5a582dc406244cd8ada9972cbc09197c4f746b3cd951fa47": "0x00000000000000000000000000000000000d524d524b2050686f656e69780000000000000d40307850686f656e69786578000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471435050fd58a5fec6ccad8f26d3a6ce0ccd4aa88ef73904ed673267c502f9d1704c8842715ba7ef33d": "0x000000000000000000000000000000000012496e7370697265207820524d524b2023320101010100000a406363776461766964000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047143512543d0def14a69a569de2e5bdfb09afc678d03cf44e576409c90326bae832fa88d114efcc2f6e": "0x00000000000000000000000000000000000d4d69636861656c204b726f7a0d4d69636861656c204b726f7a2168747470733a2f2f7777772e696e7374616772616d2e636f6d2f6d6963686165001b6d69636861656c6975646368656e6b6f40676d61696c2e636f6d00000e406d69636861656c5f6b726f7a000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047143513a7e35abd2c67c46a6bab44a8c15f7c71fc8abbde63bf128fcd626e328b351f8c2861b1183318": "0x00000000000000000000000000000000000000000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471435262d5febf811713c3defa1c97906bb8d689ff9791cfa1825a8ef5e3ff2640d5f76cefed049cdb2": "0x040100000002000000000000000000000000000000000d5562696b204361706974616c001668747470733a2f2f7562696b2e6361706974616c2f1840616e756e746a6f637572693a6d61747269782e6f726715636f6e74616374407562696b2e6361706974616c00000d407562696b6361706974616c000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047143533fb45c1708948625a907225b8ed830c16996d75cda73ef03750b535a6d83ca2ba1246be2dd424": "0x040100000002000000000000000000000000000000000ef09f8fa2204d49444c2e646576001168747470733a2f2f6d69646c2e64657610406f6b703a6d61747269782e6f72670f68656c6c6f406d69646c2e64657600000a406d69646c5f646576000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047143536b008c8bdf5eaa8c65922638840726e9b9203f89734be64b61b2e50cbc85a2d8eb147032c793f": "0x04000000000200000000000000000000000000000000044e4c5a000014406e6174616e6c7a3a6d61747269782e6f7267186e6174616c6164617a6c6174614079616e6465782e727500000d406e6174616170706c653133000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047143557b2fa873c85d70251da37e1b58a76ce238547801127124fa17d3010baff384a2da3bd52961257": "0x00000000000000000000000000000000000f4e46547320464f5220434c4956450000000000000f4043727970746f436c6976657273000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714357f962bde6d00d270b553b4cbd93585c4dc2b13699e960a1f8fd5f31f50f304106a2bb8aa2cad64": "0x00000000000000000000000000000000000b727566696e6f66756d6900000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471435868ac081666f4192f0611c424502b047a7052dbd07846e2d01f757a99db50b825984409b44cf6d": "0x040100000002000000000000000000000000000000000c44535256206b7573616d61001568747470733a2f2f647372766c6162732e636f6d001776616c696461746f7240647372766c6162732e636f6d000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471435891656bf938dec687940be7bb769432186706f4e9167f078bc2f092bb445c6f2fd6c617f64e556": "0x000000000000000000000000000000000009325468654d6f6f6e145374616e69736c6176204b6f6e6f6e656e6b6f001a40737461736b6f6e6f6e656e6b6f3a6d61747269782e6f7267186b6f6e6f6e656e6b6f7374617340676d61696c2e636f6d000010406b6f6e6f6e656e6b6f5f73746173000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714358c4c1a81950208d4b4f2d7581dea1c5b32d601fea80468da90b7c8a66ba5b8ee0612c0b368d363": "0x0000000000000000000000000000000000074a757374696e074a757374696e01010100000c407a65726f70726f6f6673000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714359d405fa784835ea8a89367cac10048b8e025cda5e0e391f4664b4c97b50377685e65ba09a5a460": "0x00000000000000000000000000000000000000000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471435a390c3506c1387482a9a411b630d2c3f850f435c4566a6a93143422e6cce181320f022a7451236": "0x0400000000020000000000000000000000000000000012537465616b20e299a8204e6f6f646c657300001e40737465616b5f616e645f6e6f6f646c65733a6d61747269782e6f72671a737465616b616e646e6f6f646c657340676d61696c2e636f6d000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471435ae67dea62435324ccd96ab1b42e8a1a0cf69f0eec21200f9a8095c4da99f44d14c5181f3955a07": "0x00000000000000000000000000000000001154686f6d6173204a657272796b736f6e0101011d696c6c7573747261746f7274686f6d61736a40676d61696c2e636f6d00000c40544a657272796b736f6e000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471435ba3891cd5a1f1af4d1d7ee3de4691a94c7691da5d29681cf0c7e01b283c8741c32d6e712fdfc2f": "0x00000000000000000000000000000000000752796f7368690000000000000b4045734a617966697665000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471435c408ac02c2a02dfae63fdb20e3ec7589586b14ea019731b5089e2d1b22a7911e48603a5939780c": "0x040000000002000000000000000000000000000000001df09f8cb2f09f8cb3506c616e7420412054726565f09f8cb3f09f8cb200001940706c616e742d612d747265653a6d61747269782e6f72670f6c6a7564766140747574612e696f000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471435dd86d8f494ed5b3a33330086b97b130e60e53e5f19a7aefd249bfe935abed57adb19fed0525074": "0x000000000000000000000000000000000004417368074173686c65790101196173686973686d697474616c383640676d61696c2e636f6d000001000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714360a99286860e95d9e3209ee615fbeeb2803b78f79e38d2750b261d2cdf03aee378953ca5187702b": "0x00000000000000000000000000000000000953696e6f7661373900000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714360c398fd5e777baf6d6531d9623034efed118d00dc62831eb6f017dcb45d66ec6af44947ef41431": "0x04010000000200000000000000000000000000000000064461617665000000176176696461636f6e74726f6c40676d61696c2e636f6d00001040426c6f636b636861696e65723931000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714361c04bb87dbdc8fded1ee76b3793ee4765d0e4ae3810234e2bdbfa5b7b9368d53e8097269106d53": "0x00000000000000000000000000000000000a4d696775656c446f740000000000000c404d696775656c446f7437000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714362e63bff395d5365ee1d8f4e275365ce386eca5dced8da68495954da5df694191446123b64d3950": "0x00000000000000000000000000000000000c42656172204772796c6c7306526f706572010114642e726f706572406f75746c6f6f6b2e636f6d000001000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047143664fd682b63101efa1946d3fbddce1df50333701d2a14f895517f6c3144bfaf0b5ac25892f23672": "0x00000000000000000000000000000000000a43696369205279616e0a4369616e205279616e00000000000c406369616e7279616e3932000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047143673545187abf2d44221843a04508635174403b3840ebffbc6c5f487373a75507291fe72019b8421": "0x00000000000000000000000000000000000a547269636b737465720b566961636865736c61760000124f72736f6e303640676d61696c2e636f6d00000f40547269636b7374657230363036000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714367c0b2407c22e99e22baee6a790a63088620f7483290c83fcb3337664866cd8d239568f7554bb14": "0x040100000002000000000000000000000000000000000d4a6f7365206e6f2d6e616d650d4a6f7365205261626173736f1868747470733a2f2f7777772e7261626173736f2e6e6574184073656e7469656e747275653a6d61747269782e6f7267116a6f7365407261626173736f2e6e6574000009407261626173736f000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471436805becc0cd7ecd46da7c288e4b28a5db64dbd221bbb75850708c556753300df83dd36b4c31c37a": "0x00000000000000000000000000000000000e50696e6b6b75726f736869726f054e656c6c00001c4e656c6d61727973676f6e7a616c657a406f75746c6f6f6b2e657300000f4070696e6b6b75726f736869726f000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714368ce1bdc40db94c34f589d251903b0ac5a22b1d13d54696fba34b77f5d21f5244de907171144763": "0x040100000002000000000000000000000000000000000850686f656e69780000001974616b65616e797768657265343540676d61696c2e636f6d000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047143698794decef314ba1ada2749f3674b54120e643601edab41454b61285f7b1cbc38fa55f3f94ab5d": "0x04000000000200000000000000000000000000000000066a6f6e61730000001e676568726c65696e2e6a6f6e61734070726f746f6e6d61696c2e636f6d000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471436a17a0db79ef688c664fbde2dbcea2d4180fc9e285ac56ecb6f89a9b88cbee9b407bbceea7da912": "0x04000000000200000000000000000000000000000000084361626c652d58000012406361626c653a6d61747269782e6f72671e6379636c6f707373756d6d6572734070726f746f6e6d61696c2e636f6d00000f4073756d6d6572735f6361626c65000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471436afe30a6f10936740d5602a0093ad63f7581091f78e184f8095d3796c36087d4b663b929dba6002": "0x00000000000000000000000000000000000d6b736d2077616c6c6574203100000014373337314070726f746f6e6d61696c2e636f6d000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471436b6b4230572c15c9ef933abec7bfe3aeefa46b090f763be83a92b954ad2ffb6460dd0cf21279e22": "0x00000000000000000000000000000000000842616b686d616e0b566164696d2042616b6800001a62616b6874697961726f763139393240676d61696c2e636f6d00000b40566164696d42616b68000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471436becd4b5e8bdbbe828618dad92559461b479508086bc781d88434e5372229cf66ffc887672e9b34": "0x000000000000000000000000000000000009636f6c646d6f6e6b01010101000001000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471436d932ff657abe1ab25aad24c981efce7f02bb55dd5a4f1628f46162e297dca06eb78138ed10ba44": "0x00000000000000000000000000000000001942756666204368696d707a20436f756e74727920436c756200000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471436dfb954fb0e362388c0101e6310fd486b69ae18fae2985fea205d8a9c6de956070d71a69a8d3f66": "0x040000000002000000000000000000000000000000000a43525950544f4e594300001240626f6764693a6d61747269782e6f726717696e666f4063727970746f6e69632e6e6574776f726b000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471436fa711136f55b2b60021c1dff88ff90ebd476b7bfc172d30c808f1629ef5df7685da36526e79a54": "0x00000000000000000000000000000000000f496c61696a61204d616b656e7a690f496c61696a61204d616b656e7a69000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047143719f7536919e4c0b2b3d5e18f8226115c2327ded2029a6308b4e8274f0b5f529b3a6e58dec46176": "0x04000000000200000000000000000000000000000000086d65643076796a000014406d65643076796a3a6d61747269782e6f7267146d656430303076796a40676d61696c2e636f6d000009406d65643076796a000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047143721f074825b67fc14e5b21d2eee0865adfb8783ac900540d67f0a89eb6881e77dda91d509398809": "0x040000000002000000000000000000000000000000000b476f6e74614a6f6e657300001740676f6e74616a6f6e65733a6d61747269782e6f72671c6172747572676f6e74696a6f4070726f746f6e6d61696c2e636f6d00000e406172747572676f6e74696a6f000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714374fc4337ebaecf75651449de27895f5da18dff76cf3fa3f1b1cf468b873d7a3e16adf7fd5187d55": "0x04000000000200000000000000000000000000000000094c454d4f4e4f4445094c454d4f4e4f44451a68747470733a2f2f6c656d6f6e6f64652e66696e616e63652f000000000f404c656d6f6e6f646547726f7570000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047143753decbc1ae388b6849627c337067117e864eff154c6125539fa6e4eaa980712e7594cf78447874": "0x040100000002000000000000000000000000000000000e416d696761205374616b696e6700001940616d6967617374616b696e673a6d61747269782e6f72671a6f70657261746f7240616d6967617374616b696e672e636f6d00000e40416d6967615374616b696e67000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714375546d9339430d36aa9e19b08ef554ef0b123940b685c0d64eabd9a1ec487e43bb7e1f3d981c062": "0x040100000002000000000000000000000000000000000e434f534d49432d474c4f42414c17436f736d696320476c6f62616c204e6574776f726b731668747470733a2f2f636f736d69632e676c6f62616c1840636f736d69635f746f6e793a6d61747269782e6f726716636f6e7461637440636f736d69632e676c6f62616c00000e40636f736d6963676c6f62616c000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714375605537adb7dfd3d6d2d20735ec00c7753d3e6071ad1e2280288a98d7d89c2a2b7fe08bf6d05bd": "0x0400000000020000000000000000000000000000000015506f6c6b617363616e20466f756e646174696f6e14537469636874696e6720506f6c6b617363616e1668747470733a2f2f706f6c6b617363616e2e6f72670013696e666f40706f6c6b617363616e2e6f726700000b40706f6c6b617363616e000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047143757d549ae01bcfef051c7e4fd453fe6e12e042c745c19c8eac609babbb08cbc1c469a06d3aa9f31": "0x0000000000000000000000000000000000097370696e7a3830380000000000000b407370696e7a3830385f000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471437635025e9b9216a08323e67f700f051d8178b6c4d82c7b2b8c9c3972f44e6dc368eea43dbe9c723": "0x000000000000000000000000000000000012736861776565656ee5b8b8e794a8444f5409736861776565656e000017736861776565656e6368616e40676d61696c2e636f6d000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714376fe373bcf08e5136b08600b83f68dae5db739d3102ef8c8f0534ed6739d2c2c9406bc5e0cd5614": "0x0000000000000000000000000000000000084d465f313333370c5375627371756964204f47107777772e73756273717569642e696f000000000a40495f313333375f49000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714378b219e43b8dedff0fd6298e6d06eefc52fb2f12dc1a6ff9e8958ac2a3efebc7f5673dc33808170": "0x040000000002000000000000000000000000000000000545646765000000176a61636b736f6e73656467654070726f746f6e2e6d65000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714378e64dbe1bafe2d68d2af8a0969437cbf470fcbc5ec5be7fc7c2acc6cd55f31e218b313fd1bbf7c": "0x0000000000000000000000000000000000134b7573616d6120706f6b6c61646f742e6a7300000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047143797aae91cb5418606bc6642d5cf9a96b25c4509ea48bcd739b9526d223d03db0fae3782647a914d": "0x000000000000000000000000000000000009586f6c6169646572074b6972696c6c0101146b6972696c6c5f73683838406d61696c2e727500000a40786f6c6169646572000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471437a030aa0334d1657a6d8b7ba3e9dc84d388f900d7a6d7eba875584a4230ba14e5923703d344ae59": "0x000000000000000000000000000000000007436f6c70746200000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471437c6690c1899a9f13208723ec642760b572b0ff8037d63d49f4d2e95875027fa85080cdff65df810": "0x00000000000000000000000000000000000d50726f6f666f664368616f7300000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471437dd5e6545f30f91146ebb6c9c8a8953adc846bb66a7067792d2b79480f784b77da11f0556b05038": "0x0000000000000000000000000000000000055361626908536162696b61680000117361626f6f6368406c6976652e636f6d000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471437ea3876caf984faa2a383db2910f8be8539704063de71c60aa9f4d2509eabc5ec04acd7d7601e4b": "0x000000000000000000000000000000000016496e666563746564205375627374726150756e6b73002168747470733a2f2f696e6665637465642e7375627374726170756e6b2e636f6d000000000f40496e66656374656450756e6b73000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471437eabe2d897b2b72548da96d92f51656ca4932bec228b08d0a0d42a55ee6dfdf7d674bfab3509e4b": "0x00000000000000000000000000000000000f42696e616e63655f6b736d5f32370f42696e616e63655f6b736d5f3237000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471437f4c44a1802b5597a079b843efdcc1361e62bfe5767fd1f49ea2e255cc8b517675d8b33cf231d64": "0x00000000000000000000000000000000000c546865417274426f79797900000016746865617274626f79797940676d61696c2e636f6d00000d40746865617274626f797979000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471437fc013628a8c12f22fff76bb4a0a5d66cff0392dbc083abbac3b3046f6fcc328abf0ddd16ca0837": "0x040000000002000000000000000000000000000000000f53696d706c79205374616b696e67000000197374616b696e674073696d706c792d76632e636f6d2e6d7400000b4053696d706c795f5643000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714380d8f9827969150946e7b9165c3228654b593ea90a5130b0f137fef6f8af691990b4d4ac0b27076": "0x000000000000000000000000000000000007414c4144494e07444d5954524f010101000001000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047143815dfeb687a9a1a2a951179aed88b7e507173ad199175237ae2c4861d242d441a77183975bbb453": "0x00000000000000000000000000000000000101010101000001000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471438172c8cfb5a713e5a718199b3c87bd8c24c35f027b2b4ba2789a85782a79cc6a924f9e4241c3005": "0x0c0000000002010000000100c8e6bc17040000000000000000000002000000010010a5d4e80000000000000000000000000000000000000000000000000000000b534b59534b49505045520b534b59534b49505045521768747470733a2f2f736b79736b69707065722e65752f1640762e7265697a7669683a6d61747269782e6f72671f736b79736b69707065722e76616c696461746f7240676d61696c2e636f6d00000d40536b79536b69707065725f001e68747470733a2f2f646973636f72642e67672f6d32794d41776276323300", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714381b3821dcc0437820844fd0e3f22f42daca7eca80593433eb14ecb21dd12da7efd2ae70e2f7b977": "0x040500000002000000000000000000000000000000000954686520446f74731254686520446f7473204d6167617a696e650000157468652e646f7473406f75746c6f6f6b2e636f6d00001140546865446f74734d6167617a696e65000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047143820161e5d657db05a63e35210da6bcf2d3ceb1720f65a7ea196cbb946768acaa184c732921c1f15": "0x00000000000000000000000000000000000f4d726973686f204c756b616d6261144d726973686f2048616a69204c756b616d626100000000000f404c756b616d62614d726973686f000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047143821f1ccdde80ab1e63e926f7d2f4b279925ff3eda433d1c619c315bcb690dd02392fc9cb5997e5c": "0x00000000000000000000000000000000000750726f7475730c44617669642050726f746f2168747470733a2f2f747769747465722e636f6d2f7374617267617a65725f7373000000000d40646176696470726f746f6d000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714382e1e172c05a7dd7e7de858372bdac26ad50af6e76207a55fb089414348a70cd32926e8e9f4c76d": "0x00000000000000000000000000000000000d54594c45522044555244454e00000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714383198d18bf4db66169b1ca15010ef10b423afee4c0fca7e42f745b39e1fe4197436ec352b7f1708": "0x040000000002000000000000000000000000000000000b54525553545354414b4500001b406665726e616e646f2e726f73736f3a6d61747269782e6f72671f6665726e616e646f2e726f73736f2e6974616c7940676d61696c2e636f6d000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714383d396eac9d6d803aca2dd5f8e9ae8f6c34fdf662ccc8582f19712716ead453187133753461a717": "0x00000000000000000000000000000000000744454442554407446564627564000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047143860568a1fbdad6c42b7d1cc48edb9374f8db31026a470a1ec19b7ccdaa262c341e6fce2375d022d": "0x000000000000000000000000000000000009546165546165383200000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714386936040fec0a1e4499a095307a2c2c62cb6875915e9a9e2effbe99e2b3c5785dc46a4a57df7450": "0x00000000000000000000000000000000000542616b7500000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471438696a3c3a114b3a3661355b125f90d7764098692927e1b80a2a8609a90378ff6a7a6689e560a407": "0x00000000000000000000000000000000000474757400000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714386a2f35e87b835c78283798169eabf7cd6924745cb60df616354b36e53549fd8dd71e815386f525": "0x040100000002000000000000000000000000000000000d45524e2056454e5455524553001968747470733a2f2f65726e76656e74757265732e636f6d2f001c65726e63727970746f76656e747572657340676d61696c2e636f6d000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714388551d2e84f8ac29457c6d96254f5e60f77e53484319beda30e5b83868ee522ed88437a18cd4338": "0x0000000000000000000000000000000000034b4a000000000000114077726974656f6e746865626c6f636b000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471438923e8a514e5d000ab0b61984dfcfe2fcb82147f0a2f00f992fa8a6b5ee81490387f8210a1ab678": "0x040100000002000000000000000000000000000000000b496275696c74726f6d6500001740696275696c74726f6d653a6d61747269782e6f7267176e65696c2e76657263686f7440676d61696c2e636f6d000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471438986317de84f44a3aab02d159dca8d84bc9aea8c42341281111885ff6be86c075ac673b5bf4dc10": "0x0000000000000000000000000000000000134b6f6461446f745f657175697061626c6573084b6f6461446f741468747470733a2f2f6b6f6461646f742e78797a0000000009404b6f6461446f74000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471438d4ac73c1121041b656e5ed45717d0c904cd18e4cfa9295f360e1cfb2a6d0a17859d5354118330b": "0x000000000000000000000000000000000004526164000000197261646d656e6163654070726f746f6e6d61696c2e636f6d000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471438e0f5c9b6d45fdea0fb0c1cb29f31d2efb81ae72ca3ae59b95bd082afa8c6046ac6ad5245a2ab0f": "0x040000000002000000000000000000000000000000000a417065205768616c650c4761727920436f6c746f6e00001667636f6c746f6e3139383740676d61696c2e636f6d000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471438e3b3fa872deb74a0c4801b6d9b3d5b3a26dae883117f4f56f96585431c9ecac4e1daebbf04c674": "0x00000000000000000000000000000000000b3432304b7573616d6120001e68747470733a2f2f646973636f72642e67672f41587250464a32564278001a4b7573616d61343230436c756240686f746d61696c2e636f6d00000c403432304b7573616d6120000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047143904609620d47eabc0256994e3cb4d398c31d072de5bb876fe05d1b958e1d76c70483224c1849364": "0x0000000000000000000000000000000000124d69737465722046757a7a79204475636b00000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471439091716621f04866c5bab403571753ecc61af53a82d7bcc6fbf910c32bb7984a3d9cf92a9ee7353": "0x000000000000000000000000000000000012706f6c6b61646f742e6a7320286b736d2900000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714390c74f4052dd71642a8f4af92bc51e83093eeecb73f2aab526a11c41735ff54d9fc7de54ace5c6d": "0x040000000002000000000000000000000000000000000d50617261636861696e626f790000001e6a6f686e72686f64656c626172746f6c6f6d6540676d61696c2e636f6d00000e4070617261636861696e626f7900106a6f686e72686f64656c233831363200", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714391938c738248b0b3c8bfe3979861faf9f62122a79c84cb49ef9ea9e34299af5886f69fb14987446": "0x0000000000000000000000000000000000144d6f6f6e496e76616465724a696d6d79536b7900000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714393bf648d0b05f8554b568a6e42a8892eca1a8e5c88dd952dde7288d79d35c3b57553767a3987a1c": "0x040100000002000000000000000000000000000000000c656477617264736d6974680000001a736d6974686564776172643139383640676d61696c2e636f6d000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047143940c3c215b77b75a45607c284ca4ff60763ec121d5818b4571092c29bb4cd52b33689c17a87d24e": "0x000000000000000000000000000000000008524f5353414e410e526f7373616e612043616e7475000018726f7373616e6140776562332e666f756e646174696f6e000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714394c7c89d577e2150875ac52744a4a4b13c7ffc879ea121886d94ce994b592f87df88e0943b19e3d": "0x040000000002000000000000000000000000000000000e4361726c6f732053696572726100001c407369657272616361726c6f7331392e3a6d61747269782e6f7267196361726c6f73313973696572726140676d61696c2e636f6d000010406361726c6f733139736965727261000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047143961067d72d621ce64f1ff58ecb85b5c7e3ed681eb7d40bb52f67d2b918159c277a436ba23aaf975": "0x00000000000000000000000000000000000650696f74720000001a70696f74722e647a69756265636b6940676d61696c2e636f6d000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714396327fe5bb731ce1ac32f80dad23cb5f164f496f39291cddfc68ed41f9cb2d57953915c9ddd0622": "0x000000000000000000000000000000000007416973616d610000000000000c40616973616d615f6e6674000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047143977b398db792530b4d42c2aa38aeb839c157991447238edbf1a48f7fbaef96b30c733e769ee1f27": "0x0000000000000000000000000000000000074d61726c7561074d61726c75612168747470733a2f2f747769747465722e636f6d2f4d61726c75614b7573616d6100176d61726c75616b7573616d6140676d61696c2e636f6d00000e404d61726c75614b7573616d61000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714397f26eed6dc09cdae3abb16e30166db6c77a2f24b6e19cc63bd95fc08529bcb05bc71273a762b29": "0x040100000002000000000000000000000000000000000c746d64765f6b7573616d6119746563686d65646576207361726c202d20446176696420531968747470733a2f2f7777772e746563686d656465762e65750010647340746563686d656465762e65750000094062655f64617363000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714398ac470c132d05746cba586963ce742f0f17d705174df4317e773788ebdd7244df0a0ddedcc645c": "0x040000000002000000000000000000000000000000000c4162756a756c616962696210416264756c617a697a204b616d696c0018406162756a756c61696269623a6d61747269782e6f726714616b6461747469393440676d61696c2e636f6d00000b40616b64617474693934000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047143992ed165a8d50830a7aadfd3b852856f9ed55fd5f9cac3b392e33d5aa9811376ede585177b14b1c": "0x00000000000000000000000000000000000e62696e616e63655f6b736d5f320e62696e616e63655f6b736d5f32000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714399bcc09e0ccb2081e808a04d4fc7cce9919d91092bae1466300cf9d5ffd53cee083b6fb9159b16b": "0x04010000000100fc8d0e800000000000000000000000000000000000000000000000000000000e45787472696e736963732e696f0e45787472696e736963732e696f1668747470733a2f2f65787472696e736963732e696f001468656c6c6f4065787472696e736963732e696f000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714399dd3c4804b97eba095019831a2323d245f465af098b4341a7a1cf39bbc4314b2a78a9299f07146": "0x0000000000000000000000000000000000074f4e44494e34000000136f6e64696e37373740676d61696c2e636f6d000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471439a60ff17fca37777ec07e354ed4f92abdd5a1570470994410ad04181deb63229bd98ff39b73170a": "0x040000000002000000000000000000000000000000000e4b454241422d5354414b494e470000184066617469682e6f736b616e3a6d61747269782e6f72671966617469682e6f736b616e2e747240676d61696c2e636f6d000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471439cea59b0d3d75b0fcf9e23d0dbff2b47a4b7e9663399e393783b37c7f73aa42990494277bb43842": "0x000000000000000000000000000000000013506f2d4b7520436861726974792046756e640000000000000c40506f4b7550656f706c65000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471439d774c6a4bc08794a87d67106ab1314e759cf2a52c4a124011bfe5dd68d96d5d43cfbf3c2d9c06e": "0x00000000000000000000000000000000000852696164205a6700000014726961647a6770726f40676d61696c2e636f6d00000940526961645a675f000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471439dbf6701a95ac8db4d7530c51ef3fd16db8e286712250830f98ad4ca9dc49eea4d8da21c810e509": "0x0000000000000000000000000000000000044b424c000000000000074031786b626c000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047143a0d5ce7b9b42aa8680d49ff8449c4b9fec83868efb25e171d2982ff23af49f0815776cf3cddcb27": "0x00000000000000000000000000000000000a4d6f6f6e726976657200000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047143a10e49be7571c32fa2d14476ca490493ebdb00a5ad1c1217d02ed4e100bc74ccd99a9415043dc6c": "0x00000000000000000000000000000000000b656e646f6d617374657200000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047143a29c46317f4f30b2a2ac2efa266a9b1dee45f418586a55232e8421ecf7f35ba47b3fc09743ba53d": "0x0400000000020000000000000000000000000000000008476f6c6f76696e00001740706170616e79797979793a6d61747269782e6f726711706170616e797979406d61696c2e7275000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047143a304428675bf6f7e6247d2909686256b09006b07e758ecc128364a926f1223ef04b38628a5a3a5e": "0x040000000002000000000000000000000000000000000f5354414b452048554c4bf09f91bd00001a407374616b6568756c6b69736d653a6d61747269782e6f726700000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047143a415aff9769824852a7ee3e88746ce662cfc7d016f8ea5c54c90579963c7d43fb7c1e0ee75a7504": "0x0000000000000000000000000000000000096770657374616e6110476f6e63616c6f2050657374616e611568747470733a2f2f6770657374616e612e636f6d00186770657374616e6140686173686d61747465722e636f6d00000a406770657374616e61000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047143a4998c1a7d8244c6819b9b3dab3439825f9b076ff1be1f248fe246f6be57b131d7d10e38b08fd00": "0x00000000000000000000000000000000000b4761746f724b6f727073000000186761746f726b6f727073406374656d706c61722e636f6d00000a40676b31385f646f67000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047143a575ad1c2d80a9bde691421928e0c701ea5599bcc8d42231da832509479317eff32f2f60fe4525c": "0x0000000000000000000000000000000000104d4143405a6f6d6269742e696e666f00000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047143a5afa2fc0fdc1a0b43edb96243d684d0e67b83708e4d62a75c5da73d14aaf3f40d1d1aa4693f531": "0x040100000002000000000000000000000000000000000764616d736b79000000176b6f736d6572694070726f746f6e6d61696c2e636f6d000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047143a631a94e785087a961d31be46eed7329adf7b0fb0c9aab987fa9a7734311077033176b56b36f66f": "0x000000000000000000000000000000000012416c6c65732050617374204c61766f726f15557273756c6120616e642046616272697a696f201c68747470733a2f2f616c6c6573706173746c61766f726f2e636f6d0019696e666f40616c6c6573706173746c61766f726f2e636f6d000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047143aa2de3f651751e4f433983f54fbdb39a76c4b223c0dd127b57d3f82321fbded49efdefb28429b1d": "0x000000000000000000000000000000000005466579640000000000000b4045757269736b6f3139000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047143ab053dc6b6a71e1b4f7f03bebc56ebe96bc52ea5ed3159d45a0ce3a8d7f082983c33ef133274747": "0x040100000002000000000000000000000000000000000f41757265766f69725861766965720b586176696572204c61752168747470733a2f2f6c696e6b74722e65652f61757265766f69727861766965721b4061757265766f69727861766965723a6d61747269782e6f72671078617669657240696e762e636166650000104041757265766f6972586176696572000f41757265766f697258617669657200", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047143ab971e615fdc0ec048320335f4847b229ae3c6484ee07fa89fb804ec120545c3386a4a4d69aaf31": "0x00000000000000000000000000000000000c5374616c69616e6f5f323304504842000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047143ac96963acc241506a3cdc93de8298ac5521a3d59f0dee37394d4cebac305b27d07669c3a5713a0f": "0x00000000000000000000000000000000000d4b5553414d414e4fc38f444500000014726961647a6770726f40676d61696c2e636f6d00000940526961645a675f000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047143ac99439d3775a97566784d696a177184eea3895409ad8a985b82b72d73881678018bb0a1152fb48": "0x00000000000000000000000000000000000c536572676579204c657267001c68747470733a2f2f626c6f636b636861696e61746f776e2e636f6d000000000f405365726765794c6572674e4654000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047143ad0b73fd39c50f8202dc1d566cfa4d8a522c4a70f1a6d6361a103c582cbf4e6671b93f2ca081712": "0x040000000003000000000000000000000000000000001150617269747920426565722046756e6400000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047143ae93558a338096bd02437b89f58ab571676fed672f8b53b35626f3c993ed7741985e9f0d7cd8704": "0x000000000000000000000000000000000005506965740b5069657420576f6c66661a68747470733a2f2f6769746875622e636f6d2f506965576f6c0015706965742e776f6c666640676d61696c2e636f6d000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047143b1b7d5d35c61682a5ce96b7e0f53b8401817a3e592f695c3c268ec05665ca0a4782fc26e5300fd6": "0x040100000002000000000000000000000000000000000b4b4d4c20426172646574084b4d204c6162730013406b656e6f6b6d3a6d61747269782e6f7267166b6d6c6162734070726f746f6e6d61696c2e636f6d000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047143b405b9499dd096722bc38752db2ff96485019da63c5c56727f8e94e3075a20e588a4ac99598b731": "0x0000000000000000000000000000000000054f736f6900117777772e6b72616d65722e746f6f6c7300146f736f696f746f6b6f40676d61696c2e636f6d00000b406f736f696f746f6b6f000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047143b44d8f3097ee1d8741080ece2c165fb6ed98470e4dcff506788f14a5375a9fc5d21f0f78f16c86e": "0x000000000000000000000000000000000005497679610000000000000b40497679615f446f6e67000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047143b484b0dc727b45354825d8d050d0ac046e52f333e820999ac3dacb75f29306eb8233c0caf8ef012": "0x00000000000000000000000000000000000c446f742e616c6572742829002168747470733a2f2f646f742d616c6572742e676974626f6f6b2e696f2f646f74000000000b40646f745f616c657274000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047143b50129d36d8eb2532cd05ac28368e20a8a51527499f368aa8a7d1afa5029b69db39dae229e64673": "0x00000000000000000000000000000000000000000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047143b5508ea0182d21940bace52337625d59fb2154473ff9eabedb24ab44499213ceb4eafd361da3b16": "0x00000000000000000000000000000000000d44616e6b527574616261676100000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047143b591f4633ac60568479c8ea5480acca5a847133cd97a87801b6e698a98f2eab0e8e9d5c51b14a33": "0x040000000002000000000000000000000000000000000744725733524b0000000000000744725733524b000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047143b5bb9c0955b82d2c633e77b0ac47351f93a639be30f4496597e4e85bbc90a2980ceb7529ffb9953": "0x00000000000000000000000000000000000000000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047143b721e900ffa3873ce292ac31cdc1aba6bc5b19b53e3f294c5da9c70aae9d8525a1f441d3626c57d": "0x0000000000000000000000000000000000086d757269637931086d757269637931000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047143b79538f38d1f4776a2b8e4592ea3a046666ebfefa1874cd632161ab49fde244017c8cef9924f322": "0x00000000000000000000000000000000000d5368616e652046616c6c6f6e0d5368616e652046616c6c6f6e0000197368616e6574657866616c6c6f6e40676d61696c2e636f6d0000114063656c7469636c6567656e646e6674000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047143b7dae00d6ad1b52b28d7556ad0d7e6a31273e2c0e81de552104382d675a2445af326525fc81b972": "0x08000000000100902f500900000000000000000000000100000002000000000000000000000000000000000e47524f55502054484552415059000018406167745f7374616b696e673a6d61747269782e6f7267126167745f7374616b696e6740706d2e6d65000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047143b8d9ac488d992b7a4b959e2a5cedaf1e09a5436cc714f79819e5b5b1c67390cffb468ee81ffe479": "0x04000000000200000000000000000000000000000000104e6f7a6f6d692053746174696f6e73000015406e6f7a6f6d6968713a6d61747269782e6f72671373746174696f6e73406e6f7a6f6d692e616900000a406e6f7a6f6d696871000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047143b8fa2e75a1b9c5bcea3dabe52b2a665b1e19bf8c6913a5d54e06d6413ca3ddbec8f9a22415ec477": "0x040000000003000000000000000000000000000000000644617669640c44617669642048617769671f68747470733a2f2f747769747465722e636f6d2f64617669646861776967174064617669643a776562332e666f756e646174696f6e00000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047143bb0e8992b8df2807e0292c2df794e7aa37c54e9be9ae80026647fbf4449917e4aca2037c3b91660": "0x00000000000000000000000000000000000c436f736d6f7347796f7a610000000000000a404b6163756b69726f000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047143bc4805f1dc5a0b3cc5ce9e629b6758532291eaefea2671334d175bed7c29c805a435857b287b212": "0x00000000000000000000000000000000000a506f6c6b61536166650a506f6c6b61536166651768747470733a2f2f706f6c6b61736166652e78797a2f00156973686974613730373740676d61696c2e636f6d00000b40506f6c6b6153616665000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047143bdc67a5cfa44da7f64ff5fb243e83dfb26e2723797c47b9e6b31cac8fc2ef91990d5be45e5cb33a": "0x0000000000000000000000000000000000074b61726c6f730000000000000f404b61726c6f737363727970746f000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047143c0edca73b5ecdd9f091ff4a3f0a8699289c47578c42557932e775cf7f9c7da0c199c730410ee872": "0x00000000000000000000000000000000000e526f78792773204175726f72610000000000000940526f78794e4654000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047143c2cb2eb0335d82a6291b0b86664408338b2fddc2ccc5bc718bc2f197d60ba32e44fd9c942e92501": "0x00000000000000000000000000000000000d417274204f66204d616a6f6e0b4d616a616e20416e69731d68747470733a2f2f6c696e6b74722e65652f6172746f666d616a6f6e00156172746f666d616a6f6e40676d61696c2e636f6d00000d40496d61706f7461746f6f65000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047143c5c102537d492632e44d899f1c95f9c968cd59399a21a4856d1b0d5d9fae07c1aeb7b4c2c61aa68": "0x04000000000200000000000000000000000000000000074f7261636c6500001440616c6d6172696f3a6d61747269782e6f72671c76616c696461746f72706f6c6b61646f7440676d61696c2e636f6d000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047143cb00158aad5ee6baec1abe6e31fe52e443783e67de24e7ee311c1506cbb215881eadc721f142e0f": "0x040000000002000000000000000000000000000000000e4272616e646f6e46696c74682b0000001a637261646c656f6666696c7468637240676d61696c2e636f6d00000e4046696c74684272616e646f6e000d6272616e646f6e66696c746800", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047143cdada2ee46b071630d8e67d1a8b9c95fe14553b3fa63f32c8690fc9ae8fd0196f16489252300b2a": "0x0000000000000000000000000000000000054c45443200000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047143cdcc87649a2d33c3e18ff79478f0555885d9da3b482bbea5930b8b33b47df607855a05848c6073c": "0x00000000000000000000000000000000000848656e676973740000000000000e404d656469756d4d61726b3232000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047143ce6197206f2905cac5e7ba2c1529f9e16e3a920f65a36f2f170522b92e6c37fe26e8a58384a7463": "0x00000000000000000000000000000000001446616e7461737920436c75622053747564696f1446616e7461737920436c75622053747564696f00001c46616e74617379436c756253747564696f40676d61696c2e636f6d0000104046616e74617379436c75624e4654000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047143cf08b9f8a98ed5bf88a4006c41081ce901e0a845e8607bce1c81a69897211b9db6e68a3c148eb1e": "0x00000000000000000000000000000000001c446f72696e672d4261657a2d476f6e7a616c657a2046616d696c790d4e69636f6c6173204261657a00001877306d38356b32374070726f746f6e6d61696c2e636f6d00000a406e69636b5f717376000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047143d1b2413f2986065923a8f80723b86c1305ace998cc4a1b500095196102f5a3889b68a6ba00e690b": "0x00000000000000000000000000000000000d476f6f6e6579205361696e740b4d4461766964204c6f770101146d64617669646c6f7740676d61696c2e636f6d00000b406d64617669646c6f77000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047143d2247c3cff243e448ed2e907e472b4db96ce361f8e1a346c5af739d6705843e1a48ee9f5eadd22a": "0x0000000000000000000000000000000000082e4368616f732e00000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047143d4a43e0b9eb6a1b4a86fd86fbce1384861712946d1aeb1ee810242dcd228026328335634af76f3e": "0x04040000000100902f50090000000000000000000000000000000000000000000000000000000e4175746973746963204170657300000000000011404175746973746963417065734e4654000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047143d54772322b9426d803112054b6f2127db5bf84fae280724596d801671e4de7d1cff4c8d56edd351": "0x000000000000000000000000000000000013e8909de88e89e4bf9de68aa4e58d8fe4bc9a076c696e79696e000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047143d71181b8a809887c0848079910d67af0a8756c87a50adb5c9e5ff410277980ba737025adf71f323": "0x000000000000000000000000000000000009506172616365696e000000176665646961736368696f707540676d61696c2e636f6d000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047143d7b57c9bab601df742f10a2b57e5ec3247c0ae6da2a2fdb4a731324dc7a2edfe0f4fc761e1a4d3f": "0x04000000000200000000000000000000000000000000094d696368656c6c65000016406d696368656c6c65783a6d61747269782e6f726700000000001336303833373436343939373331313330313400", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047143d8d6284f9cd655d3ea8ab4d4cb7d18b6a0d8f2555955abfb182af4808dfe1e4418e3e104c9cd07a": "0x00000000000000000000000000000000000d6c656f2d616e646572736f6e0d4c656f20416e646572736f6e000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047143da0de343db242fb1c384604d84ecd79034f0c19b26752abe03a0db3bf62b5069df96692ff077b18": "0x0000000000000000000000000000000000064c7973796900000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047143dcc236c1c55df5e202ff21bfa05c35d59be949ddac77d03e49ca8b43ad1d169408b247b13332847": "0x00000000000000000000000000000000000f537765657473206f6620524d524b0f537765657473206f6620524d524b00000000000e407377656574736f66524d524b000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047143de3c64163d245c278c7e23425c0433a78c7f295bee57069c78743b4630161530af5e6e5ad5a7024": "0x04010000000200000000000000000000000000000000174265737476616c696461746f72207c205a75726963680e4265737476616c696461746f721a68747470733a2f2f6265737476616c696461746f722e636f6d14406d6f736f6e79693a6d61747269782e6f72671868656c6c6f406265737476616c696461746f722e636f6d000010406d6f736f6e79695f7a6f6c74616e000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047143df5621b372fe9b952370afd8038d4fe339fe8ab84ed26748940a72ea12df5cc63bb5b0e3a6bc830": "0x00000000000000000000000000000000000b446965676f5374616b650e446965676f2050657265797261000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047143e1505ea3181f4d938b56e4773b73ad84537f2a6ceb8623781bc4fde11d5eaf672e88fc19c0f2c28": "0x040000000002000000000000000000000000000000000744656e5055420000134064656e7075623a6d61747269782e6f726715766164696b726976303140676d61696c2e636f6d00001140546c76787947713543427275316b7a000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047143e1fada5350d221c002ebf751ae1def13e95b2260485550d8c3dc41390313ca457a0062560483778": "0x00000000000000000000000000000000000e426c696e6b696e2e6368616f730000001f626c696e6b5f6e446f6573446546694070726f746f6e6d61696c2e636f6d00001140626c696e6b5f6e446f657344654669000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047143e2ea95392d7cb335c23c32caa710e0758a3f1f55ec38b4a90b46631bdc96a2b9838c9a77fc1235e": "0x000000000000000000000000000000000007726f6e63686f10526f6e616b2043686f7661746979611668747470733a2f2f6f726e616c6162732e636f6d2f0013726f6e63686f716140676d61696c2e636f6d00001d68747470733a2f2f747769747465722e636f6d2f726f6e63686f7161000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047143e3e798a3a6296aaf8d542920fa20b0dd5e126de37f7c0142db98b51a6caa4968922467b42b95a74": "0x00000000000000000000000000000000000b4441524b464f5245535400000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047143e512628d0f746aeb4652c8810763fc9c9e36f67c348508c6880d831885799456555a0316184ec2e": "0x000000000000000000000000000000000006536f4b656906536f4b6569000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047143e76497ef9205fafb2f0665e547b1ace9b2b87fdc59a2eb376e4f52a6b5776ac7bc879b8416f3863": "0x0402000000020000000000000000000000000000000011494f53472056616c696461746f72203111494f53472056616c696461746f7220311068747470733a2f2f696f73672e766311406a6f63793a6d61747269782e6f72670e68656c6c6f40696f73672e766300000840494f53475643000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047143e82b21f8446b3af1eded961809a3f356553dc14f1e93b1cb7e6b7c828e340e10415c09cdb41f86e": "0x00000000000000000000000000000000000c4c616479204b7573616d610752616368656c00000000000c406c6164796b7573616d61000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047143ea0a0e4b3cccecf1a7d6f18e9791ea8872d8882642f1ef1a567f67d8f4ebbf0e12a5f3a619fef3e": "0x00000000000000000000000000000000000e4b6f6461446f745f706f617073001468747470733a2f2f6b6f6461646f742e78797a0000000009404b6f6461446f74000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047143ec7ab919f5354868e675e5690eb2ade55d6690e6cbaaca81d24d34c805527c58d648183d74c7614": "0x00000000000000000000000000000000000c4d6f6d656e746f42756c6c0000000000000d404d6f6d656e746f42756c6c000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047143edca9b73dc0a5e4e06db2647e73f26d9b6b9d305ef921ae165215b4b7dc6f08b1ce295db0facd23": "0x00000000000000000000000000000000000953757266657273200630786864690101096d407375712e757300000d406d656864696a6169646933000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047143edfdd48fc779cd5a80ea94af8a39eb7ba8d9afb913147e67eae84f48aad7b9ce6ee05094fe0394e": "0x0400000000020000000000000000000000000000000005416c6b6f00001340616c6b6f38393a6d61747269782e6f726700000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047143f15914969e7b002928d0d0ee5f4d524a2a8bf992de4fafb497112bc3498eccdcfc88866bde42c19": "0x00000000000000000000000000000000000756616c7461720e526f76616c20546172726f7a611c7777772e61727473746174696f6e2e636f6d2f746172726f7a61720013746172726f7a617240676d61696c2e636f6d000009405f76616c746172000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047143f1c259322f2c75fc2d6907fd9c5c0a3bb5b8fa55153a9b8b798464f6ea3a540f0a7849f999ffc7a": "0x040000000002000000000000000000000000000000000b74616e7573686136303200000000000000001174616e757368615f363032233932353600", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047143f238aa31c71d3336ca6452fdccbb00af0b245231dff434535cdc7f9a2f2712dbc740e662e9c596e": "0x00000000000000000000000000000000000f62696e616e63655f6b736d5f34300f62696e616e63655f6b736d5f3430000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047143f4fdb82e13e4374aba289d29b3dd0dc2d56f7ab2c90a6776431a49723058a7050022fd81d237133": "0x0400000000020000000000000000000000000000000019706f6c6b61646f742d7361666172692d6d756c74697369670a53616661726944414f1768747470733a2f2f646f747361666172692e78797a2f0013696e666f40646f747361666172692e78797a00000e4054686553616661726944414f000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047143f67110821e73a29729da928a9148b8da4cdef9bc0f03326dac61d8c5aa0604059bee63df6273e4a": "0x00000000000000000000000000000000000000000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047143f766dca042f5e70f69409a7b5a311894e73baf41c5554009645f8c4180a1993ad690721149d7939": "0x00000000000000000000000000000000000e50726f6f6620206f662041727404496f6e00001466657261726938333940676d61696c2e636f6d00000d4050756e6b324d6f6e6b6579000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047143fc75114c6299d4af21febf4202d805c54fc3a74b6d8f2ab070f330fcbd64bf02e1276111baf3967": "0x00000000000000000000000000000000000f62696e616e63655f6b736d5f34320f62696e616e63655f6b736d5f3432000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047143fd042080b18e9fb0f4c5aaeacd001fcf32b29ad902a5dfc489af0dd8b263ea97117218103921ee5": "0x00000000000000000000000000000000000852455354414b45001468747470733a2f2f72657374616b652e6e657400000000104072657374616b657374616b696e67000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047143ff9e63960b2eb614e74b71c8f5bec8948037d4191173025162d8193d1c6773f7f5bca917ff10c5c": "0x0000000000000000000000000000000000086465766d6f6465086465766d6f6465010101000001000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047143ffe32ddffac26d1225c1cf2356a5a5cd7e13c8e5dbee6c4c89e1c5f610c1050131cc58b4d96e75a": "0x040100000002000000000000000000000000000000000943535f417869616c001b687474703a2f2f63727970746f73617069656e732e636c75622f15406c696c69616c756c3a6d61747269782e6f726714663474617469616e614079616e6465782e7275000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714401eb02c77bc87680c6be896b338d1c81b5e1c1629cc6658754b34a7382efa1daf20c8d979004b39": "0x00000000000000000000000000000000000101010101000001000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471440211a7f8ab7a9a03c757ba7f937e877ce2171c04b729b5fcdf7bb4d9f11c46dfc50212664e5cd08": "0x00000000000000000000000000000000000f5a6869786920496e7465726c61790c5a68697869205a68616e670000127a6869786940696e7465726c61792e696f00000e406e696b6b695f73756e736574000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714402a556db017fb3cf802d69508ee4778ba8e6d8406e28484017a27f50be26df185e2406fcb0b322c": "0x000000000000000000000000000000000007757a6172646100000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471440506c474710c680becff51276f84146717aee4ee4e9626ae7023246f8dc03548ee313351957a33c": "0x00000000000000000000000000000000000a616c6f74616e67686501010101000001000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047144066c167257e03db04b82783d5d3e2c81f48908d03fd43630deefd23fdb2b7f5c21e322fcf7b5613": "0x00000000000000000000000000000000000000000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471440675f145f08184fd03abd3df52537964270150786182ab41f565027d36f488215c86d5c92e1f329": "0x04000000000200000000000000000000000000000000056974736f000000136974736f3939343340676d61696c2e636f6d000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047144076a041f4206619a03297fd2374d7d2f0d1ba272e89e77079b48b402d1dcf36bbec6c7114378136": "0x04010000000200000000000000000000000000000000076a6179736f6e00000021616c77617973636f727265637476616c696461746f7240676d61696c2e636f6d000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714408289d96aa87d1172159b34e3f99ea3bb6d0c08bbff4d1d6ac30603b34811e222049cb39d8ff047": "0x000000000000000000000000000000000013e298952046696e616c4f6d697420f09f8dba0000001466696e616c6f6d697440676d61696c2e636f6d00000b4046696e616c4f6d6974000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471440972e71eac65ab410c369c571d3b7fc6207371154eb81da418c21b4c96c4382131c09fa94165634": "0x00000000000000000000000000000000000b42696e676f20417274730000001762696e676f617274736e667440676d61696c2e636f6d00000e4042696e676f417274734e4654000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714409d3d5d3a1caccf4a2c3d9e33fd1f782dc354599c2f72b160e1d9293ca67e6e907b34061709bb6d": "0x00000000000000000000000000000000000b73616c746272696467650000000000000e405469646568756e7465723138000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471440a080abf9c0d1738465abd5a02f5b42b23e323b73e52416514460b9a3e7c34c94ed8d9f986c3d6e": "0x000000000000000000000000000000000008536b616c6d616e001d68747470733a2f2f6769746875622e636f6d2f6472736b616c6d616e1440736b616c6d616e3a6d61747269782e6f726713736b616c6d616e407269736575702e6e657400001940736b616c6d616e406d6173746f646f6e2e736f6369616c000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471440a89f3abda82c85983347500922c79e9afb60da250d4dbdff3d8546f1b32f0239a5e8df8b02ea1a": "0x00000000000000000000000000000000000e42494e414e43455f4b534d5f380e42494e414e43455f4b534d5f38000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471440d539e41516f26e565c9f20217f385dabb5e252dfcca7cbfcc0b4a260b331e82d39309b42c8e303": "0x0000000000000000000000000000000000074e697068616c0f416e647265772042656573746f6e2168747470733a2f2f676c697463682e616e6472657762656573746f6e2e636f6d0018616e6472657762656573746f6e40676d61696c2e636f6d00000f406e697068616c5f676c69746368000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471440d54556e8cd2d8b532092745cdf4f2b44e2e540322cd0c7a8a692b6fa5d177ddf17aeee823fb416": "0x04010000000200000000000000000000000000000000144b41424f43484120434f4c4c454354494f4e53144b41424f43484120434f4c4c454354494f4e531868747470733a2f2f6b61626f6368612e67616c6c65727901146e6674406b61626f6368612e67616c6c65727900000c406b7568626f7763687568000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471440ef7feca334f14c4a0eb541fc52db126c97ffd8cd041322b68e9c00b6d46b09d2c852c6f737e45a": "0x0000000000000000000000000000000000084772696e694d65084772696e694d65000015766772696e696d65657240676d61696c2e636f6d00000a406772696e695f6d65000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714411a5418773a1a2568f8bfef657c69a5c34721cbaa618ae9eb2108566f9a2606cf5055578e0c2511": "0x040100000002000000000000000000000000000000000f436f6d707574652043727970746f001a68747470733a2f2f636f6d7075746563727970746f2e636f6d0018636f6d7075746563727970746f40676d61696c2e636f6d000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714412792138d96bb58c2b264a56b5eaa7e1f4cf6db61445113e7df7cbfbaf77d7b23887088f629e657": "0x00000000000000000000000000000000000000000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047144140e165d0c0e9dab86111b2d7969eb7c651d4b1772388ca5e595860e6e82bccb903b46fba28c713": "0x00000000000000000000000000000000000c5768616c6520517565656e00000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714415252cc5998dac14e516d9d6527c3bdcc45105195b8e23480bc0f257308b1f4fef03e06efbb1c5b": "0x04000000000200000000000000000000000000000000055245504500001140726570653a6d61747269782e6f726700000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471441681d40d088fef712df12dcbb5083fb5ae84c019e2b22922dd4e87647b0c5569955f40195cbb512": "0x0000000000000000000000000000000000095472656173757279104b7573616d612041706520436c75621b68747470733a2f2f7777772e6b7573616d612d6170652e636f6d001a6170652e636c75622e6b7573616d6140676d61696c2e636f6d00000b404b7573616d61417065000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047144177d8c48739d4b1602ae92f82bf4f711ac8534b73bc0959cf87cb691c42eb14bffd93d15da51f53": "0x0000000000000000000000000000000000145374616b655365656b65722062792042544353194254435320496e632e20284e61736461713a2042544353291b68747470733a2f2f7777772e7374616b657365656b65722e696f0018737570706f7274407374616b657365656b65722e636f6d00000c404e617364617142544353000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047144184ba79c24cf9898ce7f9b6eb21ee076f759396cbac56c8417e38f5a5e93f354da84d6bf20bde62": "0x0000000000000000000000000000000000117374726f6d626f6c692d7061796f757400000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471441b31d51b902bf81b44481905d25563efe49d16584345474c8b6127729b934e7b740a9f264d63457": "0x00000000000000000000000000000000000642696a616e00000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471441ca7551fdd5198464bef580d4d5350d51b7aed6eedd24a2f14e9de9a4c438bb91f9d2b57ddc9026": "0x00000000000000000000000000000000000a73616b616d6963686900000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471441e29c1629f394e1e4a77c09a5e7cca4340cd6ce8dd3cf6dfffacadaab7bd6581b7ca50959834271": "0x040100000001006c57c10b0100000000000000000000000000000000000000000000000000000d4b657920506963747572657300147777772e6b657970696374757265732e6f72670015696e666f406b657970696374757265732e6f726700000d404b65795069637475726573000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047144200a83649f12b6d9218a3abca6aaa7cda30f2493e57e5261b060f5f392f2d4cdd9aab3713e33d3c": "0x00000000000000000000000000000000000e4669676d656e7420416c706861001368747470733a2f2f6669676d656e742e696f0000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047144207de929e0c2c7c20f322a0ce33a28f8e0d44accc268eaa77b9f80f421d8e0e1a96e10718dee164": "0x00000000000000000000000000000000000d46726f6e74696572736d616e01010101000001000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047144229207fadf4b0c2366c1d734b33c714b0e0e9f164426e66e3bfa97b917b23e5d3674f4a2074f86f": "0x04000000000200000000000000000000000000000000094d6f6f6e6e6f64650000001174656368406d6f6f6e6e6f64652e696f000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714424771d484adc6a72a6f412b15ba9a05e58871913e1db1c5e2ffaa7bc58e5211721e98a03045284a": "0x00000000000000000000000000000000000b4d616e6e696d4d6f6e640d4d616e4f6e5468654d6f6f6e00000000000d406d616e6e696d5f6d6f6e64000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714425d6aa15789f0c1507bf2acec7efcbdcf09e8ec2187bb87b07ee88825d4b840af4159a30012cf4b": "0x0000000000000000000000000000000000010101010100000a406361626c696e6531000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471442661dc55caceeca42a60e286bf3ab5228cc24f47e4087436285f889a306a4542f3e97c50834ee51": "0x00000000000000000000000000000000000451766f00000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471442846f3701313edf5e14105dd8e15633168123d30f93edbbcc5cccc3518791e53cdb9c541cbcd343": "0x00000000000000000000000000000000000e62696e616e63655f6b736d5f350e62696e616e63655f6b736d5f35000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714428cc1cacf21d843cc386a98ed8462dcd6df033f115fe1527867c49a2a898280691dc57ab5e63974": "0x00000000000000000000000000000000000d4672616e6b7920467265736800000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471442946832d384cb2c5e1eb942e5f591bc1d902fc6a04dd7ecadf5f4916f2597df0505c6c521412c4b": "0x04000000000200000000000000000000000000000000084649474d454e5400000013636f6e74616374406669676d656e742e696f00000c404669676d656e745f696f000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714429bcc7f376222a2d1bc4259aeb77874ee7ca72a9763d6385763068b56bf47fcabd0d854311ab7c1": "0x00000000000000000000000000000000000e524d524b204d756c7469736967001168747470733a2f2f726d726b2e617070000f68656c6c6f40726d726b2e61707000000940726d726b617070000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714429c4677f860fc0c88f9c19843d4503698a3cbdb00a6bcf115fd11c36d646f280da7822733a81f03": "0x0000000000000000000000000000000000084a52637265616d034a5200000000000a406a75616e69727566000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471442a5466c1294dfdc0a7deeafeecde52fd2ef2749958d1b0e5094c629a355ab52c984116556e5f515": "0x00000000000000000000000000000000000f73696e67756c617274732e6f726706456e67696e1768747470733a2f2f73696e67756c617274732e6f72670111656573756c6140676d61696c2e636f6d00000840656573756c61000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471442ade399737c4384882a9309f1e5f87abb745dc51d5dcc338e3dbe7b818fd8a9768e27d97e57ec13": "0x04000000000200000000000000000000000000000000084469616d6f6e640000001776616c69646469616d6f6e644070726f746f6e2e6d65000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471442b0e5e788b77418280221db3cd2515ba48cff6c400cf4624b9459eca62f30523972ee5b608e967b": "0x0800000000020100000002000000000000000000000000000000001c45535152204361706974616c204e65746865726c616e64732030311945535152204361706974616c204e65746865726c616e64731c68747470733a2f2f7777772e657371722d6361706974616c2e6e6c1940657371725f6361706974616c3a6d61747269782e6f726719706f6c6b61646f7440657371722d6361706974616c2e6e6c00000d40457371724361706974616c000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471442bd7fccd27172c3c0b457c25ea2f71dc18c12a6dfef5c32a1d663269787f2fe0b49b9ec041eba64": "0x040100000002000000000000000000000000000000000e566f75726865794b7573616d61001c68747470733a2f2f726f626f6e6f6d6963732e6e6574776f726b2f1b40766164696d2e6d616e61656e6b6f3a6d61747269782e6f726716766d40726f626f6e6f6d6963732e6e6574776f726b000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471442c610f7e050710e06b2570a6c00c6e0c418a2fef16ca9c55e7316c995265e99b1e5f15117ee3e3d": "0x00000000000000000000000000000000001553746174656d696e6520646576656c6f706572730f53746174656d696e65207465616d00001c626c6f636b636861696e627562626c653740676d61696c2e636f6d00000c406b6f7265616e5f67656e000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471442d6dbf1184a5e27d45579ae86a4bb29d2440e48a9eed4790411a6a8e8d09413c827504c2088660c": "0x000000000000000000000000000000000007566f6f446f6f00000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471442eafc0ff257cf6b6a27e5f57753658d45a60fe2d7f5a2b9bc2e0202ed891a8fc80ad7c27882f448": "0x00000000000000000000000000000000000c4e465420496e766164657200000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471442f7186af73e2c106edfd181c979c11a1d853c8fdef7b18e85ec39bb67ce723130b25fc24232c358": "0x04040000000200000000000000000000000000000000094769734c656d6f6e000000186769736c656d6f6e4070726f746f6e6d61696c2e636f6d00000a406769736c656d6f6e000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471442f901039d3431b5a0111975da4d8d0ae457ced7a3628c368ad8a7d089ebbed2a2f2561b0c144236": "0x00000000000000000000000000000000000d496d616464696e416d73696608496d616464696e01010100000e40696d616464696e416d736966000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471443031ba174ef004f7e21ab0dcd65abbbf6f37cfde306ea29c7416a984ec5664cd553befbe3cf114b": "0x0000000000000000000000000000000000054d4a465301010101000001000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047144313f37cc5b7356c545b79d13047971ae5df6134fd0e034f99db6b174cf1046764861569f943514f": "0x0400000000020000000000000000000000000000000009726f636b6e6f646500001540726f636b6e6f64653a6d61747269782e6f726715726f636b6e6f6465687140676d61696c2e636f6d000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047144315c981ebc9c224e49a94c01d7c0511480422e00ef7030ff64f314591b50d7057deadbd6411112e": "0x04000000000200000000000000000000000000000000074655545552450000124031667574753a6d61747269782e6f726700000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714431c4c64db68d8bc2211d6fce26d7140904357fce2aca5d1e63b362f1789bb6d7dbd848d3df79c65": "0x0000000000000000000000000000000000084d6172636f526f0d4d6172636f20526f6d616e6f137777772e73747564696f2d6967732e636f6d00196d6172636f726f6d616e6f77656240676d61696c2e636f6d000009404d61726330526f000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714431fc37d4e65266372f0e8e7a0016e48feebb38705376825b84f27f82c8c108eb4301755293a5274": "0x040000000002000000000000000000000000000000001af09f90a420424952422e544543484e4f4c4f475920f09f90a400000013686940626972622e746563686e6f6c6f6779000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471443219b832eb0cea63abe5f0e44b84bebe5b30889223938b97e535b6092c30915e40890f16edd51e1": "0x0400000000020000000000000000000000000000000016f09f9ba1204457454c4c4952204b534d20f09f9ba1001468747470733a2f2f6477656c6c69722e636f6d14406477656c6c69723a6d61747269782e6f726711696e666f406477656c6c69722e636f6d000011404477656c6c69724f6666696369616c000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047144322706aab5751605e9a8499b030780091dae032059aa6e38cc55ef49a68644a1cb272891b676760": "0x00000000000000000000000000000000000f42696e616e63655f6b736d5f32310f42696e616e63655f6b736d5f3231000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047144336ca0e09f590ffb45bcaffa67198b19865dce57baff03eff340df85c52e256631ec9c4b96ad275": "0x00000000000000000000000000000000000000000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714433a39cb0e6f7bc112319b29cc9112a1be246421e75de0339021bfe1ed7b06541d969acc17a6de40": "0x000000000000000000000000000000000007736174656b7800000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714433b1db524879af62af538e357eed0b3fe92c64dda50c356a3359a8c38940765e48c8a830279bc2e": "0x0000000000000000000000000000000000054b61727000000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471443496d81af6ed7735855f6f9634a68990a917f22cda160e53f14a0bab251926d946650b4df53412f": "0x0000000000000000000000000000000000217370617a636f696e5f4368616f7344414f5f496e74724b696e745661756c7473000000137370617a636f696e40676d61696c2e636f6d000008407370617a7674000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047144352c02456f8db9cda79564e50582d71b58582eee69b5eb4b01441d3e40edc2cd2eeaeef3f6d2963": "0x000000000000000000000000000000000007636872697a790000000000001040686579697473636872697a7a6c65000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714439dcb29ce5bd09bf622b449b4731ab216a7b8c8845323a004906934f028e2f16c5277b96e86c77f": "0x0000000000000000000000000000000000094d7255706f6e6c7900000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471443a5a3e7bfd489c4deb05fb7623d20882b463209bd7e6a20a1ed0ec1929764ec119a616abe71e642": "0x00000000000000000000000000000000000b4b656c6c204e6f72616c00000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471443bb1018fc2bff6592536c5469fd64b2adaee0a10c5936bb0d4c8e4c5e4d31185fbc0c9136e1f205": "0x00000000000000000000000000000000000b4441524b464f5245535400000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471443bb2518f5dd346208bfa1909b08831184ddb72b2bcd671adc761e4cfecc24b725be3f5a24cfe94d": "0x00000000000000000000000000000000000d4d722e2043616e64796d616e001b7777772e696e7374616772616d2e636f6d2f6368696c6c2e6d65000000000e406d725f5f63616e64796d616e000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471443c19ff4a42bbd9874372fc06884fd5e1cee0831c88891f0e2941ee0017d3125724105d1b6b4f776": "0x0000000000000000000000000000000000074b7573616d6100000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471443c2329d3180137656c0b55c865aec0af22f6d39e01e0d943f3350933058f3b56807c89476e5125d": "0x00000000000000000000000000000000000864696c6c6f6e780101010100000a40584d696e676b6169000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471443d5af598339f8ef98796948d017243ad1b85af8cfc8bac2ef20e3b7e867bb096c5cb847e3562078": "0x0000000000000000000000000000000000074b75246b757301010101000001000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471443dd79f4e889aacc3c3ac3653a4bf9a728758393bbc9bdc5ca31e29aed46a1585fd3d4910257c821": "0x000000000000000000000000000000000007746f6d616b6100000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471443e9f94129b67458622984b619c81ee9a2a84c6ee36fa79b67b535ef31d7ee0b668d704b00c32f69": "0x0401000000020000000000000000000000000000000013526f626f6e6f6d6963732e6e6574776f726b001b68747470733a2f2f726f626f6e6f6d6963732e6e6574776f726b1723726f626f6e6f6d6963733a6d61747269782e6f72671961646d696e40726f626f6e6f6d6963732e6e6574776f726b00001140414952415f526f626f6e6f6d696373000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471443f90c79a74ca36eecafd4305f2a5592eb1f819e05e7ed312282c5d86f284ed0dc5043e8715df14f": "0x0000000000000000000000000000000000084b7573616d613200000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714441abecd8f673549225952e5bb10c80a33d25cdd180dfe6dddc0cd934560c8f6dbeb52edbccb054a": "0x04050000000200000000000000000000000000000000047377620d53657268616e20426168617200124073657268616e3a7061726974792e696f1173657268616e407061726974792e696f00000e4073657268616e776261686172000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714441fb0b93c3c68999c036f0e22d9e0a68b1dc5018d743fb85f400f2e5e213561d03b4c966b131a64": "0x00000000000000000000000000000000000b4b7573616d61205a6f6f001e68747470733a2f2f747769747465722e636f6d2f4b7573616d615a6f6f001a6d616c696b62726f7468657273647240676d61696c2e636f6d00000b404b7573616d615a6f6f000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714442352000e64552148dd734e16f0815537f6bb9a491f1d76ecc83f46c6efe47243f6ac87ae88730c": "0x000000000000000000000000000000000008554d46204b7573000000116e6577756d6640676d61696c2e636f6d00000c40726f6f6d317a65726f31000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714443156d8215300f5028613450f87010f24fa491fc01aee1a9a00649bc3656cc95623caabfd99df6c": "0x0401000000020000000000000000000000000000000007316b4e6f6465001368747470733a2f2f316b6e6f64652e696f2f1740766c6164316b6e6f64653a6d61747269782e6f72671277656c636f6d6540316b6e6f64652e696f00000840316b6e6f6465000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714443ad277a8dbe9aba845ea35913a0fbdec49687ebc5b1579bb632c080ce61b02919ba40bcf889276": "0x040100000002000000000000000000000000000000001056616c696461747269756d204b534d0c56616c696461747269756d00001656616c696461747269756d40676d61696c2e636f6d000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471444509eb7f7220ceaeebbde3ff2bb37ca11414154e92c0521ac8051ea48d0d84b39714b2347763648": "0x04000000000200000000000000000000000000000000094d4554415350414e00000013646572656b406d6574617370616e2e636f6d00000d406d6574617370616e5f696f000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471444555228869870c2e666c8204234e3e9dc671cc875c4f22316e6a7b67bb8b0538d8d77674468ed50": "0x04000000000200000000000000000000000000000000054178696100000019617869612e76616c696461746f7240676d61696c2e636f6d000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047144456b32654fe47f91a8ab26aba64d6176b6aa462a2a7ef6252ca1063cf978dcb6f6c64fec81e7861": "0x04010000000200000000000000000000000000000000074534592e696f001368747470733a2f2f7777772e6534792e696f13406534792e696f3a6d61747269782e6f72670f737570706f7274406534792e696f00000740496f453479000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047144458ae5cd71591333641233f6aa39d0515608c15dc001611a7c5fdf5f5f76fe72d8f8348b0596f09": "0x00000000000000000000000000000000000c5669636b79447265616d7300000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714445f24d9b88c5e2770086e7c9eb19ebdb3e7c492dce59dd3f895c2253e7a838d6dd746503bbdbe44": "0x0000000000000000000000000000000000074a617a7a75730d416e6472c3a920446962c3a9127777772e6b616d65616c6162732e636f6d000000000c40616e6472655f64696265000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471444687e96c8cb00dea2fca1a6c0cf0568cd25a13786689400f1a7dbc63ce2b16a5568b1e88576a307": "0x00000000000000000000000000000000000000000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714446c9be06dc89e3a8c57b6eb2ab6d89e5822919b8d492d510e847f4d60c8380d0265ef7804774a03": "0x00000000000000000000000000000000000000000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714446ced0dc56cc8bf082dfbe87772fa0f7d714b22e0f43cf978a8b588035950aac6f9d14561ddd831": "0x000000000000000000000000000000000017426c7565517565656e20f09f9191f09f9299f09fa68b0020687474703a2f2f6c696e6b74722e65652f42617374617264467269656e6473000000000d403078626c7565717565656e000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714446ecde49f31e64a2a3fa40b4085d8adf7dddf3e3073d45d43cc9e55de72822990fa2d84b18faf20": "0x00000000000000000000000000000000000479616f00000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471444781ab96a799989aea86d60aba408d8d30ec708eb6e322d9c9eac484e957053efab66f1ee4e0f58": "0x04000000000200000000000000000000000000000000094252415f31362d4400000016637074636f7272656f6f6640676d61696c2e636f6d000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714447de9973eed816a0c4e7bbcd18257cff6e835218d6e035cfe29dfdda404abd34f0107379cc9b239": "0x00000000000000000000000000000000000b4d6567616e20536b796500001b40746865746f6b656e626c6f6e64653a6d61747269782e6f7267176d6567616e736b796570686f656e697840706d2e6d6500001140746865746f6b656e626c6f6e64655f000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714447e1613a9d973af08d48a00b01356b80f40e50f281c2cda9e858f45a1bc8e989b3eedfb27dfe044": "0x0000000000000000000000000000000000094252415f31362d4400000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714448ea7872d496c7fe40898073d5ab4bfb056778a95be2d797fb929315d0a0e31ca415e9f37a1d726": "0x040000000002000000000000000000000000000000001447494c204655545552c38d56454c20f09fa496000000167a65726f406379626f72672e636f6d6d756e697479000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047144499fd1a049d4b87923e75ccccb33e471161db9558583ef4668de361bdf471e674256e8fe0748706": "0x0403000000010010a5d4e80000000000000000000000000000000000000000000000000000000c4f50454e474f5642524f53000000166f70656e676f7662726f7340676d61696c2e636f6d00000d404f70656e476f7642726f73000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471444a4a90b1106c3b5aed98e15e3ed392e38654215c3d1fa8143de53460386b60139fbb45c036c1b43": "0x040000000002000000000000000000000000000000000ff09f90a0207374616b6566697368000013406d34646269373a6d61747269782e6f72670e6869407374616b652e6669736800000b407374616b6566697368000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471444edfa80574ab9caa493de655d6a57c136e22828f46b8532e2d31cc6f2e7a5c7ba2a20e689f7540c": "0x00000000000000000000000000000000000b547269706c45696768740e44656e697320506973617265761e68747470733a2f2f6769746875622e636f6d2f747269706c65696768741a4064656e69735f703a6d61747269782e7061726974792e696f1864656e69732e70697361726576407061726974792e696f00000b4044656e69735f507374000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471444f07034c5b0cf0e041e9a27a03cc500b1953d21da30a299cd37b16dff34adc74960e58d747b6524": "0x0000000000000000000000000000000000085369737365726f0e4d696c6f204269636b666f72640000186d696c6f2e6269636b666f726440676d61696c2e636f6d00000a406379626572706171000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471444f53fc133ec6c80a0d32bc7ae5d421990bdb847fc38cade9b388ce8138ab4e4ae957fc7ca59bd2c": "0x0400000000020000000000000000000000000000000006506c7573560000000f706c75737640706c7573762e696f000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047144509291906f0088c76fea4c5f219d65cffa5fe38856023a2faca6f77682c6d6787ceeec403e6c461": "0x00000000000000000000000000000000000653746565621d42792e205374657068656e206f662046616d696c792050727963652000000000000d407374657665707279636533000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714450c8a71697e6a933a4100ce6c8cbffb10c34bbc2792d3c4e05e611f907038cb0b29af8a6ae0292c": "0x0000000000000000000000000000000000114b7573616d61487562204d696e74657200000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714453c05212d64d20f682eeef106c00e84e6c4ae91fbedae25dadb1a9acb8ffed3e0e90494c789d364": "0x00000000000000000000000000000000000e536b79627265616368204f5354001668747470733a2f2f736b796272656163682e617070000000000e40536b796272656163684e4654000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714453efa586e0ab504d20f2ce6c2c876745bbb399c6290cf4e3ee75ce31bbc7ec11342fd5118b98e3c": "0x04000000000200000000000000000000000000000000105374616b65f09fa7b24d61676e6574001c68747470733a2f2f7777772e7374616b656d61676e65742e636f6d18407374616b656d61676e65743a6d61747269782e6f726715696e666f407374616b656d61676e65742e636f6d00000d407374616b656d61676e6574000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714454451249bb2a28c9e7db7bbc0e608c8947bcb697f3a57cfe4586184d757267011ce0ed08fa14976": "0x0000000000000000000000000000000000074e4674657874000000156e66742e6e667465787440676d61696c2e636f6d00000a404e5f465f74657874000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471445599a5d9a55b787b6448af583e707f5da901694a4d98471a3be7d6ed6fd76711bd28278987bae25": "0x00000000000000000000000000000000000a426c6f636b20446f6700000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714457458e4dcb0efd044ecac8b217db711304ba182b23eea8795d7d3163a0d4552bc2c0bd46d38b213": "0x00000000000000000000000000000000000b5374726f7744654154680b5374726f77446541546801010100000d405374726f77446541546831000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714458263f3dd29a31aca42f0b5c7957571706f29d2828291b148b4b162100ddcac72c507fd8ab69b2e": "0x04000000000200000000000000000000000000000000084a6f6579e29ca8000000116f647364727140676d61696c2e636f6d000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714458370997cd94a3038eb1437e296afe15e68d2f76e911a3eaee426d061821343101c542b4e375253": "0x00000000000000000000000000000000000e447265616d204e6574776f726b0e44696d69747269204f6c6f636b00001b746865776f6e646572796561727340686f746d61696c2e636f6d00000f4044696d697472695f4f6c6f636b000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047144586d84f22c954a18d34b38fc5c98e7e3ca205b60de22964fb8a6b81f9573ecd9f36fe5d50923927": "0x00000000000000000000000000000000000d504f4c4b414c4942524152590d504f4c4b414c49425241525900001a706f6c6b61646f746c69627261727940676d61696c2e636f6d00000e40706f6c6b614c696272617279000d706f6c6b616c69627261727900", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047144586d8be9824d3b1ae54b764b5092a89e9a47240f68fc77b20831a47d17cb26216f51b09a6ebf238": "0x000000000000000000000000000000000003425a00000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714459cc19119e455ad94b3d04ef219a8970ac5f76658fdee1005b4b7ffee3fc02355f60db1a778f826": "0x040000000002000000000000000000000000000000000b46494e5354414b494e4700001a4068616e6e736b6f72686f6e656e3a6d61747269782e6f72671868616e6e736b6f72686f6e656e40676d61696c2e636f6d000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471445a19fd11dfab9141672dd5646976a1e7970e4294e7c76108ceaecae9d451cd9114aa05e60d7ed15": "0x040000000002000000000000000000000000000000000c6c65736e696b5f75747361000018406c65736e696b5f757473613a6d61747269782e6f7267176c65736e696b3133757473614079616e6465782e727500000e406c65736e696b313375747361000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471445ad914bf08ca65600401fa089dca21daddd06b7a240939cab69a9b322b1b5d97106814d915a941a": "0x00000000000000000000000000000000000565746e6100000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471445b717dfcdb4e9d874b415e0035e3edc9f18063fc7e060ed66b35f6fff4b657ed0110fa3c0972b1f": "0x00000000000000000000000000000000000e62696e616e63655f6b736d5f340e62696e616e63655f6b736d5f34000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471445be453e8a7bff0f1c7376c9f2afef25e542556d2af805dfa691a414efb9e0fc9a8e33f625294f67": "0x040000000002000000000000000000000000000000000a43617270656469656d000012406a6469656d3a6d61747269782e6f7267146a7361766f406d61696c66656e63652e636f6d000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471445d43cb8401e3564f40cd7a2181289e32776625b9f3a193f749e33ce1bdeb76cfaabece606c7324c": "0x040000000002000000000000000000000000000000001768656c697873747265657420666f756e646174696f6e00001b4068656c69787374726565742e696f3a6d61747269782e6f726711744068656c69787374726565742e696f000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471445d464460dcc7a6cee757e08a886f0c05726f01a5896cca539d55f5f479aefb99065f7fb522f9857": "0x04000000000100902f500900000000000000000000000000000000000000000000000000000014506f6c6b61646f742042656c2033617261627918506f6c6b61646f7420d8a8d8a7d984d8b9d8b1d8a8d98a1d68747470733a2f2f796f7574752e62652f4f7962346e753144324663001c506f6c6b61646f7442656c33617261627940736b6966662e636f6d00000e40446f7442656c336172616279000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471445d6cf8cdd42d9567e551c089af6a7a53e7644e2e1f0cae900ee599c7b093d8d84e0b260baef1e2f": "0x000000000000000000000000000000000003726f07526f6265727400000f726f40737570657264616f2e636f00000a40726e646d6b696e67000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471445ec95bcb8dd897248d5f568124b09fefe504a22bbce2ccee0fcae9262c639b6b2ebaf95b5c8fe77": "0x00000000000000000000000000000000000f5368616e6b617220576172616e6700001a407368616e6b6172776172616e673a6d61747269782e6f72670000000f40576172616e675368616e6b6172000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047144606c1e64c9b04ef089f89ddbc0f4ed98a10fb57963bbbb03c451dd3aa47ac578a0866ff36400274": "0x00000000000000000000000000000000001c5761674d6564696120426f756e7479203132204d756c7469736967001a687474703a2f2f646973636f72642e67672f595558716a5658001743687261776e6e61436f727040676d61696c2e636f6d00000e40746861744d65646961576167000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714460eeee95ee3957682947d9ddfb4825c6c07ea8c0259249142a42ae15548f32eed2f26dc995f8c44": "0x00000000000000000000000000000000000970696b612e61706501010101000001000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047144631dfe0f44bc9a172d92509f6cf730bcf490da19f09c2271c053d750155b314ec96a7b929ae0c1c": "0x00000000000000000000000000000000000943616c76696e20570000000000000c4043616c57616e675f4359000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471446374d36cdcac1f68e28e91f200ae0e50fec4354a429a7e4e00f684f594a33437dff6e8c4ed18053": "0x080100000002040000000100902f50090000000000000000000000000000000000000000000000000000000b63696563686f6d2e6575001368747470733a2f2f63696563686f6d2e6575001c62617274656b2e63696563686f6d736b6940676d61696c2e636f6d000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047144642619111762c48be1c7627fbc96a38d3a3cf746ae545f60e2510ed80961537d9b4924421fbb562": "0x00000000000000000000000000000000000b4441524b464f5245535400000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047144642e4cbf75408a4e0b67671edec61aa1d5fbcf798d4a25beda1a5dd1e3526317509d2c2fd200127": "0x0000000000000000000000000000000000084b55574f524c44000000116b7577726c6440676d61696c2e636f6d000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714465ad8a5d19f9267c884cfb4aaa082d634dd1490b083e2484eb1ae869dc283bdd232e79076050f23": "0x00000000000000000000000000000000000000000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714466fd64f62aa7900e0c3d50d8748046da1a6d4b266aa6272596357d2fd8505297750874fef54bb62": "0x00000000000000000000000000000000001044656570204d75736963204e465473001b6170702e737562736f6369616c2e6e6574776f726b2f36333332000000000f40646565706d757369634e465473000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714469fd489f05874310eb3bf62c9a8af621503ff143b18cb35afbfdf56b274e6c6de571e7a12732200": "0x00000000000000000000000000000000000b426974537461636b2d30001568747470733a2f2f626974737461636b2e636f6d0010626440626974737461636b2e636f6d000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471446b931982fa83f40c009ab06d6b49cd62f2801c4b0029a5343c51747f6716c788780bfeb2730af66": "0x040000000002000000000000000000000000000000000e436861696e20736572766963650000000000001140636861696e736572766963656c6c63000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471446b9cd597eba686fe4a48b16cd6a6c6c44e4c9542e923726dc861077b6a4ff3df1969b13a6868b2f": "0x04000000000100902f50090000000000000000000000000000000000000000000000000000000d5061756c6b61646f74746572000013407061756c6b613a6d61747269782e6f7267177061756c6b61646f747465724070726f746f6e2e6d6500000e407061756c6b61646f74746572000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471446c4669abf816fba10d77f8b691c95b2e7307a11e1ef18b68c26e000c3989a780bacc7349437bb50": "0x00000000000000000000000000000000000a616e657474204b534d0f416e65747420526f6c696b6f766100001a616e657474652e726f6c696b6f766140676d61696c2e636f6d00000f40416e657474526f6c696b6f7661000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471446cfb02d325485373adee633eaf6ebc53ac8f7aec7bef21463801b4034e0e83a49aaa5f143554a1b": "0x00000000000000000000000000000000001054696d4b207c20414a554e412e494f0c54696d204b72616d61727a00000d74696d40616a756e612e696f000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471446ed2c28a4803e5468f660000960b688950a3e61f27955ce98545c0039dce11d99e53d03dc4ceb76": "0x00000000000000000000000000000000000000000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471446f06f7d193327806c7bcff1709777857526bb52cb6216759a67ea7e56d1d3571c828902b5bff774": "0x00000000000000000000000000000000000945676f72205368610000000000000d40436f726e666c616b656e73000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471446f13c2d0cde69066a89d6035d62de486ffa7832f579971d6ad69ae8cf9e1e8b284b075c06be7d38": "0x00000000000000000000000000000000000e5572616e7573204f7973746572011f68747470733a2f2f7572616e75736f79737465722e63617272642e636f2f010100000e404f79737465725572616e7573000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471446fa647d7b60b7824ef63a0f97791221290fd19207cbb23ec5783221b5016afa55161b01dbb0125d": "0x00000000000000000000000000000000000b4441524b464f5245535400000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471446fb667c004eee811ae687e64fca4530b4fd2d2c1f55592a05e4957804177fab940dbeb5cbd00855": "0x0000000000000000000000000000000000094272616e64736f6e0e4272616e64736f6e20556d61720000176272616e64736f6e756d617240676d61696c2e636f6d00000c406272616e646930303230000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471447108ba2f686e08a84385f4dc4e864120c2648aafc704e395043dc4035e464a9b2a949b4bf0bd51f": "0x00000000000000000000000000000000000b726f6d616e6d65706c730e526f6d616e2042656c696165762068747470733a2f2f6472696262626c652e636f6d2f726f6d616e6d65706c730015726f6d616e6d65706c7340676d61696c2e636f6d00000f40526f6d616e42656c6961657645000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471447298269749af4b4ae59eb4208247833e23d7fb08f26370152accd40170824923bcaab638039a104": "0x0400000000020000000000000000000000000000000012474f4245524e414e5a41204b5553414d410000001f676f6265726e616e7a61626c6f636b636861696e40676d61696c2e636f6d000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047144730d851b833f1c06eaf819ef043560115f737f51d3b07afa79fe8780373bd00070a2eae94015646": "0x0000000000000000000000000000000000046c6b6a0667686a6b6c0000186775616967756169306775616940676d61696c2e636f6d00000840477561693047000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714473db53267f4b4815c4a22915a8bf1866be4812ab49589348457618cebe48440fd7caa86b9b59e2e": "0x000000000000000000000000000000000012566f696365204d7920416d626974696f6e0000000000001140566f6963654d79416d626974696f6e000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047144746bdebb15ec7155ee8c2936d7a2680fcce49b83f26983593b56a7d7ed33a261bcfdabdda639e2c": "0x00000000000000000000000000000000000e4d617465726961205072696d610e4d617465726961205072696d61187777772e6d6174657269617072696d616e66742e636f6d001c636f6e74616374406d6174657269617072696d616e66742e636f6d000011404d6174657269615072696d614e4654000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471447584c2d31e2e9c26ecda2dbfae5750cd7a01702757efade022460d7c30fce208e0e2f850c2aa93f": "0x00000000000000000000000000000000000d43727970746f5f4c6967687400000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714475aa077ca585da3a65d8a5050f324ebffc0acbe4405923615e0d76c0c6665050b888337833de927": "0x000000000000000000000000000000000015416b726f6d6d756e6974792054726561737572790000000000000940416b726f5f4456000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714476c17eecfb55ebeba2a4bd4f5273adae499968adab8b397e60270db6dd18a85d69180b385a57a3a": "0x0400000000020000000000000000000000000000000006696c6f6e6100001440696c6f6e6131313a6d61747269782e6f726700000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714476f6754a2671256884bfab0d164daf8d9820db39bb87b170e21e75abadeae41fa148e853254d17b": "0x00000000000000000000000000000000000a4d616e6672656461730000000000000d406d616e6672656461736d69000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471447785781ee7fbf17b8bfec3d3aba4cacf54940cc35e865b8ab6d8a856894f6401c4a653031a92e42": "0x00000000000000000000000000000000000f42696e616e63655f6b736d5f33350f62696e616e63655f6b736d5f3335000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047144788a63a68d46b3e90eeff9c04b03b3893aa1b545ce5e271bec4de02dee3ac259867733d65e4636e": "0x00000000000000000000000000000000000000000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471447a11575d19da5016c32ae0601494f734050511609799c3e1e9c5be224bac231a5e083aefa3a5d61": "0x00000000000000000000000000000000000754495a49524901010101000001000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471447a1a560bf1b7d81546b0e2808b74dd556d18a6438df5b5b3afd038785afb34e8e1457a1dd1e9009": "0x0000000000000000000000000000000000074272616e6368126f6620746865204461726b205369646520000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471447a838aa9114c0a2d29656902ad531e8326517cef640e70eb793c712b6329633dee3da0599c88e79": "0x00000000000000000000000000000000001446757475726520566973696f6e204669727374074a6172726f640000127261656a70756b40676d61696c2e636f6d00000f404a6172726f64436172656c7365000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471447b2d7bf40bf9bbc24beb92b2450897df40f8df93e348c583d972d1b6d4f661a49961acc2b88101c": "0x00000000000000000000000000000000000f42494e414e43455f4b534d5f31390f42494e414e43455f4b534d5f3139000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471447bedb9f0d77b46d6883b9f834076b9c1368e7692ec0a01ae97a52c5cdca957b5d31103423cfbe45": "0x04010000000200000000000000000000000000000000074c55534e45540d4272756e6f206c757373616e1268747470733a2f2f6c75736e65742e696f13406c75736e65743a6d61747269782e6f7267116272756e6f406c757373616e2e6e6574000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471447d0dac62a754c76dc74b64f14d50dfb713f914714ac6adc34d806466858fe9289687aa0decaf762": "0x00000000000000000000000000000000000b4b7573616d614d696b650000000000000c404b7573616d614d696b65000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471447ea99c6c537b3af1e65015f1fcf3b5f0dad80efb6213321b2fbace6b1662722d574d9641bbfa072": "0x00000000000000000000000000000000000b436174686557616c6c730e4361746865205061726564657300001763617468657061726564657340676d61696c2e636f6d00000c40436174686557616c6c73000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714481d0bcc9fe1394af6bf18ddf629a634fe0dc352b4f82084c67135cb235f1a7caf05e7b70bd1d128": "0x00000000000000000000000000000000000000000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714481f4f2839a459d644a41e55054618d207431192696d5a5505935c9a8c7257e1067797c8484fcf47": "0x000000000000000000000000000000000007486f6773737308686f6773696869010117686f67736968694070726f746f6e6d61696c2e636f6d00000c40486f486f486f486f6734000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471448240b28222befe0c820f33cbfd5179274cc09289203fd06d9bf02fee2c2ddb01202b6588fde2d23": "0x00000000000000000000000000000000000a42525542414b45525a0000001562727562616b6572697840676d61696c2e636f6d00000c4042525542414b45525a31000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471448289f8a612ecf7a008963f0b205fdfab299aefe8f86eac63a6c8418b081c3333c2ab9da1767d825": "0x00000000000000000000000000000000000b524d524b2042554c4c530000000000000b40524d524b42756c6c73000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714484f9e39f4f0e8475cce1eed57740222d643b9c92a594bec58f9b9968bfd4d63d495a7fe5237ab1e": "0x0400000000020000000000000000000000000000000007686972697368000013406869726973683a6d61747269782e6f7267166869726973684070726f746f6e6d61696c2e636f6d000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047144851b9f7dac59c8088b775aecc56294102b3c3b55732f7355d69d629b7b3f75415134ae16fed8c49": "0x00000000000000000000000000000000000000000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047144871b57949825f03065cd01d8f8ad376ee4306bc8da85235688b7ef486eaa8efb7ef16228a32c317": "0x00000000000000000000000000000000000b626c75207072696e636501010101000001000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714489667186afa0e91ca5bc1915da74aba3aadd7ce7b809045d5eb5b73559259755fdcd85a40a5dc6e": "0x00000000000000000000000000000000000f4a414d20e298a0efb88ff09f908d001968747470733a2f2f73686f6b756e696e2e6e6574776f726b00156a616d4073686f6b756e696e2e6e6574776f726b0000114053686f6b756e696e4e6574776f726b000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714489b5689523a93fdf4f5911143092b1788c3a91f96d192b35e4fb201f05658f47b677e7dc9a1fd5d": "0x00000000000000000000000000000000001f52686565207c20444f5420456173742041736961204865616420416d622e055248454500001472686565756e696f6e40676d61696c2e636f6d00000c40524845455f554e494f4e000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471448a5df45177101a6780c9d8ff3121bf764b263a23d7913b4822df102bff190f70ea63effb2672d70": "0x00000000000000000000000000000000000c4b7573616d6163616e676100000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471448a936aa7fb7ee3630e0edcf2e2340535e12db18dc82636cc2398a3e51bc3c8652f738e3130f6c43": "0x00000000000000000000000000000000000773616e34657305416c657800001766756e70726573656e74373340676d61696c2e636f6d00000a4072796261345f6f6b000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471448b0b934213b6e967cdf18faef23f25dc98b3c1b43e11f334ff5df943dc922e8f24ffdd726bb3733": "0x000000000000000000000000000000000009504f4c4b41444f5400000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471448b805c30833f34f66f193bc93e18f77ec6e9b26ab283adb6b5e58cc43c6cb81a22264525bfcda57": "0x00000000000000000000000000000000000c4d6f6f6e2d4265617265720000000000000f405468654d6f6f6e426561726572000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471448c23fd18bd08932827463efe7300e6a0f8839aaae0278895c8bdb087088da4583402898e4174478": "0x00000000000000000000000000000000000f506f6c6b61646f744c752e444f540000000000000c406c7578696e7a68656e31000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471448cdedeb02681e28ac891d5a6e2f56c923dcff8c05d0a535c6695a118bf3de7ed3bab92ff7db641f": "0x0000000000000000000000000000000000144a6f6e617468616e207c2054616c69736d616e000016406a6f6e7064756e6e653a6d61747269782e6f72670000000b404a6f6e5044756e6e65000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471448da0b535190e8951a734819deec3876010a3867c2ac97785e17624a30d8f51d3ab4e93f0d0d9816": "0x00000000000000000000000000000000000000000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471448ec723cf1e5db8eb6886973c891bf20892bfe376d58c89e42f42163a47816c2b064ac7e78528f25": "0x0401000000020000000000000000000000000000000016e29aa1efb88f457665726c69676874e29880efb88f0d736572676579706574726f76000017706574726f7640736f72616d697473752e636f2e6a7000000a405361676553503739000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471448f55d60a49f7e0a2119e372adc7757021cc9e11304519ed6f8f0ef24a3a61dcc5c5e983b2d7171a": "0x040100000002000000000000000000000000000000000d4b4d4c204a616c6162657274084b4d204c6162730013406b656e6f6b6d3a6d61747269782e6f7267166b6d6c6162734070726f746f6e6d61696c2e636f6d000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047144900c2cf5eb1d4d5dce117ad72d855b586a1c7ab1e2e1400b00418037000a81a26d131eff8486b77": "0x040100000002000000000000000000000000000000001af09f949273746174656c6573735f6d6f6e65792d32f09f9492001d68747470733a2f2f7777772e73746174656c6573732e6d6f6e65792f19406161726f6e7363687761727a3a6d61747269782e6f7267194161726f6e2e416e746f6e6f706f756c6f7340706d2e6d6500000f4042656e57686974654a616d696e000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714490d06ea3a7f6662a4bfd8243876621936043198841c6226dd58bb5183f2581182ccbbf1f0804607": "0x00000000000000000000000000000000000000000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714494a0eac89f0ff78c63b6d81d7d307b9f4464304330a840f5159c78a804dd344c5fcbfb3da9aad11": "0x040000000002000000000000000000000000000000000c445241474f4e4c414e43450000154074616e69735f33373a6d61747269782e6f72671b74616e69732e737461636b4070726f746f6e6d61696c2e636f6d000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471449577d51da67dbbadc86d7e1dba377a90f087a942c0c2777851b447a16af68cfac09c2e58ecf7e1d": "0x040100000002000000000000000000000000000000000b4e6f727468776f6f6473001768747470733a2f2f6e6f727468776f6f64732e636f2f0016737570706f7274406e6f727468776f6f64732e636f00000d404e6f6178656e6565646564000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471449699ba492f6ca67be2153373520551c1a92b9a2f47ee66c0de25eb1e1c09a4b73af2fdf819c1464": "0x0000000000000000000000000000000000164172636869766572736520466f756e646174696f6e00137777772e617263686976657273652e61727400186172636869766572736538383840676d61696c2e636f6d00000f4061726368697665727365383838000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714496fd3c0ebe3acf5b2479a4c5a314be896da932acd7d770361daf76a8c0795afcbb09137ce83d545": "0x0400000000020000000000000000000000000000000012416d697220456b626174616e696661726400001740616d69726b68616e65663a6d61747269782e6f726719616d6972656b626174616e69373540676d61696c2e636f6d0000000005414d495200", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714497b07aaeca4b31138f65ffa021ed80b8111b27929180c5ebb79e279810b521adaa2bbc22c343b7a": "0x04000000000200000000000000000000000000000000076b61766b617a000018406d7978616c6574697368653a6d61747269782e6f7267116974656b31393834406d61696c2e727500000d406d7978616c657469736865000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714497f7f7e0d825e942084ed6e5d7bbd49c8bcbf018d5aec40e9e62ef105729b7dcb83007e3ac5c911": "0x00000000000000000000000000000000000a4368616b726172696e0a4368616b726172696e0016406368616b726172696e3a6d61747269782e6f72671a6368616b726172696e2e7361726e7440676d61696c2e636f6d000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714498d5c402783eb13d4da6bd9b592cffa69e19e3758d8984704c2335bf4c6474ad93e442f16b71556": "0x00000000000000000000000000000000000b736f6c6f6d6f6e3232360a50657465722053756e1868747470733a2f2f706574657273756e6465762e636f6d001375676c793032323640676d61696c2e636f6d000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047144997fd81d8f83eff7294d22dea735215a7ac4a2aee260eb25d1beaad4b02bd8dacf87bd611a96c3f": "0x000000000000000000000000000000000006416c656e610e416c656e61204c656f6e6f766100001b616c656e616c656f6e6f76613139393740676d61696c2e636f6d00001040416c656e614c656f6e6f76613134000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471449d8d1014a0c6d168029a7ce3dc02d90888bf05e8fe3ce278e7a8bf499cdb24c432315dace83176e": "0x0000000000000000000000000000000000054b796c650b4b796c652057696c65730000176b796c6577696c657361727440676d61696c2e636f6d000011404b796c6557696c657353747564696f000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471449e133447b19f12b84d282e5fd1797757dfd0075cdc362493994ae63d980d941081baf72ea395e41": "0x00000000000000000000000000000000000956616c696572616d000000000000104050726564696363696f6e73436174000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471449e3956212fb445c6e184bf933cc4cdd61b28f8609c1de672bcd1177bc284c479d184b1e9578d152": "0x00000000000000000000000000000000000c546865204e6f7468696e6700000000000009406865657a697573000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471449e898b75f9afd0d882faabfb49658b912fa7020be5bc8eaed5fba952a353359447d4406a1a24260": "0x00000000000000000000000000000000000c4e6f626c65204561676c650c4e6f626c65204561676c6500000000000e406e6f626c655f6561676c6573000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471449f010e5122c00e6fc71e57767a5284519f6f586a093a59bb6148d5b8a62ed7d65ebdd0e56c96a50": "0x00000000000000000000000000000000000d4775797346726f6d4d6172730d4775797346726f6d4d6172730000194775797366726f6d6d617273737340676d61696c2e636f6d000010406775797366726f6d6d6172737373000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047144a0028d535eaa15c36bfed4710cf084c43f5c119f46111b46d7d3c7ad9fc54745e04283a64cef16a": "0x0000000000000000000000000000000000076461696167690f42617275636820466973686d616e00001164616961676940676d61696c2e636f6d000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047144a0f7a54a1ff58eebceeeed23997617c15d2ccbf5f14196f88c4765152956458ec73b13716ab6b4c": "0x04010000000200000000000000000000000000000000075a6f6f657973001968747470733a2f2f7777772e676d6f726469652e636f6d2f13407a6f6f6579733a6d61747269782e6f726717706978656c747269706e667440676d61696c2e636f6d00000c40706978656c7472697070000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047144a15805a80c56a9eeee55cfb505663c2f6ca145bfd1942cf28f9c416db4d893b787a96feadee1066": "0x0400000000020000000000000000000000000000000011546967657250726f204361706974616c00001540746967657270726f3a6d61747269782e6f72671a746967657270726f6361706974616c40676d61696c2e636f6d000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047144a1cf1abc24f3e10d215f8486a8ae2ec99783c371eb0a270a5e7a4b6e2eabe42270ad46a90d28523": "0x00000000000000000000000000000000000a536269726f76736b690101010100000b40736269726f76736b69000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047144a2cd9d6d0b8021feaf06fd1666c41a9f0879bbe0928041cc4bc5dfd31f1d36ab4abdb643228584e": "0x040000000002000000000000000000000000000000000c63796265726f6d616e6f760000184063796265726f6d616e6f763a6d61747269782e6f72670000000d4063796265726f6d616e6f76001163796265726f6d616e6f76233739383500", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047144a30177d9940d3d8dec1aa82291268cf854ddc3ed0a0869ed1da026b4e5df758ad4f6a380ecc052b": "0x04000000000200000000000000000000000000000000086753616e373143000000136773616e6a37316340676d61696c2e636f6d000009406753616e373143000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047144a46ea11348a56200a66532a23c418cca12183fee5f6afece770a0bb8725f459d7d1b1b598f91c49": "0x00000000000000000000000000000000000d44617277696e69612044657600000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047144a539d4f2d822bce28aff3e47f38d52ef86e186b3d0e5935e813fce1f3ed67c3cd2237171c9f2048": "0x000000000000000000000000000000000009386269746c6966650101011564656461756e756b696e40676d61696c2e636f6d000001000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047144ab3116558524fc28ef755e985c62930b3c452073aef9336f78ba7bd0d48b2a19f3aaf430dd2d573": "0x000000000000000000000000000000000005646f2c6500000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047144ab82d82d397c8860874d8217aef5c084de244fbc3778345f11abe840071962ae16bc3709def6f57": "0x00000000000000000000000000000000000973616d65206f6c6401010101000001000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047144abab00f092058545487b54dc747fcbe6747dea2ce277caa6f70b21ec7031c20560b693c4b8f9066": "0x000000000000000000000000000000000009506f6c6b614d6178000000196d6178696d652e6d697261746f6e40676d61696c2e636f6d000011405468654672656e63684d6178696d65000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047144ac339d82839fc62b8076afe0f3dd1a5b76b65ed4b34f0fca26a4bcae1e98ff052836ecdad1cd955": "0x000000000000000000000000000000000006596f7563650000000000000a40796f756365617274000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047144ad035c90c4d684092084338b54489d20ae38de6e2e3014504d49e8c69da585a7994f5cf1d3a0e06": "0x04010000000200000000000000000000000000000000175375706572636f6d707574696e672053797374656d731a5375706572636f6d707574696e672053797374656d732041471368747470733a2f2f7777772e7363732e6368000c696e666f407363732e6368000008405343535f4147000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047144adf867ad6d86f6e22ecf13716f735f9b2fdfc69032bf3fbc35b9b0f11fdb7e1885ba24da2f96c32": "0x0000000000000000000000000000000000074b696d50726f00000000000009404b696d70723030000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047144ae112a6269c8ee59e10cc56a3e2852932123da5f88edcc0e81fc797ea65ea4225d0720efa7fb764": "0x00000000000000000000000000000000000d506f6c6b6157617272696f720000000000000e40506f6c6b6157617272696f72000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047144afda37d0066d26344a9b7448162343250ddebb4d5eca9cf18c0fd710c01f65c20ef5a7a2b08c160": "0x00000000000000000000000000000000000a4c7567616e6f646573001668747470733a2f2f6c7567616e6f6465732e636f6d0013696e666f406c7567616e6f6465732e636f6d00000b406c7567616e6f646573000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047144b11c09379596e080ac8aad77582e035ce510d01d6bdfa7d8eef2445bcb492123120d3ee940aa16e": "0x04010000000500000000000000000000000000000000094b7573616d61203100000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047144b290c17b4e25a4a36e132f4b16bd325ddb6a3c63562f23c18dfd20bb2c785d391f625f481097c1f": "0x040000000002000000000000000000000000000000000a6c6574735f6e6f6465000016406c6574735f6e6f64653a6d61747269782e6f72671a7465616d2e6c65747363727970746f40676d61696c2e636f6d00000b404c6574735f6e6f6465000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047144b3956c26b2adb6f2c47a26841623e7a55aecd35d0d8972fe0a05b7a9f65ad36e2fe47f465d6ea4e": "0x0000000000000000000000000000000000054b59544500000000000008404b7974655f30000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047144b3d0a4ac99549aef4e2e84d81b6dc5b195f0e03e36c1810af34eb2c64d2570d0ed343473d846b7a": "0x00000000000000000000000000000000000850616e646173730850616e646173730c70616e646173732e6172740000000010406b7573616d615f70616e64617373000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047144b3db0fa2b7c5e1502a095fe039e07658c9fa559d0919e4f4e288b383882a2262d322a71007f5704": "0x040000000002000000000000000000000000000000000d5669727475616c4261636f6e0000001864656e6e6973407669727475616c6261636f6e2e636f6d00000f407669727475616c6261636f6e31000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047144b425fef2474f0f6e08407ceab678c192cb8605649dd4eb488d8f3611ccb496c83ef856b3e1a430c": "0x0000000000000000000000000000000000115468652053696e67756c617220424f54010101010000104054686553696e67756c6172424f54000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047144b5632672e4e08b2e2fec50feac8a6c83a3e9f869ce04ab800420b2c80c4310f2de2e9f0adfa301d": "0x040400000002000000000000000000000000000000000c50726f666974206c696e6b0000001b67617263696170726f6475636572393140676d61696c2e636f6d000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047144b5a0926bf96567c4230c50bb60625c3db7e0446f4528301691ccb07fa5572cee0444f86c9d30511": "0x0400000000020000000000000000000000000000000009636c616e67656e6200001240636c616e673a6d61747269782e6f726700000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047144b610455a917d0af0422941b0c99c8add13283a6b1d5e62e55d9e634ffa427591031f7a4fd8fb16c": "0x04000000000100902f5009000000000000000000000000000000000000000000000000000000066b6f6d62690000001463656e776164696b6540676d61696c2e636f6d00000d4069616d5f636f6d62693136000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047144b7fd70c8f696bc35842bb6c3f854a1bb2243b20069f088f306eb9101ad40f8b120d268578d8f547": "0x00000000000000000000000000000000000944696d73756d31330000000000000b4064696d73756d313331000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047144b9d785f0afee887423e5d0451428d77e1f81f6f20c87427e355468da3ac8eea9eee7f041871a733": "0x040000000002000000000000000000000000000000000c646f746265726b656c65790000000000000d40646f746265726b656c6579000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047144b9d8be32324ecea4466b2edfa709b581c84f0b55deabcb93de767955a37c6513d18dbca4d261069": "0x0000000000000000000000000000000000076d6164346f780a4e757273756c74616e00000000000b406d6164346f78617274000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047144bb93cb3dc92785e3e6f301b0a1e1a9c7bf69be3b0bd221a150319c3465bb42e2e7820cc0b1a0e4e": "0x000000000000000000000000000000000009534659204c61627309534659204c6162731e68747470733a2f2f7777772e737469636b79666163746f72792e69742f00167366792e7374617274757040676d61696c2e636f6d00000a405346595f4c616273000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047144bbbcb9ded8c9980f69287204245020e54f703c5f12edc826ceac6c514a4e947ba402d9c32615e37": "0x00000000000000000000000000000000000e54776974636879547769746368105374657068656e204c696e6473657900001373706f646e65737340676d61696c2e636f6d00000c404875654368726f6e6963000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047144bbd9731b8ad75407894adb5327cf29867bc6eb3d212dc96760f511ee3503d3f3ba1fbccb190434e": "0x040100000002000000000000000000000000000000000e4b7573616d612057616c6c65740d57696c6c69616d2054616d7300001774616e752e63727970746f3340676d61696c2e636f6d00000b4074616e755f74616d73000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047144bbfbd1503dacab9f01c087c4a752cbf56ae4672f910acad4b234a830818356b8378afcd8e042360": "0x08010000000202000000010010a5d4e80000000000000000000000000000000000000000000000000000000a534158454d42455247001768747470733a2f2f736178656d626572672e636f6d2f1840735f736178656d626572673a6d61747269782e6f72671468656c6c6f40736178656d626572672e636f6d00000b40736178656d62657267000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047144bc05de7e42ebb50ceeccdb6802df2253998f9d4f928b120d51110d1d2afd969b95232bc16768702": "0x04000000000200000000000000000000000000000000096b6f6b656e616b69000015406b6f6b656e616b693a6d61747269782e6f72671c6b6f6b6564616d612e736167616e616b694070726f746f6e2e6d65000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047144bc1483b442cf7e9662fb31b7c1853748f43f46de1b1d0ef23ea62165357c098e72621ac6b54347f": "0x0000000000000000000000000000000000084a617276696578084a6172766965781a7777772e61727473746174696f6e2e636f6d2f617669726d7a0018696e666f2e6a61727669726d7a40676d61696c2e636f6d00000a406a6172766965785f000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047144bc16c907ee6cbf1eef5d9e432937a9eb75c3ff77eed7fcd5f737899ed8f430fc0cf973ec61bf308": "0x0000000000000000000000000000000000044e494e000000166e696e2e6672656e63687940676d61696c2e636f6d00000d406e696e5f6672656e636879000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047144bc4e6ae3f5f5afdc470d4501fc73c4bdfb5c4a2faf683657785a8714fd9c4b8ebb6ff3835950f4e": "0x00000000000000000000000000000000000557617361055761736100000000000d4043727970746f5f57617361000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047144bc589ab602f6840aaf5b22b19bd3ea8d77cffcd9cf1d1fe284bab4d8af41577edb4d8266c8add58": "0x000000000000000000000000000000000006504f4e494f0000000000000c40506f6e696f6d6f6e696f000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047144be3d4c5b2fe50ebeac4895a2fbabcb267962c7f717455d5c77cd3104c71b943c04ced35a6cdcb0d": "0x000000000000000000000000000000000010204b4f4441444f545f737572766579001468747470733a2f2f6b6f6461646f742e78797a0000000009404b6f6461446f74000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047144c058945adfbac44402589207ea3e9ba42e801aa4c708c414b804a5309216ccd01b5b6717646301a": "0x0401000000020000000000000000000000000000000013444154414d494e452e4641524d204e4f4445001668747470733a2f2f646174616d696e652e6661726d1940646174616d696e656e6f64653a6d61747269782e6f72671876616c696461746f7240646174616d696e652e6661726d00000b4056446174616d696e65000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047144c13d695515297086609300c61120adaba3301fe939f37a0c68915b8e998234283f800e7eb16e224": "0x000000000000000000000000000000000017e1b485ca8020e1b484ca80ca8fe1b498e1b49be1b48f001a6c696e6b74722e65652f63727970746f756e706c7567676564000000000c40447243727970746f3437000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047144c1956d8be560280b4ec21e13380c9be78fd373b4f73bfd4b21d8ae43274220f1de50c8d8eb9b329": "0x0000000000000000000000000000000000064a67756c68075275736c616e0000144a67756c682e656e6740676d61696c2e636f6d000007404a67756c68000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047144c28b62f4c20a085a223f906156407224304ef1353300b63d3fb6a4f3cffbb117239149c0884917b": "0x04000000000200000000000000000000000000000000114b5553414d4170706c69636174696f6e0000001e636972696269666572612e70696574726f393940676d61696c2e636f6d0000104050696574726f3337343230333730000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047144c3a92bfc0327de1b8fdf4d6648e1e72dd1ebd3d2acac4c85e1d6b17b3c657153a94db2e0c2aa356": "0x00000000000000000000000000000000001076696b695f7468655f77697a6172640956696b692056616c1c68747470733a2f2f6769746875622e636f6d2f76696b696976616c000000000a4076696b696976616c000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047144c4ff33745201ef57c04de8781bd329a979004519d2e6b02ddc140af6a548b3b59008053d5459537": "0x00000000000000000000000000000000000000000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047144c530bbe085c5f6b608bbdc4a6f918146da541013750078357a37afc7c397d7a0fd3c4c7e528b23a": "0x0000000000000000000000000000000000125241482d44455349474e2d4e4c204e465408526963686172640000000000104052414844455349474e4e4c4e4654000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047144c5546659ce31189d0075cd9bb3988e0b5e05b124b20127e93531bc80c40ac0e4a1f22006815285d": "0x0000000000000000000000000000000000065375736861011f687474703a2f2f7777772e73757368617368656c656e612e636f2e756b2f010100000b4073757368615f736865000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047144c6fb887a199d035466f0fac5092dbe66d2402fde1bd7255483f087deabeddbaab26142d5a3db71a": "0x00000000000000000000000000000000001754686520436c616e61727920436f6c6c656374696f6e00000015746865636c616e61727940676d61696c2e636f6d00000c40546865436c616e617279000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047144c89c93c5a9d60f348cb77bc66938feb608aaf2ddc62faa8cfa2b9c7c9576fb5f69ca8913b41f713": "0x040100000002000000000000000000000000000000000641726a616e1141726a616e205a696a64657276656c641a68747470733a2f2f6769746875622e636f6d2f61726a616e7a134061726a616e7a3a6d61747269782e6f72672161726a616e7a696a64657276656c642b6b7573616d6140676d61696c2e636f6d0000114061726a616e7a696a64657276656c64000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047144c8f1e30e595b6bb7c4039fa473c4bbdfb7d175ddbef8407fda3e32ea0df0536c806bd4a64c6f35a": "0x000000000000000000000000000000000006666f6f677900000000000008406d667567616a000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047144c9165b3ec94f3b1c602f98da395c5bf3804e86851c5bf2a30db39848d62f6c14fea1a300946ca00": "0x0000000000000000000000000000000000096b736d726f636b73010d6b736d726f636b732e636f6d010100000d406b736d726f636b736f6663000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047144ca13e1b44c9d065a63e6b2499f54c2be949deb97b030010274cef1d88c2af220b1c6013096e4e44": "0x0000000000000000000000000000000000056675636b0000001365706f6361383440686f746d61696c2e6974000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047144ca2592175bb1cc4a09af83b3d2e115f1aca50377618b28b8891101b1f9d06a36889499676427b27": "0x0000000000000000000000000000000000086b616b61726f7400000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047144ca775588b3d2ef060b8d7880b3110a1609b771f10f2ecff15a345059368867bdae4c6884c888210": "0x040100000002000000000000000000000000000000000d444953432d534f46542d30310e4469736320536f6674204c74641a68747470733a2f2f7777772e646973632d736f66742e636f6d154064697363736f66743a6d61747269782e6f72671876616c696461746f7240646973632d736f66742e636f6d00000e4044697363536f667457656233000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047144ca8b26602d73427e46675e622c45de390f070b175f99ea56d47537b076a3fc9ac0bc07c38e01005": "0x000000000000000000000000000000000006464f58585800000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047144cce5213f083cefe724cf673d804e34e23743be0969e9606c64b7ccf64a82b498c77a3195ad6214c": "0x000000000000000000000000000000000011416e61656c6c65207c2050617269747900001340616e61656c6c653a7061726974792e696f00000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047144cd9322609738faf34a6cda09ad0388dd406269c050889d0fe64d996c3ff3571e26802ecdefedc51": "0x000000000000000000000000000000000006546961676f00000018636f6e7461746f646c746e657440676d61696c2e636f6d00000c40646c7461636164656d79000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047144d0e40b01504aed30c0a7bb6b17a969c1c076cb422eb08c0185f932f494086f4d37abedd18af487e": "0x00000000000000000000000000000000000f42696e616e63655f6b736d5f32360f42696e616e63655f6b736d5f3236000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047144d1691d80588b205382d4a2c2b6eee702dc19705f86d9113e79b860306c1b672db9adb4da9d5631a": "0x000000000000000000000000000000000017524d524b20527074696c69616e732043726561746f7217524d524b20527074696c69616e732043726561746f7200001d74686572657074696c69616e732e726d726b40676d61696c2e636f6d00001040524d524b72657074696c69616e73000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047144d35c327c115f99b08745476e8a2fb16504c77a75b2dd20b6f56cfb71c87125f1707a702753af24e": "0x00000000000000000000000000000000000642726561640e4272657474204b6f6c6f646e792168747470733a2f2f6769746875622e636f6d2f62726574746b6f6c6f646e792f0000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047144d3e0d4f24d59fa98ce6c79ffe1d5f06f89eb2ec7653c8c9c33cc32506aaa8ba0d4e0b63b43a5d67": "0x00000000000000000000000000000000000c6261696c65796e6f6c6665124a6f686e204261696c6579204e6f6c66650f6e6f6c66656d656469612e636f6d0101000001000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047144d4b24b1bbf7bc3bd0b1cf79e7be19b7cf96bd4e625f4d5002278802fc0542a42535770798869b2f": "0x0400000000020000000000000000000000000000000014506f2d4b752050656f706c6520e29da4efb88f00001640706f6b755f6e6f64653a6d61747269782e6f72670000000c40506f4b7550656f706c65000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047144d585451a689512eae088990b08a6e0e8c06a9234cc06125677742fb1307bf70a2775ed19427dc09": "0x00000000000000000000000000000000000c65746e612d7061796f757400000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047144d6200fed0714c63987ebea45bea8a2676cd896c6e01460290bdd56a6dcb27e9648fb33ac2b7fe66": "0x0000000000000000000000000000000000084e65656b43757801010101000009404375784e65656b000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047144d699313bc760a036a81f13352076dce1dfe8f357fd805bbece6ec16efabad52a2c24e6824e16315": "0x0400000000020000000000000000000000000000000008494e4748415a4900001440696e6768617a693a6d61747269782e6f7267147374616b696e6740696e6768617a692e636f6d000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047144d9a1147d1ed82c8b00eba4acb0f53ac420d73857bfba1ac2df6e3a4fd8001fd4bc1691e9a8da44e": "0x0000000000000000000000000000000000076e667465657a00000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047144d9dcf234fbee40ff6f2366ea3f3a900ae6b42a85e4860ca95bd5f42ae8e42b9ca30bfd975f7006d": "0x0000000000000000000000000000000000064d617474610f4365736172204d617274696e657a00000000000e4043657361724d747a4d617461000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047144d9e54521ff7e843ce3f66e4350864006ec5174657fea7729c83aa847e1949ca8256686e07c98123": "0x00000000000000000000000000000000000d4961726f7661796120415254094b61746572696e61207777772e696e7374616772616d2e636f6d2f6961726f766179615f6b617465001963727970746f6b6174653139383840676d61696c2e636f6d000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047144da1eb2472c6e636a0802cb1cc2721239d717a1b2aaf59febe8995bb5c374272b7f7d346e8b7b923": "0x040000000002000000000000000000000000000000000e4c61626164616261646170746100001b406c6162615f6461626164617074613a6d61747269782e6f7267186c61626164616261646170746140676d61696c2e636f6d000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047144db2a789d942dda53e3c2bc736c233d8d77544e74987ceb03bcac1ba7904b1a98f377883d4b1733f": "0x00000000000000000000000000000000000e4d616e7461204e6574776f726b0e4d616e7461204e6574776f726b127777772e6d616e74612e6e6574776f726b010100000e406d616e74616e6574776f726b000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047144db321631814cd32ace82546c558ba2ec9e42f805a65c2f16f011216b01b0bbcb32d6b68ffdf8c6b": "0x0000000000000000000000000000000000065269676f300101010100000c40416c65785269676f3930000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047144db4fe1336b5ba5a06dc4e63396771cc7d4e36c3fc749db4b0f367c9c9edfd37badf8aa31efea960": "0x00000000000000000000000000000000000f42494e414e43455f4b534d5f31300f42494e414e43455f4b534d5f3130000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047144db8c074b305156e12fbc6f6f8379674458d237fa3a42ad300923a6721841c373dc2a168c83e0479": "0x00000000000000000000000000000000001bf09faaac2054616c69736d616e20476f762044656c6567617465001568747470733a2f2f74616c69736d616e2e78797a000000000f40776561726574616c69736d616e000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047144dc9b342edef30bb0404127e6dee3322530e94ae97f3c9d21f0549b5140d9d004cadf94a66a2b730": "0x00000000000000000000000000000000000d524d524b53746f69634465760753746576656e1b68747470733a2f2f736e616b65736f6c64696572732e636f6d2f000000000b4073746f696364657630000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047144dcd3691e5f659d55e0e72cb881993bf61241e60224f1e6bf2b9acf201c84cc5c6cd05fa6e0c591a": "0x000000000000000000000000000000000009616264756c6c616800000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047144de1efce0c5d7d9ff807dd354eec53082fa68580d6240ca57bb0f02afd6697c6f35b3fc11f0da402": "0x00000000000000000000000000000000000e50756e6b205661756c7420233700000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047144e066e19d4ddf8f19eba94f67453eeded0e6c8ce2932269f57b7227f6873b782a3a0aa0cad95b40f": "0x040000000002000000000000000000000000000000000e4e65756b696e6420546f6b796f0000001168656c6c6f406e65756b696e642e6a7000000c406e65756b696e64696e63000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047144e0979985c355367e080d3f0de7be8f9edc6d90d8bc337aac66844025f3e9da7129356eda0f04256": "0x0000000000000000000000000000000000114e6163696f6e43727970746f2045787407416c657820470000174e6163696f6e63727970746f40676d61696c2e636f6d00000f406e6163696f6e5f63727970746f000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047144e0e08d8f728b4dd32068fb3b800c5df40df16619761b3418e40d9455784b6a293d2425e35ef2c27": "0x04000000000200000000000000000000000000000000054c554341000000176d6172726f6c754070726f746f6e6d61696c2e636f6d000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047144e3ffaf4570f18710a3289a760e8155e8894b96d8a319d43588281ef4f69c1bd0a0daaeb845d980c": "0x0000000000000000000000000000000000027600000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047144e6523a4af508944f2311ebbe228b955638ea3a3d58a8c73ffe0b98b2ea8214617c397bc98f3dd37": "0x00000000000000000000000000000000000753656557687900000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047144ea5d0f641dc611c309d30ed1f41373d0abb1b8dfec4055e93312d73e9e7279f776e662fe306a00c": "0x000000000000000000000000000000000010546f6d61737a205761737a637a796b10546f6d61737a205761737a637a796b1568747470733a2f2f7761737a637a796b2e636f6d1b40746f6d61737a7761737a637a796b3a6d61747269782e6f726714746f6d61737a407761737a637a796b2e636f6d00001040746f6d61737a7761737a637a796b000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047144ea6923b31b03243e0b9bdcc45111c7c23b354318607f4cbda8e7f017d500aa15402b1a16a36497a": "0x00000000000000000000000000000000000e524d524b206f6666696369616c0009726d726b2e6170700011636f6e7461637440726d726b2e61707000000940526d726b417070000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047144eb1abadf357251052c4cde966f7c4088d60cbf459a665660d36ae1f664cf65a86ced132b645c833": "0x00000000000000000000000000000000001353697874792d466f75722053717561726564001e68747470733a2f2f6d656469756d2e636f6d2f403634737175617265640015737175617265646e667440676d61696c2e636f6d00000c4036345f53717561726564000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047144ebc48c63a5dc09fa4ac69b3ea42acebe4f70767ee894eeef5eef1f011f0dca45097a2e6c40c5366": "0x04000000000200000000000000000000000000000000036635000017406b7573616d61323233333a6d61747269782e6f72671e6b7573616d616b6f736d6f73696c613232333340676d61696c2e636f6d000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047144ec6dcb09516ac9cae463a6613cae63a77d1c391bb1e00a974ccd178ebd91e00268608f3a570f84f": "0x040100000002000000000000000000000000000000000d5061736861426f7563686572000000177061736861626f756368657240676d61696c2e636f6d00000e405061736861426f7563686572000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047144ed0bc7ef1112e6f2ee6766c1a3679e5638966ec23c25dc094b99c082151f913704f439cb1e07636": "0x0000000000000000000000000000000000084b7573616d616e0442656e000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047144ed12f7f95496d053674aa73951219dbd27b3e3fc5847b806c68c1de38fd4f22f9493a461c80e903": "0x040000000002000000000000000000000000000000000b472d646f742e74656368001368747470733a2f2f672d646f742e746563681740672d646f742e746563683a6d61747269782e6f72671467646f742d746563684070726f746f6e2e6d65000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047144ef34c27d4dfe709f615fbe2b5b19fd70abc2d71709e5a8efda335fc4ec06d25ac1105d7eaa92663": "0x00000000000000000000000000000000000b466f726572756e6e657200000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047144ef6058a4c93b2fc18e2ab095c1838261df21f7474602c520288bbb6b328728417d5b6189591a054": "0x0000000000000000000000000000000000094a6f686e566173650d4a6f686e6e7920566173656c0015406a6f686e766173653a6d61747269782e6f726716656e61656e6169736f6e3240676d61696c2e636f6d00000b406a6f686e5f76617365000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047144f0201a59b9849e4541e0539e47fdc4222ab09d8b19ae6ae612de8088ce5e73afd2e1b926ada255b": "0x00000000000000000000000000000000000b446f7473616d616b696e00000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047144f08661e9ff1a0dca2faef0d22feb488024378daeefdc612f34713c17425c5fb5c1ee5ecca7f3908": "0x0401000000020000000000000000000000000000000009417272697665657200000013617269657665657240676d61696c2e636f6d000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047144f0effdbba5ecc713aecc4a1d9f8b782b08d7468da4753da690d55c26f9bd1fd1ca09dbc60bd4a1e": "0x00000000000000000000000000000000000b54686555464f437265770953414e544941474f00001654686555464f437265773140676d61696c2e636f6d00000c4054686555464f43726577000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047144f105dc4d6865f85da54f55778dd9d3ccc434d0000bc254788d7e0a9c766b8f6dde51e335a28305c": "0x0000000000000000000000000000000000084d69726167657a114a616b726170616e204d6565636861690000124a616b6170616e40676d61696c2e636f6d00000a406a616b726170616e000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047144f133aa79b057d66fef5977196fe3fe5c456a767e6b06013ca62762b282de97040add4ad2c53db61": "0x040000000002000000000000000000000000000000001350726f5374616b6572732e636f6df09f928e001768747470733a2f2f70726f7374616b6572732e636f6d1b4070726f7374616b6572732e636f6d3a6d61747269782e6f726718706f6c6b61646f744070726f7374616b6572732e636f6d00000f4050726f5374616b657273436f6d000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047144f1e36622dd2acb4fcc2b373ac96c11d293ab0565d243750874cd8d060b66d1d908761ac1d616d79": "0x00000000000000000000000000000000000000000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047144f2ae4ec939743a590bdd91c993e87db3f250c0d9276d9b122e8cd571cfc0d5d6c54066f2a225a32": "0x000000000000000000000000000000000008427269636b737a00001440627269636b737a3a6d61747269782e6f7267176461627269636b737a37303040676d61696c2e636f6d00000b406461627269636b737a000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047144f2c0ec81395af615055fbad57aeb372174b99b9dc3723e1bd0f28febc74008251d7102e5ba631eb": "0x00000000000000000000000000000000000a4d6f6f6e7374616b6500000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047144f3ddf57e13a6e9f5cd992745ac97a51f7535709b288163895baa3b70f2620c3141f9a16b8ec8714": "0x0000000000000000000000000000000000134c69666542616e206f6e20547769747465720d426f6220446f62616c696e6101011c43727970746f57616c6c65744e616d657340676d61696c2e636f6d00000e4062756b7368756b616c616b61000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047144f3e6ee6ff9d1b948244b130639897c7f76d7838eb1c530786b0c1e15e65f0c09c0a6a3ec35f9d68": "0x04000000000100902f50090000000000000000000000000000000000000000000000000000000a79656c6c6f776265650000194079656c6c6f776265653236373a6d61747269782e6f72671779656c6c6f7762656532363740676d61696c2e636f6d000010407962656539313238303835353036000f79656c6c6f77626565233733303700", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047144f487a423739a66d8e27005a0b559b40d16613abc2804aef92cd137692b2eb228820e20aabdda27d": "0x000000000000000000000000000000000007704d725f4e4c0000000000000840704d725f4e4c000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047144f4f5169450cef7530b0e3fc5407fa802e7988b2d86f8eb9d13784e230668e74cd90eab4d48d145b": "0x00000000000000000000000000000000000f4275726e6572204163636f756e7400000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047144f5fac645183a09c2ab937c4061cfa1059fbab2252518119f1f4f18a1f0155ee42732ae263c4510a": "0x0401000000020000000000000000000000000000000012454c454d454e54204352454154555245531042656e6a616d696e204e6971756574000021456c656d656e745f4372656174757265734070726f746f6e6d61696c2e636f6d000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047144f96a77cdf9bb4b12ee187e3230395e417650558d1362b6dc594a481134ff29b3d63db53b8597d09": "0x00000000000000000000000000000000000b414c4c434841494e4d4a154d61726369616c2053204465204c656f6e204a7200001a6d61726369616c64656c656f6e333040676d61696c2e636f6d000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047144f99ab6629a5af0254007a3d6d00fa2d2c2e8f8b24c88def5120d3b168e003b7d15a405a5c105d67": "0x040100000002000000000000000000000000000000000c4d696368616c4a657373650d4d696368616c2056616c636f0000176d696368616c2e76616c636f40676d61696c2e636f6d000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047144f9f5cdc4b4279e04ad1d3ce2898b3b78ac9df34af660eefd167222e9efdb07467a0c82160903f7a": "0x000000000000000000000000000000000009526f6d616c6f727414526f6d616e204c6f72746b6970616e69647a65000017726f6d676c6164696f6c797340676d61696c2e636f6d00000a40726f6d616c6f7274000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047144fb1c11ebf76bf856c70f422fbca28c1e03e79bc42594c5bd8588a7c23454842f169b1b8c57db47e": "0x0000000000000000000000000000000000096f6e616e61736f7500000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047144fbb681dafad845da0f491d92cddc77c2487a3fba73ac3008e418a146631a742407b1af5e107c568": "0x00000000000000000000000000000000000b4d616e7361204d7573610000000000000c4069736861726c65653932000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047144fc324df3bb6d99258bb56063a47ee6e4a4d0bfe444682394a1e4657fa39f4622f2a0285689c1b3c": "0x00000000000000000000000000000000000b4441524b464f5245535400000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047144fd5ef0c5bb8d4b6aef764dd5f7e23556b143bc80e0ae0b4835b469dbad3b0dbea4b8275e91e5256": "0x000000000000000000000000000000000006566172757301010101000001000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047144fd7f55b4df090d0ca1b43ab297c7745ad2f6b3b5b201df66cf98723c3029230ffe61057084a8425": "0x0000000000000000000000000000000000094b6f6d61696e7558000000166b6f6d61696e75786e667440676d61696c2e636f6d00000b40785f6b6f6d61696e75000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471450004b04910a1297929aa2bfe7b52500b288c943b7c24a90928cd8a6f7ec8eec44763d9f74198401": "0x040000000002000000000000000000000000000000000f43727970746f2d6275696c64657200001b40616e746f6e696f2e63727970746f3a6d61747269782e6f72671b616e746f6e696f6b61726170757a7a6940676d61696c2e636f6d000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471450045aaecb66d5cace6fb186ae3769b7bbee62c3ea178cf730754413b26bfe540eda5ccce590d444": "0x0000000000000000000000000000000000096b75727572614c5000000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471450079469344a3846844f55022b2b8667129c167068a9c2a6bc292f2d312336bd98339d686b575a1b": "0x040000000002000000000000000000000000000000000b416c6c34486f646c657200001740616c6c34686f646c65723a6d61747269782e6f726717636f6e7461637440616c6c34686f646c65722e636f6d00001040616c6c34686f646c65725f636f6d000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714501e18a682931984145bf48774f53c991d99038301e44c30a2de38d805016bc6ea1a95d74b2a7f4e": "0x00000000000000000000000000000000000d73696c6c79736865726d616e00000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714501f97beba27688eba2c0d2631820207e6461b85177854a6cb019fd8b7f689c9a255457b346ead78": "0x000000000000000000000000000000000006437261696700000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471450233fe85fbce46c6ee137ac7e0f2103c00e787b5ba39ea7ce81c245e4ac64718041272d8218c748": "0x000000000000000000000000000000000009437269737469616e17437269737469616e2d417572656c2047616e657363750c69616e637532312e636f6d01196372697374692e67616e6573637540676d61696c2e636f6d000001000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471450417bc6d24f055d92200a0fa4244b13cf0277ce222a51979033d35e0cef4c692b27b4871d748b06": "0x0000000000000000000000000000000000114a6f686e314d6163206f66506865656200000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047145045ef62591a03255a26d9a7c3642c9bac25a08bf77ddf394916fa48fd714e61e8b5088fe8f58872": "0x0000000000000000000000000000000000074b3273616d61084b3273616d616e0000146b3273616d616e696140676d61696c2e636f6d000009404b3273616d616e000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471450494b773f99187c086b3cff28537011ee3cdb33556a85d93cb1d836c7bb2c8e9a000a339d887136": "0x0000000000000000000000000000000000154d722e20426c61636b2057686974652047726579064d72425747000016726176656e32303139303940676d61696c2e636f6d00000d40726176656e323031393039000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471450541acb5b3adfcb783677be3528d7c562df11a31317f6138279cd39ef96abba3dd1f38e9896a37f": "0x0000000000000000000000000000000000127733662d7374616b696e672d6d696e657200000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714505689aea117f4b4d03671180d2ac566d1ed507709b08be083bdb86d29d36a654f899c8c9e624874": "0x0000000000000000000000000000000000044f746407416e647265791a7777772e696e7374616772616d2e636f6d2f6f74642e696c6c00126f74646e6e6f7640676d61696c2e636f6d000008404f7464496c6c000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714505fb34a37127f8a58e8959d0add94c9171e095082f1a476fe16fff8fd01a0e51401135f4801d844": "0x0000000000000000000000000000000000046d726200000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714505ff16b5338dbbc26b65a62591e46572822dd9b2e5866b150fc2a10196ccc8ff71303d3e2713e69": "0x00000000000000000000000000000000000a4d61726b20524d524b00000000000011406d61726b5f656d6265725f7279616e000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047145082507ad8dcff7f3cfd8876d11ad724df41e20f43f3bdedabc6d83620a029b9d7c28f54ebc47501": "0x00000000000000000000000000000000000358430f5869756361695f66696e616e63650000127975727569717540676d61696c2e636f6d00000d407368756169676579757973000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471450841acc86ed6f0be071272e72b49c948d9b4013d7563b649cb1730b0a52de303155dcb44c9e497d": "0x00000000000000000000000000000000000a4d6f6f6e62756d3364024a00000000000b404d6f6f6e62756d3364000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714508509c16c555d079458bb073e69511e772b1608cff07add7f5240cb1c89cabde012d5b29504e72b": "0x00000000000000000000000000000000000a7874755f63757272790c43727970746f52616269741568747470733a2f2f383735372e6574682e78797a001a636f6e666964656e63652e6d6f766540676d61696c2e636f6d00000b406a6961736875323131000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471450c343c18df87d20fe565d8fcf8fdb44c9a61cc16a70649519a2acda598ee64d5b664e09a76d1c1d": "0x00000000000000000000000000000000000a646f6f6d73617965720000000000000d40646f6f6d73617965725f31000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471450c3b90207ca02d3d2dc9a9f85e3c523f1da8ee7e3e116f520ed49a53a48aea229147880736b906f": "0x0000000000000000000000000000000000000000000000000e4063727970745f6d6164646f67000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471450e0223a7f06f4edee2804a63951212e1342a2c01ea12f20153f27b6a5a649ef2e6c7b20d7859f68": "0x00000000000000000000000000000000000a696b68616c656432380000000000000b40696b68616c65643238000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471450fc5019aa653ecf50c91b0b82bff9b1b93145633214a08d5fd25d12e6c78a3b369cd7e539b92e26": "0x040000000002000000000000000000000000000000000853616368696b6f0000144073616368696b303a6d61747269782e6f72671c73616368696b6f2e76616c696461746f7240676d61696c2e636f6d000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714510331c48413f98ff85f04ed2bce67d0b51550754bdd4da9f8800f83ad39390c5925429f3cc47d47": "0x00000000000000000000000000000000000a5472756f6e674b6169064865726f330101010000114050686d566e54723038323236353134000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714511c6af03bd0bb3e6abb62dcdf9839bcee6a1686d8bba50e66959c2b5f23bcbb353eaa2522e62520": "0x000000000000000000000000000000000016496e697469616c576f726c6443726561746f72303116496e697469616c576f726c6443726561746f723031000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047145126d11d32941450dc41188d0dcd6722402508e1eb7601ac5d225c923114ff63aa085f20756fc371": "0x0800000000020100000002000000000000000000000000000000000f564c41445950524f4d4f5445414d00001740766c6164796c696d65733a6d61747269782e6f726715766c6164796c696d657340676d61696c2e636f6d00000c40766c6164796c696d6573000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714514824a3c36d4d80d22cf3de263e508136506b6e9b7b06bb8c7abb53a5a55f7772229273fe43a41f": "0x00000000000000000000000000000000000000000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047145151486ca217f604d23f678af47c89d76031edc91e43784bcf9991b131f957d312fced2c5187fb47": "0x0800000000020100000002000000000000000000000000000000000b5354414b4543524146540b5354414b4543524146541768747470733a2f2f7374616b6563726166742e636f6d15406e3174726f67336e3a6d61747269782e6f726717737570706f7274407374616b6563726166742e636f6d00000c407374616b656372616674000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714515c9ae1e485544e02b666dc3f8a627302f02c719cd1179cf2b762bfd23d97c79fcfa515283bc23e": "0x00000000000000000000000000000000000844205765657a7906446572656b000018646572656b6e65616c7765737440676d61696c2e636f6d00000a40645f7765657a7935000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714519b117a3f97578bf416788bc4684010deb2f452fad6136990e23fab94d7a6ea03a212d22dad1461": "0x00000000000000000000000000000000000e444f5453414d4120444547454e0253000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471451af1b7470f237d6dcb36abb644c739ee8ccf5b2ed810bf1bdc860a8082b43885c3c04db9befc011": "0x000000000000000000000000000000000010416e656b646f74652053747564696f00167777772e616e656b646f746573747564696f2e646b001a6e69636f6c616940616e656b646f746573747564696f2e646b00001040616e656b646f746573747564696f000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471451affb7adda940b6380329063444b0d709fe60a6bd0ee966c85ee1da8d62faf0bf33c58d8a15f93a": "0x000000000000000000000000000000000005546f6e690000001d746f6e692e696e66616e746563617361646f40676d61696c2e636f6d00000e40546f6e695f426974636f696e000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471451b32c5fc205cb3dc8d71df73e465b4a8872ab23bd7a7a6556ac05f3146f5b08f77e0b6ea437d051": "0x00000000000000000000000000000000000962656e6a617348750101010100000a4062656e6a61734875000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471451bca9b0989e2a50c096244f429cc3c9a56de9dfd07cb0dca6c15a42e701acac26d1ea108d8cb91e": "0x000000000000000000000000000000000009737578696e78697500000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471451c349b821056bc4dcf8dc909c5afd9755dd3c322b6f06b32dcfcc36755bb73e7ee5ae0722f4477e": "0x00000000000000000000000000000000001c54686520706c6179206f66206c6967687420616e6420636f6c6f721c54686520706c6179206f66206c6967687420616e6420636f6c6f7200000000000e403139353931566974616c6969000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471451db8a617be61c665e0a4ca74bbb4da39c79954e7875519fa67049795c02a360412f3ee41a020506": "0x0400000000020000000000000000000000000000000006416c6e74630000001d63687269737469616e6f7272656c6c38373840676d61696c2e636f6d000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471451eafd8385d1936b5812d714528fe379fe7ddc1381d3608149064486d4b95266072df8dba9539a22": "0x00000000000000000000000000000000001073735f70726f64756363696f6e657300000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471451ed17e92838fdaefe73b0dae6be10617b258eb5f9a3a6a8eb62ac48d8815c159149a267d616cf27": "0x00000000000000000000000000000000000101010101000001000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471451fe2259dc584cad041148d9102c91506d9e3e75297536084c9e3c3259ff78e4651ef4c464a04377": "0x04000000000200000000000000000000000000000000064e6f646c650000000000000e404e6f646c654e6574776f726b000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471452003ea86a3405e150a9915a75f39429595debcf987a1ce8aa34937de24d2356f31fab6192acd032": "0x0000000000000000000000000000000000053147616200000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714520f291562f43512506732d16ab06c1d33cae04a14f0aa43c2de8a3971d419c6db3fa03a6a047131": "0x00000000000000000000000000000000000962616c73616d69630000000000000c40307842616c73616d6963000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471452212743bf9486034a6b7fe6b1506b1a58b5e6e4b5635fdb17797ce19fc34786e3c1520c21bc024e": "0x040000000002000000000000000000000000000000000e446f6e6174656c6c6f204b534d00000017646f6e6174656c6c6f6c707a40676d61696c2e636f6d000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714524d4c9a4edf7068ae7469e454ccb99c9086f96135f5aa2b32b44652c9d739a2e4f80aadef463600": "0x00000000000000000000000000000000000b487970657263756265200dc3967a676520546f70c3a775177777772e68797065726375626573706163652e6f7267002068797065726375626570726f6a656374737061636540676d61696c2e636f6d00000d407a67653432323232393433000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714526acd0240c524a4b01af838437b50496eed9bc64de023cfbb1afdd633b0999537bdf0e5030f6e6c": "0x00000000000000000000000000000000000f504f432044454c45474154494f4e001e68747470733a2f2f7777772e70726f6f666f666368616f732e6170702f0021676f7665726e616e6365696e63656e746976697a657240676d61696c2e636f6d00000f40476f76506172745265774b534d000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714527b633bf5bcbf6fc8d5ea648c1881e3cc19179ce0aca0b0b13f9f8bbda137472a91864b93514667": "0x00000000000000000000000000000000000f4d757368726f6f6d20546f706961001a747769747465722e636f6d2f6d757368726f6f6d746f706961000000000f406d757368726f6f6d746f706961000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471452864ab8b7555a13f24cb6d3f22ce3f4f7a7d553f2d53defdc6cfb346115bc7c81fb34b2579a0c58": "0x000000000000000000000000000000000005686b6465000000136b756e693633323240676d61696c2e636f6d000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047145296f5f3e605a0e3e8b2603f6baee5bc32a9b9e4eee9168499fa553d35edb56aef0035ff7e1f165e": "0x040000000003000000000000000000000000000000000850617261646f78001568747470733a2f2f506172614e6f6465732e696f164070617261646f7878783a6d61747269782e6f72671470617261646f78787840676d61696c2e636f6d00000b40506172614e6f646573000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714529f9f0efcc4d1fef4a187600e4026679cd65074ea9a9bdf2e807d7df8160b1ffbbc8032c97b1c03": "0x040100000002000000000000000000000000000000000970756e6b726f636b0018687474703a2f2f696e666f2e70756e6b726f636b2e6d65154070756e6b726f636b3a6d61747269782e6f726715706f6c6b61646f744070756e6b726f636b2e6d65000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471452a0abbda8b43f37b8e21e9844672e363cb73cb15c0b5e8bab835962d2f60baeaa6035ed31245f48": "0x0000000000000000000000000000000000144b534d204d41494e20434f4e54524f4c4c455200000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471452ac2d872feb1e6aae19bf487c9effca2fe23d3601d330da0a0b82462f340b84ef49676810e58c44": "0x00000000000000000000000000000000001256616c656e74696e73204976616e6f767300000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471452c8ca65b329df6b02f87ce6d066323c92f56d284faaa856ce083f9ba81635464f04fabec453c822": "0x04000000000100902f50090000000000000000000000000000000000000000000000000000001fe298af4368616f7344414fe298af204e6f6d696e6174696f6e20506f6f6c094368616f7344414f00000000000a404368616f7344414f000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471452ef0ce1f0943599a092ee7d51b6ba1268db2c00f3037cd198fd31f14343bcdc966cb23d7ad90816": "0x040100000002000000000000000000000000000000000c3238446179734f66446f74001c68747470733a2f2f7777772e3238646179736f66646f742e636f6d001a6368616c6c656e6765403238646179736f66646f742e636f6d00000d403238646179736f66646f74000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471452f06c1cd27b99a6fe276fe53bf4d1a7589d977a91c8cc990d58ec79654f9560bdcf4e06ea7c2b39": "0x000000000000000000000000000000000006642e67656e0c64617665646f7473616d6100144064676e726174643a6d61747269782e6f7267000000094064676e72617464000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471452f7789aca5beb4f4eaba2222455fc5cddf28b131f3f6317f2c22de7976eecf12ad8d3865d453418": "0x04000000000200000000000000000000000000000000074e585858494f00000000000008404e585858494f000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047145311d7c5ed4d76a10e82ed0d7d2e0f86a12c9f4276c1da60ac75cbba94789514736664d15514fd5b": "0x00000000000000000000000000000000000f42616462756e6e696573204e4654000000186e667462616462756e6e69657340676d61696c2e636f6d00000a404169746f725f6c7a000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047145322d4c9d96b74a14a07b12f3c8a1cbf139a46d05f52acae666ffe15f97e2e19d6def5831d101166": "0x0000000000000000000000000000000000093342616b5f6172740e4572696320547265736261636b1a7777772e6c796e6b666972652e636f6d2f3362616b5f61727400133362616b2e61727440676d61696c2e636f6d00000a403362616b5f617274000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047145326dd1bd53284ff3c2dd5a18ca096521bdf0adfd35e358ba6b89ce8931c87144f80998c5f6a0a48": "0x040000000002000000000000000000000000000000000a43414e445953484f5000000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471453274014bd0b9f664274f5c7b6be61ea3dcce96b80af40f4ff7b53e46c598986411fdfae942a7955": "0x00000000000000000000000000000000000d4372656174697665204c616208526f626572742000000000000e40437265617469763936393634000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714533d19de9dfcc61206d1b911e582c3c8c372135076ef9570fa2a48ef4ce5a71d53d9e1dbc9e70e2d": "0x000000000000000000000000000000000009736d6f6c6265616e000d6d6f6f6e6265616e732e696f0013736d6f6c73406d6f6f6e6265616e732e696f00000c40736d6f6d656c65747465000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714533d284f329fd8fc9e13e5a0517ed028b4f44c593efb7caa0f82ddb90e95b8cc1c68122d0b03c319": "0x00000000000000000000000000000000000a417274206f6620424d00000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714535df4fc4871fff79c0495d70ded39e5fe05f1d41b05db162a52cbfd4441ebf81a50132070ad1d09": "0x000000000000000000000000000000000000002168747470733a2f2f706f6c6b6176657273652e636f6d2f6163636f756e74732f0000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047145361b1ae059eb11e0650a2e41ea97b60bbd3f87aa30d605562069075deaaf79559959230928a2487": "0x04000000000200000000000000000000000000000000124d722048617276657920537461636b657200001a40686172766579737461636b65723a6d61747269782e6f726718737461636b657268617276657940676d61696c2e636f6d000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471453798c7023fb40ea3629a3ff4589c42f2239861dc182184b176845a6bc350b9d72aa592a8d113e25": "0x00000000000000000000000000000000000b524d524b2050756e6b73001768747470733a2f2f63616e6172796e6573742e696f2f001652656d61726b50756e6b7340676d61696c2e636f6d00000d4052656d61726b50756e6b73000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471453860ac0c7c038f0f84edf06c02ea2f2216867fbd39f86329f2558741c17f78643d052bb8eb83008": "0x00000000000000000000000000000000000a4b757361746f706961000000146b757361746f70696140676d61696c2e636f6d00000b404b757361746f706961000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714538812c43fb3e37faa55a7d8768b4fac73f8c942e3639d378464730219023c5df0d4b2634b7db07c": "0x00000000000000000000000000000000000b56672042756c6c69736801010101000001000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471453b266b24dcdb964c81deb9f19b615125e4e4f316d5ffdcf2e24eb250126a1a4e60b3ac1eb0a2f6f": "0x040100000002000000000000000000000000000000000e57454233445241474f4e434f4d001768747470733a2f2f77656233647261676f6e2e636f6d001561646d696e4077656233647261676f6e2e636f6d000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471453c8b0719674d5ad2ac4ff01309437984822f0b78beb305aa015cb11b01b993468b64a744216cc1c": "0x00000000000000000000000000000000000553756d6900000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471453db9f22b39bbf09f8d7db5169156459bbdee84a522da4bc2110027b602154ca5b363abfff5e527e": "0x00000000000000000000000000000000000f4b7573616d612047686f6f73747a0000000000000f404b7573616d6147686f6f73747a000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471453e4f85431a5b93d464a24ea583d3b746841db2aa9af933ff6c1239ed2fc83d1aa424bcfbbd66b1e": "0x0000000000000000000000000000000000095342486f646c65720553616964000019736169645f626f737331303040686f746d61696c2e636f6d00000a405362686f646c6572000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471453efe4a2559eb48e920b814b0381e982418dcc9a71ff4248b63308d015b77acb31977ee72543de0e": "0x000000000000000000000000000000000009426f6b726f6e697300000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471453f12a00f2f2c920388038a2455e863b7a51a8c6c2015c3c1001583db6c1068f0362eb73c6f9f804": "0x040000000002000000000000000000000000000000000f4b5553414d412047656e657269630000184073656e7469656e747275653a6d61747269782e6f7267116a6f7365407261626173736f2e6e6574000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471453fdbf79c2885f07749f37b4b1d74040e735d5d6d683415de3c084e069409d863a7ff876c307a031": "0x00000000000000000000000000000000000000000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047145400dfd4fa6501fb4ee051c50b5c51b147d939e25ce61aa7e05af10ced2ed62ce7051509009ddf54": "0x00000000000000000000000000000000000d506f70707970697820417274001668747470733a2f2f706f7070797069782e6172742f0015636f6e7461637440706f7070797069782e61727400000b40706f70707970697831000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471454265aa0109191e386863b1e54bacf60ffc0a50e063b1bea72f2b1b1e9334173777e045f4c2ad618": "0x00000000000000000000000000000000000d4d61726174646a616c696c69064d617261740000176d61726174646a616c696c694079616e6465782e727500000e406d61726174646a616c696c69000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714542d07047e260805305a014d7c8a0804316d2b4eb9e2e3cd6c1a021d60f1c6402c3c3103f2abf20a": "0x00000000000000000000000000000000000c5452554d5059204e46545300000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047145439cf6aa71671f74608fc7527698d3f4d4cfcc6074f01c2ed59112ad670dd5206b3658bbb62a073": "0x040000000002000000000000000000000000000000000b6f70656e6269746c6162000018406f70656e6269746c61625f3a6d61747269782e6f72671c6461766964652e6f70656e6269746c616240676d61696c2e636f6d00000c404f70656e4269744c6162000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047145460e0b925bf21dedef46db9b4a4808a39f261919782eb5530a835a5454e31ad95e1ead1bb67076d": "0x00000000000000000000000000000000000542544e5101010101000001000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047145486e9127d5c6ea83e6cdd1a5f9be051d4f9bde07d864b9a2d963d3ea06efd1ea6ce3ec73280f34d": "0x0401000000020000000000000000000000000000000008556e69636f726e0000000000000d407472696e69747931363132000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714549a808861f1a51754a244c98779e1b91c46999aa8713fc01b8fc589002d302fe54e264247228705": "0x0000000000000000000000000000000000075368657272790e536865727279204e677579656e010101000011405368657272794e3039353033353131000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471454a75c3f1924b5a8f4eba0e62e3993df8992425026148f7f818a9140343439eda6de9b85cf80d74c": "0x00000000000000000000000000000000000946656c6972616d69000d66656c6972616d692e636f6d000000000a4046656c6972616d69000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471454bcedbc59ca5b64fa3c3e2de0340ce354980a87c50a75447114c521bbf11d3366528e0e5507bc36": "0x0000000000000000000000000000000000074bc3b2c3b36200000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471454d7e633409fc98ca61cffec64bd3d89d7195fd423998178d8a4e6a0593ea5ced602f43d2e5ca346": "0x000000000000000000000000000000000009437361696e74303200000014637361696e746e303240676d61696c2e636f6d00000a40637361696e743032000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471454e846fe38b60f59dccf45d8f5333a3cda7b160d6f930e1e3a97a84b752365745bb0f133af36027b": "0x000000000000000000000000000000000008574368656573650000000000000f40576973636f6e736f6e62726564000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471454ec0e7f694e04f5fcf0c2ab943cebb940962bfb3cf3c29b9f3031ffe3257dfb57c87865e1c3817d": "0x00000000000000000000000000000000000101010101000001000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714550a7f6530adfd1672f1cd51a567fdf672b0f622cac26b6b4b2b777f062d72b1278cd30f1f909a0b": "0x0401000000060000000000000000000000000000000014636f6c6c65637469766576616c7565732e696f001b687474703a2f2f636f6c6c65637469766576616c7565732e696f0019696e666f40636f6c6c65637469766576616c7565732e696f00001140436f6c6c65637469766556414c696f000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714550eb3eebb9a802e905a70f40069da23d88524866c0386eac29894ed423cf9f5c2715a375694c82c": "0x00000000000000000000000000000000000442424600000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714554194451846f3f4140ba7452170aa67c1de4d8315d861cedbbd398ed74664d3c78397b0e10dea23": "0x000000000000000000000000000000000018546865204b696c7465642041706520416c6c69616e63650000000000000b404b696c746564417065000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047145548f72303df99a6dc926438eb65dfa069c73774ffafcba13d1519c0132d14a8537323feb356467e": "0x040000000002000000000000000000000000000000000d4e6963636f6c6f2047616c740000000000000d404e6963636f6c6f47616c74000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714554d8e14cb2e6c614c909beaee469132767ebae5cc49961b19237150c0e983b4ae7ac64f23d83519": "0x040000000002000000000000000000000000000000000b626c6f636b7a696c6c6100001c40626c6f636b7a696c6c612e7465616d3a6d61747269782e6f72671a626c6f636b7a696c6c612e7465616d40676d61696c2e636f6d000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471455538dd590c80f13507c2d0784ffc68240a395784f16cd29f99f974a58876fa9e948fe4ffcb70334": "0x04000000000100902f50090000000000000000000000000000000000000000000000000000001d4c75636b792046726964617920476f7665726e616e636520f09f8d80000000147279616e406c75636b796672696461792e696f000011404c75636b794672696461794c616273000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471455596bc6a00ad8cb92d11958f5d22465a5c44d5c4411437e57ca8bc73b0d61e332a6c4f698381d7a": "0x00000000000000000000000000000000000b53776973735374616b6500000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714556c80301dcc6c9cb22a4babf3715c5f87721f51b3c81da94e30982ff1208676559eb41cfee4a96f": "0x00000000000000000000000000000000002143726561746976656d616b65722020284461766964204172616b656c79616e29104461766964204172616b656c79616e00001d64617669642e6172616b656c79616e37373740676d61696c2e636f6d00000a40645f6172616b656c000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047145579d397caf9629d608aa0febae80d8c228709183cf997bc87b0aa219cda0928408df22ac7ffef39": "0x00000000000000000000000000000000000b4441524b464f5245535400000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471455968c29c82cacff564ee20cf557d9908995750ee210fb123037816ada2d4a702bb54068100a8767": "0x00000000000000000000000000000000000000000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471455b22415a61f9221bcf7fa68ff79818686ee0a26bcff740a8b3c2930251fd15a49c6ccc64faa7508": "0x040400000002000000000000000000000000000000000948616e205a68616f0000124068616e7a683a6d61747269782e6f7267157a68616f68616e406c6974656e7472792e636f6d00000b4048616e5f5a68616f5f000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471455c8a048a9a0dce1d6ae958d7ee48f421e3e5c4adf7448c8ca260e9deb824e62ef108e7e25758d78": "0x00000000000000000000000000000000000c4c75636b7920426972647301010101000001000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471455f668eb0e022b6af4f8d7504c181954de142fa5dc2dd3d7e79ce9b4f19b89cce879eb7f60bb5721": "0x0000000000000000000000000000000000055a69676100167777772e6d69636861656c7a6967612e636f6d2f7a0000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714560e4606f61ab63ebe1f786c654c20757527b840d1d4a4ea6fc3b355d5791110ab8f8f0724b9404f": "0x0000000000000000000000000000000000114c69736120576c6164696d69726f7761114c69736120576c6164696d69726f776100001a6c697a612e766c6164696d69726f766131406d61696c2e7275000011404c697361576c6164696d69726f7761000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714562122059d1dbce57ca460cc927a04fbc91f4ddda54149556d1a85196bc753d054aca1fb7621e349": "0x04040000000200000000000000000000000000000000055649585900000017736175726162686772696e6440676d61696c2e636f6d000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047145629138aa7fc2439fc079f0aaf5e36f2d2ad13f54b81924eb303eb0b47e3af372ded43049bc64910": "0x000000000000000000000000000000000008437572696f757300000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471456437782aa58550c3801e22f05e304a3fff7124b7e1830b112e3466db9d8fb6cf1e8e9e79051662c": "0x04010000000200000000000000000000000000000000144c616d626f6d6f6f6e204d6574617665727365144c616d626f6d6f6f6e204d65746176657273651668747470733a2f2f6c616d626f6d6f6f6e2e78797a011779756475732e76616c6c657940676d61696c2e636f6d000011406c616d626f6d6f6f6e5f7665727365000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047145667d4d8a497c0945a2b916f6525c0639e089c5b221b61ff495cccbb4fb82fd4dbd6034a8ec4c008": "0x0405000000020000000000000000000000000000000009506172616d6269720f506172616d6269722053696e6768000019706172616d62697240706f6c6b617373656d626c792e696f00000c506172616d6269725f3137000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714567dc72806fd2ef9d453b6e497b6a89979fb34eea715720d37c2381c8c51458be04296fd059dcc3a": "0x04000000000200000000000000000000000000000000044a4a4200000000000008404a4263727970000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471456842ac04118f270ecbab750f5f7563a45e30f4b4ce064248400b90c5f8d06158944dc94bc6d5236": "0x00000000000000000000000000000000000000000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047145687eed0089938017caa8fe3fab162b7508198c9ad5b37c7af8b02cb70ac48da4a5f98c505c7155d": "0x00000000000000000000000000000000001052616b73686173612053747564696f0000001972616b736861736173747564696f40676d61696c2e636f6d0000104052616b736861736153747564696f000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471456a1c5009025aa2bb6c090fcf1675617fdd8ced70d7567c5dc707782d10d9570430ef02194c75067": "0x0000000000000000000000000000000000154c6f6b6f20506f6c6b61646f742077616c6c65740e4d696775656c20426f7267657300001b6d696775656c626f726765733739313340676d61696c2e636f6d000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471456b436eb439d2e4862586fe7c5d0173262986d66edceb58dfa24f4ba4f35aed0f37228ee9ffa4f00": "0x000000000000000000000000000000000005416c657800000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471456cebd3283e0ea933a3884dbc6806e8b4cccbf2c407d800c12141c3d7cacde442a649a6a2822ac17": "0x040000000002000000000000000000000000000000000c53454b4f5941204c41425300000013746f6d4073656b6f79616c6162732e636f6d000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471456d57c08aef106735ecb86012e4c9df3676d3ba24512ff0c5b3509a4282b4290f095da42de17eb56": "0x0000000000000000000000000000000000064261626172064261626172000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471456ec9fbeed402237beb4f57329d674153ba91c3d1a21f744e48d79e8879f1213bc2099a3eb241429": "0x000000000000000000000000000000000009524742416e6b7379001d68747470733a2f2f6269742e6c792f524742416e6b73795370616365000000000a40416e6b7379524742000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471456fcf1e5447565198ac9fad47064fa58342aea6727b9e45076283c71a6447534c444f163eb426813": "0x00000000000000000000000000000000000c50616e6f707469637573200000000000000d4070616e6f70746963757376000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471456ff64b33828b8d02a3a79d6cb82c0f1fff14cbb78d3b7fa64b5a9a3fd9c54fd4e78a5cbfbade710": "0x00000000000000000000000000000000000648616e697300000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714570905ee38b668978c7da506845d451b9510e7ac2e7d30c36e72a5f39e05d427f9e79719724a5a3e": "0x0000000000000000000000000000000000115468652042756c6c697368204f776c7301010101000001000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471457130fa04591b33060283de9f5beb93ac69b24ca8c62f60f39b8c80758d807aa244532c66b67bc3c": "0x040000000002000000000000000000000000000000002153616e746961676f5f47757a6d616e28656c63726970746f7061726365726f290000001d6469726563746f724063726970746f6c6174696e666573742e636f6d00001140656c63726970746f7061726365726f000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047145721ebba28d18ffd9c84f75e0b1b92f6b003bde6212a8b2c9b776f3720f942b33fed8709f103a268": "0x0400000000020000000000000000000000000000000006616e6472650d416e6472c3a92053696c7661001140616e6472653a7061726974792e696f000000000b616e64726573696c76610000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471457303e92e8fb25ab9a83298c34e9c1f3f325afee086ab423e88645861ad8c9e380e4bc3ef7046e07": "0x0400000000020000000000000000000000000000000006526567686f00001340726567686f5f3a6d61747269782e6f726710726567686f4079616e6465782e7275000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714574f6106315eb5517418571179b97e88a57328ecffa64c08abd0dfb5ff50be36e00582e56c5b8955": "0x00000000000000000000000000000000000c706f6c6b61646f74626f6900000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047145771ae952ce319e894390dfcf349f8a5e73597a2e96ce1344cf8272e990489a08c24ac30d9027953": "0x0000000000000000000000000000000000074b757261726106446172696100000000000b406b75726172614e4654000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471457845cd05536c32e9c6ba1325d8dc7cec809ce61640c9ed92d18f0d818a4c102c2c0ea4f29820136": "0x000000000000000000000000000000000004546f6d09546f6d20686f6c64000017636f64656861636b3737373740676d61696c2e636f6d000009404b534d50554e4b000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047145786fc402111e82d5202845d849d9eb6a7e5a414492a86d205be4a374ede34e98fc2440de4809a3e": "0x040000000002000000000000000000000000000000000c556e6f205374616b696e6700001740756e6f7374616b696e673a6d61747269782e6f7267186f70657261746f7240756e6f7374616b696e672e636f6d00000c40556e6f5374616b696e67000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471457903c6184bae82f5a090c88f0438b46b451026597cee760a7bac9d396c9c7b529b68fb78aec5f43": "0x00000000000000000000000000000000000d5365756e204c616e6c6567650000000000000d407365756e6c616e6c656765000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471457a1aae68bb3807a7ae8740550b3d4de49d50fb4e83354786a6ffc5c166d7b876c31baae7388ea51": "0x04000000000200000000000000000000000000000000054d414473000015406e6f626c656d616e3a6d61747269782e6f726715676f6d6164736e6f646540676d61696c2e636f6d00000f4053657267654e4d617263656c31000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471457a5cae663c515ca00ecaacb451648a3660fe122ccc2c32cfd9459ca6dac9f10cbf7a0ab60c61318": "0x040000000002000000000000000000000000000000000d4a414d4553204147454e4441000019406a616d65735f6167656e64613a6d61747269782e6f7267176a616d657340686f6c64706f6c6b61646f742e636f6d00000e406a616d65735f6167656e6461000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471457a97c250c6d982f788f24f65de10ed710c10f5daf367e9ca57d8a998cf6bd13d7cdaf6937e16d68": "0x04010000000200000000000000000000000000000000184c696768746d616765204b534d2076616c696461746f720c53616d20456e672053756e00001473616d65733230323040676d61696c2e636f6d000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471457b1a86eeaa2582dda1a090ac84e6183dc9e7e3369cbab0ca51afcc7133b1324634093753a483e11": "0x00000000000000000000000000000000000f52757368696e672053747564696f0f52757368696e672053747564696f1a6d656469756d2e636f6d2f4072757368696e6773747564696f001872757368696e6773747564696f40676d61696c2e636f6d00000f4052757368696e6753747564696f000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471457b1fed518565181aaa635f88e75ad58af28925d0c21a804d87a449469e45970c3a52f57aba7b366": "0x0404000000020000000000000000000000000000000008486f646c6f6e690000001874656d70696568616573736c7940676d61696c2e636f6d000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471457c41eaef46fdefb2ca8e96b721f074e95a3f7d994c370dab688fc85134de7e2e7d4589d0a306c51": "0x040000000002000000000000000000000000000000000842696754756e610000144074756e616269673a6d61747269782e6f72671574756e6162696776616c40676d61696c2e636f6d000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471457ce53ed6bf695bad6266aeeea11e5bcbf8d5a1b7255a363aa2635083e0e0aee6ab434fdc3f1b511": "0x00000000000000000000000000000000000848414d5a4941530e48414d5a4920412053414b455200001a68616d7a69616264616c6c6168393640676d61696c2e636f6d000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471457e0f36f0fe2bdee54efb33a98824d6330a8f074481df98b5123305473559bef960180791f849252": "0x0400000000020000000000000000000000000000000008426572657a6b610000154074696b74616b33343a6d61747269782e6f726715696b617a616b6f766e6e40676d61696c2e636f6d00000f4063726970746f637468756c6875000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471457ef873d5dca9de5ac09149a298fb86b4ecb5c648a2d37e8dbd6da2ad3f265179eb5daa903c3f73f": "0x0000000000000000000000000000000000046b736d00000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471457f4780677cf709b4ec0381e4427ed6567f7a5c328288ced36c33becea6ececd8145001f4230ac1b": "0x04020000000300000000000000000000000000000000185869616f207c20e586b0e993bee7a791e68a802d4742430f44722e205869616f205a68616e670f7777772e676263746563682e636e1340787a68616e673a6d61747269782e6f7267127a68616e677840676263746563682e636e000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047145805cd76b5154e33e6b0690ac14357ff8a2228b2dca5e221badf5d252d94ab08dbcefb2004d5214e": "0x00000000000000000000000000000000000000000013736f6b6f6e66747340676d61696c2e636f6d000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714580dd48e484c5f2972a45f5688398a40b4bebab307d097de95cda8220d74e053fa0b7b77f0c36e14": "0x00000000000000000000000000000000000d5761746172754b6f73616b6100000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471458138ec91336832cb4dd8fc49aa15538543007347b1df3f4bf948ed60474105c19819a311fdced43": "0x00000000000000000000000000000000000c416e61726368792041706500000016616e61726368796170657340676d61696c2e636f6d00000d40416e617263687941706573000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047145839ea98689b2889bc6e12d7ab70abea4c08db7055e84f16bab817b5fb359088ad5190422df9dd1d": "0x040000000002000000000000000000000000000000000e416c657850726f6d6f5465616d00001340616c65782d6d3a6d61747269782e6f72670000001040416c65785f50726f6d6f5465616d000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714584010d60675c6289a8cba76944a9dd66c20b150c5821f2b6c3fb5c7896b9a3e889d574f48d3d50c": "0x0402000000020000000000000000000000000000000011494f53472056616c696461746f72203211494f53472056616c696461746f7220321068747470733a2f2f696f73672e766311406a6f63793a6d61747269782e6f72670e68656c6c6f40696f73672e766300000840494f53475643000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047145853e7deee1e01320c3e1db6b821c4e5dd8d3199aee048377eeb692392743d43e7196d4f8d52e212": "0x040100000002000000000000000000000000000000001344455720436f6d6d616e642043656e746572001a68747470733a2f2f7777772e6465772d7374616b652e636f6d1440646577706f6f6c3a6d61747269782e6f726716646577706f6f6c406d61696c66656e63652e636f6d000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471458554ac760f837f7d8f7fd9ee2b808717305d4bbc06e1ed5aa519e75c398f6dad27e1c1c026c593c": "0x00000000000000000000000000000000000b45736b696d6f204a6f6500000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714585c0f93d15e98cb42f3c525c66f2a4eacfa88479f7537670d2e1f45f4ec25703a111f5f003ba15d": "0x04000000000200000000000000000000000000000000145374616b696e67204c616e64207c20457269630000001265636f7637373340676d61696c2e636f6d000009406572636f373733000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714585dc428f7abc0d304b28d3651a60f46affd3f6b3b5631bf8e1181a53911bc83872183ed80f92641": "0x0000000000000000000000000000000000033838000000113932343131373533384071712e636f6d000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047145879c1214022b88dc8566f6d3669729e877cd5e453d59f6be01ae6f31b7a9c9925160e70072f7242": "0x04000000000200000000000000000000000000000000084d555348494b410000134062726f776b613a6d61747269782e6f72671069726f6e406875626361702e70726f000000000a49726f6e233933323600", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714587c6bbae1bb420cf2d0eed0f21b82d4b15802153cde2a229f257f01d003694b2973ef785a734766": "0x040100000002000000000000000000000000000000000a416e6f6e7374616b65001668747470733a2f2f616e6f6e7374616b652e636f6d0016737570706f727440616e6f6e7374616b652e636f6d00000b40616e6f6e7374616b65000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714587c6d66c4c89f37ce8bb3daa399b23c4c37885a945461ca1e15579969152bd06ad91aa42a901c45": "0x0000000000000000000000000000000000095261626269747373000000186461696c79726162626974737340676d61696c2e636f6d00000f404461696c797261626269747373000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471458929df6c9d6b10576a95bd9907b8b23244d8d127f6218e662a8098b03338c02b70926cff7215812": "0x00000000000000000000000000000000000849736c616e6473054c696e6100001749736c616e64732e726d726b4079616e6465782e727500000b404c6567696f6e383837000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047145894bbb4b58b7f2a267bb3686448c8f8e75390a649826f7b524f9a9768817678333e405f03b2330e": "0x0000000000000000000000000000000000036b790273010101000001000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471458b1d929f632e2bf305941b16193089ecff9efaea02756aa01cca8a54406d6cdc44f7d4b3ec7fd37": "0x00000000000000000000000000000000001d4c696e646f204a6f736f6e202850656163685f6e5f506561726c732900000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471458b50dea3d326a26e61e809e1d333966b27b8a6ad71850881f0a7f534caeff85ddf6c9cec0b3763b": "0x00000000000000000000000000000000000e50756e6b205661756c7420233500000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471458d6ba7bdbadef08f05f73ff22478af897ca6ff58c5152c641fe41bfbb168ec437b1e699c18ced5d": "0x040400000002000000000000000000000000000000000b5169756861692047756f000013407169756861693a6d61747269782e6f7267157169756861692e67756f40676d61696c2e636f6d00000b4047756f516975686169000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471458d8557741d41ae44e4ac8070fea95496b63cdcb6987de88f63dc75a295eace6ce5079149169300c": "0x04000000000200000000000000000000000000000000044b594200001a406b6f73747961796573696b6f763a6d61747269782e6f7267196b6f737479616573696b6f76393040676d61696c2e636f6d00000a404b596573696b6f76000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471458dec35f4d8ac0dd708b394ff79e4dcdd95357d1f6f5eb4db7314ea5bddad55e9b1507e58059cc3f": "0x00000000000000000000000000000000000c53565941544f534c4156310c53767961746f736c61764e0000177a6164616a616e697930317940676d61696c2e636f6d00000d404d5370656b756c79616e74000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471458f0e1d56d9c06ae72cf375dbf960070e09942d1eb553973beac2e3d410a30a87e1271c53d1c4b13": "0x0000000000000000000000000000000000084b6f646569737400000000000009406b6f6465697374000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471458f78aab94d3b05202ecd7386aa07e755cb458b790699dbcf09458279ec393f5384ff7729da38d10": "0x00000000000000000000000000000000000000000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714590171a64e0cbc98e6482c69539ce311c0cd1b067d98be8f177fcd9620f938a48f3e61353bbd0367": "0x00000000000000000000000000000000000000000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714591121c7e29722e2043fef4609e750d25d21d9fac3f3144e2cacf1f758e70dc4a23dc848e140850f": "0x00000000000000000000000000000000000943656b697264656b000000000000104063656b697264656b5f6d65647961000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714591a0dfab85943a49e28e10189b8bdd0e4980086b6c36728d840932128ea4bce3db2f26032c15114": "0x0000000000000000000000000000000000074a787264786e074a6f7264616e00000000000a406269746d656d6578000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471459212f1c3da6903f24172a563943291c97d252def71e17abf467a1626bca358728a90a82b3de3118": "0x040100000002000000000000000000000000000000000e5a4b43484e2e52594142494e41001368747470733a2f2f72796162696e612e696f12407a6b63686e3a6d61747269782e6f72670d7a4072796162696e612e696f000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471459368261611b8625ee3f7f4c2dbe3c27e5e524c226ef9e65b827498e0f53b5c3592d4b6b884e6d55": "0x0400000000020000000000000000000000000000000004707467000000137465616d7079617440676d61696c2e636f6d000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714593a90e3bf5c060f765a97770360b61055ecfbe9f3790d29fe8dcac870716c5464cd4ce27c3f4744": "0x0000000000000000000000000000000000084472616e6b73790f4472616e6b73792041727469737400000000000f404472616e6b7379417274697374000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714593b2319048c7897fc6b29e92d65b645a56a0d44e3f4879eb82f3c5b50341cfa61aad9edeb7cbe0e": "0x000000000000000000000000000000000003656600000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047145943caacae6ad2f25aae17b541f38373368901648429badf112a0dcefd9a8976dc5b8d6acebf7425": "0x04050000000200000000000000000000000000000000096a616b6b796f6e650661726d656e0000136a616b6b796f6e6540676d61696c2e636f6d0000104043727970746f61726b657469706f000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047145964965cb7d831cc9e819e2426df687c803ee2abc546c68bb0267ea7652029e7e242ac75a83ded24": "0x00000000000000000000000000000000000944616d69656e4d6b00137777772e617263686976657273652e6172740016736175636564616d69656e40676d61696c2e636f6d00000e4044616d69656e5f5361756365000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714597947638d09aa7a7a5b71ff1acdfd938cac1b6b115ca5479c392d1fa5d9d78c1770f0042a9db811": "0x000000000000000000000000000000000013506170696a656d20706170696b697263686508426f7961726b6100000000000d40506c6179657248656c6c61000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714597991a0ac94c2410af5599c203182b0859805283944d9a8df0d788a52a37423ef002cc5889f5764": "0x00000000000000000000000000000000000c6d757461626f726174756d104665646f72204e696b69666f726f760000126665643232323240676d61696c2e636f6d000011406e696b69666f726f765f6665646f72000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714597a2e1f5ab12e08025741e5e3fa614b7a17855d223f48d4ac98bdaf45c11e67963cd0b4fbe0081f": "0x04000000000200000000000000000000000000000000104261657a61204b534d2053746173680000001373676261657a613140676d61696c2e636f6d0000114053656261737469616e474261657a61000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714599ea05228cbabc6429a9eb3c6a1f14b291fbd2c10ae3b6dc3fd95fab0ab0072122a90c2f6529057": "0x00000000000000000000000000000000000f5461626f6f2047616c6c6572792011436f6e74616374203420636f6c6c616201010100000d4079616d696e617274697374000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471459a857c5ae03b5a7ece6a4bff0a206e9739e9f05b36e23cafe0e59d2c5fc1adf3d00069160ec6319": "0x00000000000000000000000000000000000b4a6176696572204e46540000000000000b404a61766965724e4654000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471459c0a69a8bc9cd0c3e89f6d3fe88c432363723082d6d6cc6e5b3c09a1b4087dd409bf8804b1f7d57": "0x000000000000000000000000000000000010506172616c6c656c2063757a64616e00000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471459d3ac6be2fd0312ce6ac62a23361838caf62d10c11a08b4ef6048cd2d8819abbe0399f2da40da68": "0x00000000000000000000000000000000000e43727970746f4f7665725553440000000000000f4043727970746f4f766572555344000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471459fb49563ab8f0448629b0221568837ac8c93a4534c77b40e4f07dc7dca8e7ab9062914c6d5cd64e": "0x0000000000000000000000000000000000204b494c542043524f57444c4f414e2046554e44494e47204b52414b454e204900000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047145a20e5cb7fcd59317e4d3937a8778981c0365ad2faff4ca846c9d910ec1196e66f9fa0ae5a469c2f": "0x000000000000000000000000000000000006354e344b3300000000000008406a6f63323430000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047145a322d41358015c5820e859e96c107c3dc5e0b110d8e5a7fd2bf312b511b00a5a45e59eeec47d741": "0x000000000000000000000000000000000009436872697342434b0000000000000a4042636b4368726973000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047145a53642bcce8d5192055808c210d863dfc372ec85beafa8fd3a8ff497f8eaee401ef05bf27d3065b": "0x00000000000000000000000000000000001f4a696d6d7954756465736b69202d204b7573616d61205265736964656e740000001b6a696d6d7974756465736b69407374616b656e6f64652e64657600000f407374616b656e6f64655f646576000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047145a5afe08a0a9de9ed6aadb9a7f66a45224f6f83011f854c0b5758c626b213f97cbffded94830507d": "0x000000000000000000000000000000000005f09f909c00000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047145a5f25d1ebffdf66facdca5effe8072173c4c12f7bce4d0e693e5feb83f7926bf1a8c7ffd1caf14a": "0x000000000000000000000000000000000008536576616b3438000000144374696c657236303640676d61696c2e636f6d000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047145a69592e77fa7ad2d8dd47918c70f35b60c098e90f3ddb7aaab24082cb7043be071bf323f10b3928": "0x000000000000000000000000000000000007454e31474d30000000196672656e6b656e737465696e373740676d61696c2e636f6d000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047145a6c990eb5706de2f6d5d7a1f11d32d33bff1d878db5eff7462b104818a869e89f47034210c88812": "0x040000000002000000000000000000000000000000000763727968656c0000134063727968656c3a6d61747269782e6f72671163727968656c40736b6966662e636f6d00000f4063727970746f68656c656e6b61000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047145a84a36862a690700210f894089a5fd3e91bcc8f6848717c556f002438cd902c40af4d031e9d5e21": "0x040100000002000000000000000000000000000000000c46656e6e656c204c6162731046656e6e656c204c616273204c4c431768747470733a2f2f66656e6e656c6c6162732e636f6d1b40726f6d756c757331303a66656e6e656c2e656d732e686f737414696e666f4066656e6e656c6c6162732e636f6d00000c4046656e6e656c4c616273000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047145a8a8fc110b069894a0ac27d662bb3987c4f0568f1d048d57dc25a1479fdee48cae7b7cf6eaa8d42": "0x0000000000000000000000000000000000084472617468696e0000000000000e40616c696d617277616e693130000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047145a8e89c3cf824328d0962c02edc80c0e947917fbb8b18e5811c1f3be76938130208f71aa07f0f909": "0x000000000000000000000000000000000011436f6c6f7265642050617261646973650854617469616e6100001374616e7961626f796172406d61696c2e7275000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047145a8ebd7db5efcab1de575b9b9da6c9296693e2c37ac5f38c1d84f64a7749a5c59edd1951fb5dff12": "0x00000000000000000000000000000000000654455452410000000000000c4074657472615f636c7562000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047145a951ea190277ac2de78f9ebf672082a2ed1e9d5b00430dbf6d0284fe3bbc4176f140e934d3b3b2d": "0x00000000000000000000000000000000000942657253746576651053746570616e204265726c697a6f76166c796e6b666972652e636f6d2f6265727374657665154062657273746576653a6d61747269782e6f7267156265617273746576656b40676d61696c2e636f6d000010404265726c697a6f7653746570616e000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047145a95852911b4bab1a41f73a80d77cb1ca2a8ced7f20a74c1677edb562b37e8a16310b89187cef94e": "0x00000000000000000000000000000000000853747573616d610b53747520426973686f700000177374752e702e626973686f7040676d61696c2e636f6d00000c40737475626973686f7033000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047145aa8315fde207d41183982ce80e4b52f2e80aaf36d18b1eba1a32005ffbefd952962227f2f4db309": "0x00000000000000000000000000000000000f477561726469616e7320f09faaac00000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047145ab174fa9e055d169cfe0b920dc749dada372dd02f2b5d60cbf9081a05ed65c7df35e4e47c593c01": "0x040000000002000000000000000000000000000000000a4b7573207374616b65000016406e696b735f67656e6e3a6d61747269782e6f7267157472656964636f6e323140676d61696c2e636f6d000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047145ac78869847a814046d41e304d6e7344c6509ee4cd56eb032090b86436ae5fca4ea3a357018a0659": "0x00000000000000000000000000000000000000000016736572676f35363534353640676d61696c2e636f6d00000a405365726730373136000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047145acf1d24617d25ba6a88b4d1ab30ab4708521d6c6d480a858d92692c0b0cff67e1a6904e23b84112": "0x040000000002000000000000000000000000000000000a68617070796d65616c0000164068617070796d65616c3a6d61747269782e6f7267146d617276657238333340676d61696c2e636f6d00000d4068617070796d65616c6368000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047145ae21247553af3c4f683b2e8b27985776e127615b3dd6362db1d252d4136112efb7451838cc62e4a": "0x000000000000000000000000000000000012426f68656d69612047616c6c65726965730d426f68656d69612046616972147777772e626f68656d69612e67616c6c6572790015426f68656d696144414f40676d61696c2e636f6d00000c40426f68656d696146616d000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047145ae3d02694d32b74b4154f12cdef88338edfa85cbdd64b61c410187e4f7971057aef32cdafdfb702": "0x0400000000020000000000000000000000000000000016f09f9bb8205a6f6f70657220436f727020f09f9bb8001868747470733a2f2f636f72702e7a6f6f7065722e6f726717406a6f686e756f70696e693a6d61747269782e6f726710636f7270407a6f6f7065722e6f726700000c407a6f6f706572636f7270000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047145af116176166f3dcdc891490870515c71014938641e9b09cfbfadeb502b16d67d2cff9145aaa9a75": "0x0405000000020000000000000000000000000000000009426c6f636b41544c09426c6f636b41544c1a68747470733a2f2f7777772e626c6f636b61746c2e636f6d2f0015636f6e7461637440626c6f636b61746c2e636f6d00000b40426c6f636b5f41544c000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047145af3c641a81d6a63eaacc14e67deba7935dc28c86bb8b6bdb64239065b718fed6b8691ce14163350": "0x040000000002000000000000000000000000000000000853494c49434f4e000018406b6f6e74692e6b6f6e74693a6d61747269782e6f72671b6b6f6e74692e6c696b652e6b6f6e746940676d61696c2e636f6d000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047145b03e1028650b87eb4ef79231816c3f685dbf10c86eacea23af48909a856957b41dfbd75ac36524b": "0x00000000000000000000000000000000000a506c617965724f6e65000000146c6175726f2e6b656e40676d61696c2e636f6d00000a406c6175726f6b6966000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047145b0f569c80b1ef944889a8a8910ca711d463b40c9216c7007638c77f4f62fa37ad1f05b5fc386e0c": "0x00000000000000000000000000000000000f4a757374526f636b657443617368011a68747470733a2f2f6f70656e7365612e696f2f446f6e4a5243010100000a406a72636173686868000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047145b174056fc3b6e14dc9163ea2d0bf58ceaf597668ac362d5723f061642ef6dbd498e5088f11b2225": "0x00000000000000000000000000000000000a446973727570746f7200000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047145b2364935bdfff38fa27cbf66115a030147d7e427273ca01ced9332ac5ca8883927d41f121f60651": "0x00000000000000000000000000000000000e736b6574636879206a61776e73012168747470733a2f2f7777772e6162616e646f6e656463656e7472616c2e636f6d0113637874726f6e636f40676d61696c2e636f6d000001000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047145b2d54fd29af31b28691026aa386df1bde178237fd99072af73d9fba71b0a350dff42db8bd2a4279": "0x00000000000000000000000000000000000447616201010101000001000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047145b3a26a81f77f16fd623d05214a4c208f0dc52cf4eef865afccd55bfedd175856129aa3048d38174": "0x00000000000000000000000000000000000e4e465420436f6c6c6563746f7201010101000001000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047145b3e4fda94e65239bdde527f50b491568aa2085ee12c5535d7ce765e180399a038eac99654a31ad5": "0x00000000000000000000000000000000001b53595354454d20434f4c4c41544f5220505552452050524f585900000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047145b48f080beb98586a8ca45025561ad23d3000cef010fb14901ba322283898e08c3d0a7fcdd03ce5a": "0x000000000000000000000000000000000007446542616e6b001368747470733a2f2f646562616e6b2e636f6d0000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047145b4c4e58d29949859a2cb674ea2f4866664769a1663fd6aa321d9cfb89b67c402c881891700c0f57": "0x04000000000200000000000000000000000000000000084c6962657274790000001c6d657461706172616469676d4070726f746f6e6d61696c2e636f6d000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047145b55dc011bdbdd6c4c50e314596f61c5d9d8d93121d1fb03734be5b91e7f4d89eb5fddf130148274": "0x00000000000000000000000000000000000b4e696b75737961363636054e696b611e7777772e696e7374616772616d2e636f6d2f6e696b757379612e36363600156e696b756c696e39313140676d61696c2e636f6d00000d404e696b757379615f363636000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047145b63e90199fb6234a42f4d0ef9a0113223ed286071390af15142d1ca267cb1683a5bf6e8f492de75": "0x00000000000000000000000000000000000a47726f6f645f696e6b094e7572696464696e2168747470733a2f2f696e7374616772616d2e636f6d2f67726f6f645f696e6b2f001367726f6f6472617740676d61696c2e636f6d00000b4047726f6f645f696e6b000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047145b71d956514a077d9ee54da7df7f0e7ca7a874fa03f8094681e9db42994f0b21cd215fed704c3b37": "0x000000000000000000000000000000000009796f726e6161746809596f726e616174681f68747470733a2f2f6769746875622e636f6d2f676f72696c6c6174726f6e00126a6f726e407a65697467656973742e706d00000a40796f726e61617468000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047145b8f8631883ea6dd1e568033ec5a6695a6f27b6e2cb4a2b6dbdcf497c0837fa0272e31019a69ea29": "0x04010000000100c8e6bc170400000000000000000000000000000000000000000000000000000d61726e6f6c64736d616e676f0000194061726e6f6c64736d616e676f3a6d61747269782e6f72671376616963756c697340676d61696c2e636f6d000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047145b908e9c38f784a922592d747d00fa956a6388eccfd7c7684191178e62a1e6e2b12758ff447fc402": "0x000000000000000000000000000000000007506f62626c650000000000000b40506f62626c65417274000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047145b959c6eb8b10f975ae160771e1bffc404bfedafe29a049e2804721a4932258c8a89e7a9cd5a2632": "0x00000000000000000000000000000000000000000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047145bab0f6894110edcd06077d6ae735ec4a8fc88f424db70b0dec1e9bae95e39d2737a105296af462f": "0x0000000000000000000000000000000000094b534d204d61696e00000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047145bc7aeaa278c7e8dda0ab7aa04417272602b517a5e25b783a5aac2a251495eb12d5a4d64ea0d7f7d": "0x0000000000000000000000000000000000074a454550455200000000000009406a656570736f37000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047145be3d49d6a02aa76663628177efedc10b4ffa4c6765b525575ed6a6128b945d93c02b45d56358255": "0x00000000000000000000000000000000000b426561722054686965660b426561722054686965661c68747470733a2f2f6c696e6b74722e65652f62656172746869656600186265617274686965662e6e667440676d61696c2e636f6d00000e406265617274686965664e4654000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047145be620e3757932d22e0299102b6e06b617097dcc0380612e6d3ee0692721d984a3e92b5520d5095e": "0x00000000000000000000000000000000000f52657475726e65642056616c756500167777772e72657475726e656476616c75652e636f6d000000000f4072657475726e656476616c7565000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047145be79f90404ad9e0e4a66ee66171e3238670377bc9ffbd7cb4bda47baf25e6ed80c2070942ee3f72": "0x040100000002000000000000000000000000000000001070617468726f636b6e6574776f726b135061747269636b20486f666d6569737465721d68747470733a2f2f70617468726f636b6e6574776f726b2e6f72672f154070617468726f636b3a6d61747269782e6f72671f70617468726f636b6e6574776f726b4070726f746f6e6d61696c2e636f6d00000b4070617468726f636b32000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047145c0211d083cd891e2594a69ff79c03f8cf57c80cff2d29d4a62d07787e70838463232e42b694a260": "0x00000000000000000000000000000000000000000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047145c35b09fcd09a3c258fd2bfc348cd72f4b516fa5d07dbae2f170724947cac5a578a0cd43d30bce38": "0x00000000000000000000000000000000000e526f636b585f4b7573616d613406526f636b581268747470733a2f2f726f636b782e636f6d0012737570706f727440726f636b782e636f6d00001040726f636b785f6f6666696369616c000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047145c435ff0076da260aa4370d01e3beef9dd9b535ed1c7957cc66685f15cc203189f1245013f92f14a": "0x040000000002000000000000000000000000000000000c56657261636974792e6669001868747470733a2f2f7777772e76657261636974792e66691c40646f75626c655f6f5f74686576656e3a6d61747269782e6f726711696e666f4076657261636974792e66690000114056657261636974795374616b696e67000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047145c5ab5d3c9934ab83e8b471e99fa0edd1730046ef2d4e82f66364dc513f52dbd0fb1ab561cc33e17": "0x00000000000000000000000000000000000b4672616374616e617279000000156672616374616e61727940676d61696c2e636f6d00000c404672616374616e617279000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047145c6592b134c699ba187444691216a55e3455ee1ed462d54ce0b635a1b2b37d0eb7625faa31218877": "0x0000000000000000000000000000000000074f56c2b9c2b9154f6c656720567973686e6576736b7979c2b9c2b91e68747470733a2f2f767973686e6576736b79792e636f6d2f6c696e6b7300156f6c656740767973686e6576736b79792e636f6d00000d40767973686e6576736b7979000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047145c6b1c34b6431f3840b9259dde4ecf577907b60e73ac636e896ac881e1f44c1bab1062fce8edef10": "0x08000000000100902f5009000000000000000000000002000000010010a5d4e80000000000000000000000000000000000000000000000000000001942414a554e204e4554574f524b207c20616a756e612e696f0e416a756e61204e6574776f726b1268747470733a2f2f616a756e612e696f2f1540726f786f6e746f783a6d61747269782e6f72670f68656c6c6f40616a756e612e696f00000e40416a756e614e6574776f726b000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047145c7a1f1f152d77a7e61ccc992fa2dcd65b95d4f77ce0f63db60e2bdb19cbfec36d300f44069c751f": "0x00000000000000000000000000000000000d42696c626f42616767696e7300000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047145cb77214d79cb5a2fac0b420b2c0787c18368b8685cf54606b59fd34f941ce2f31fdb91534c6bd53": "0x00000000000000000000000000000000000f496e7370697265207820524d524b0101010100000a406363776461766964000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047145cc468a5aba1dfd7cc0460228b1d0c8cb99d0b025dcffabfad0f11c8b61297a9dec7d7a2f72c744d": "0x00000000000000000000000000000000000e43616e2d417269732044656e740000000000000b404154726f7531393835000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047145cc5698ecc3af260fe2c90d31ad2500e8b1358efa80aa7170e5887de4687081c24def3fcdcc43d07": "0x0000000000000000000000000000000000037879037879000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047145cdaddbf5de66df5623470253bd540d69edadc8a758e8dbeb532a66c9eb39311e7daf3ed2466d25d": "0x00000000000000000000000000000000000a686f70657361696e740a686f70657361696e740101176e696365726973653133333740676d61696c2e636f6d00000b4074776974706f746170000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047145d07888ff9ed46fc58994e72c04b7c36de2b08b119e7abc2870c51f2315a4980e544197e706e7874": "0x04000000000200000000000000000000000000000000074a656b736f6e00000016657667656e6d617373383440676d61696c2e636f6d000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047145d12ddd9ba6fb6ca0cb2d216a8ad7864f222d92dd6636ae1ff0fd9151ca3b60e0bcd2d55ec25ab4e": "0x00000000000000000000000000000000000a5b41525453414d415d0000001661727473616d612e6e667440676d61696c2e636f6d00000d4061727473616d615f6e6674000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047145d3dec38e02e37251c6d8b40be9990c19e993d238e6e3613cfc6cbc51979d5fa61dd6ea259385609": "0x0400000000020000000000000000000000000000000007416d666f72630a416d666f72632041471368747470733a2f2f616d666f72632e636f6d00137374616b696e6740616d666f72632e636f6d00000a40616d666f72636167000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047145d42f9745219ed50b6b86c53a0db7f8b293e164a22bc0c47d4cd554e3ab2f1f8c4dde73f2227c574": "0x000000000000000000000000000000000010636173746c652f524d454b61626c6510636173746c652f524d524b61626c6500000000000c40636173746c6532353331000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047145d6c6374575f1684f47abec3c5269249303575bb90c763d420fb6148e567841105815cd63152c121": "0x00000000000000000000000000000000000d4368616f73204b696420763200000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047145d9004d360afe69f265dc7b1a304621252fdbb2e64751d958a3ca006f359f4987fd9a77f9b22124d": "0x00000000000000000000000000000000000b636170656c696e686f7300000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047145d9e8b6d1aaa8f64e8e5969ab8c6f6f4d63b090863923fc834b24583c0f2363e00edbd7b7b296011": "0x0401000000020000000000000000000000000000000008766f6c3474696d001c68747470733a2f2f726f626f6e6f6d6963732e6e6574776f726b2f1440766f6c3474696d3a6d61747269782e6f72671773617340726f626f6e6f6d6963732e6e6574776f726b000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047145d9e956221876f960a49a73df6ad2c6b41b8a01c54e34488b27cf010c22af4ad2b46baf013c75303": "0x00000000000000000000000000000000000d5469676572e2938874796c6500000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047145da16a0301baa67d9e1e5d3c3e1a8f1018f081a7d998ea6684e823165a3bf8f18d0838c0ab9fc531": "0x00000000000000000000000000000000000e47396536207c2043797068657201010101000001000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047145dac9d84545257d0e49291d5619f4363858a3528f102f0270fb36e1eb3283e3c1f6478a4e48c8f35": "0x000000000000000000000000000000000013446f745363616e6e65722046756e64696e6700000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047145db29c27869ebe6dc20d53e9595db5afba8fd5320b11f3fa6970ab4335c7517f86fbbc7560bbbb5b": "0x04000000000200000000000000000000000000000000134d696d69204c65742069742068617070656e0000001a6d2e6661727265732e72696d62617540676d61696c2e636f6d00000c406d696d69666172726573000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047145dbe0f77941d0faafa383fb921b3c46f10d51250fbf855bf1de45709fb43db76534a8bdfd072e479": "0x000000000000000000000000000000000005676c736b00000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047145dc126cfaa025d1aac2139e2876b295c93ed453f5de79048754ed32e3ecdd7991584200e822c4532": "0x000000000000000000000000000000000006417274656d06417274656d000015617274656d6b7574726140676d61696c2e636f6d000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047145dcfddbf8eff24b40c1b579fe2da2803945658be583be68ae72980152018d8dff7d8a83f27f37d73": "0x00000000000000000000000000000000000a43656c657374696e6f01010101000001000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047145dd8f42acc19bd83d2c5ddbad0ff443692047d533ca5d92693fb03f15c740757264643133eb5d542": "0x00000000000000000000000000000000000a4b7573616d614875620a4b7573616d614875620016406b7573616d616875623a6d61747269782e6f7267146b7573616d6168756240676d61696c2e636f6d00000b404b7573616d61487562000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047145de66fa01fb4c2d708b3b1930f36bf7fa336c7abc044e75fea45cf1c903081e7e0bfbd664a80093a": "0x0401000000020000000000000000000000000000000008434f534d4f4f4e001568747470733a2f2f636f736d6f6f6e2e6f72672f1540677265676f7273743a6d61747269782e6f726715636f736d6f6f6e40677265676f7273742e6f7267000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047145dea83f53bc9588fa6e49f5e4ba8e10080d8f963dc77cc2a1bd11c0426542a26ac8a0200bbd03c3d": "0x00000000000000000000000000000000000000000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047145e09b43fe9323929ec586c840ae4772a0c0068d8202ce6baa96408294fb32e03bf3e44984307ff1f": "0x00000000000000000000000000000000000000000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047145e0b461bbe90623fec95ed93ac7c2ef8f9eeec8e072f236841214fa59bad12f4d6d2072490922753": "0x00000000000000000000000000000000000a44697a536572676569001c7777772e696e7374616772616d2e636f6d2f64697a7365726765690000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047145e12dc698b4a5bd2d01ec8518f4e2a34834d5d62d8091e8aee663e4446bf8c1ad1d9b02e58a22568": "0x040000000002000000000000000000000000000000000d6b7573616d6178692e636f6d001568747470733a2f2f6b7573616d6178692e636f6d15406b7573616d6178693a6d61747269782e6f726715737570706f7274406b7573616d6178692e636f6d00000a406b7573616d617869000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047145e238672304420f9c80539b93608621c583bed3c25caa9b9862d27ad2d5c36e40a00986b92a5747e": "0x00000000000000000000000000000000000e41746f6d6963546967726573730000001861746f6d696374696772657373407961686f6f2e636f6d00000f4041746f6d696354696772657373000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047145e25f5c22e4254863073c378b0833da59cda1d49d711f37c9ae20ed30dc3dbb842ead63dde578331": "0x040400000002000000000000000000000000000000000a4359424552574156450000001a637962657277617665304070726f746f6e6d61696c2e636f6d00000d404379626572776176653134000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047145e2b059303130f519ad0a56ae39a6237f9eb5c1929d8cb87ecdcc6a31b053e1a37b06d3bfb885943": "0x00000000000000000000000000000000000c4b7573616d61205061706900000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047145e38d1015309414f0ce9186972074fee3e851ea1c8b6d97a0a4fd631a98be1996b14448936bd8e36": "0x000000000000000000000000000000000005594e6f74000000177768796e6f747265636f726440676d61696c2e636f6d000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047145e3a90dd26f050973a8c8c37aeeed30fcb32ee7e4ddeb5e633eaa8f2c0c46a64ba5864f63a0c3970": "0x00000000000000000000000000000000000d4d61676963204672616e6b79001d68747470733a2f2f33347a672e73686f72742e67792f43686f726473001a6672616e6b792e757262616e696b6140676d61696c2e636f6d00000d404d616769634672616e6b79000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047145e5d6dae2517ec4656a5e2491de262ad111c767a3ef398f0b19b6fb4ec7794af4939231abeca073f": "0x000000000000000000000000000000000005576562330557656233000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047145e647d848a1c0e61baae5cc25103ed6b8f136972b3582f23e0e524783c6da4357becaf258a6c837c": "0x0000000000000000000000000000000000094173636f6c646678000000136173636f6c64667840676d61696c2e636f6d000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047145e76a25c3b19eea73e9ff161410bcc8358a7016fcb249cf8e841a5b8d4417db5e1e578efc8e45522": "0x00000000000000000000000000000000000a53494c56412e4d415200000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047145e83c43ea150b4deaee71703931ed8f0437b28ca920a0054c723c9c3e099e6822f58ca0f5620325f": "0x0000000000000000000000000000000000154d6173686f7665727365203420556b7261696e650b4d6173686f76657273651d7777772e6d6173686f76657273652e636f6d2f342d756b7261696e65000000000c406d6173686f7665727365000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047145ead7e317a7b15bc802c869bef7c9ee9696b34b72df675e6d2c0767f1ee15cf38f396a8a06099f70": "0x0000000000000000000000000000000000064d4152494f000000196d6172696f70696e6f4070726f746f6e6d61696c2e636f6d000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047145eb64e243ca273fba80c7347e64d19e137abd5258ae78a835ed01d65787a2f4aea106e8122254577": "0x00000000000000000000000000000000000c5452455f4e46545f4152540454726500000000000d407472655f6e66745f617274000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047145ec8ab4f526b5c792c227f6cb71a18ace22f7e126b230d765c53bb168753b3d33f12582baea65658": "0x040000000002000000000000000000000000000000000c4465657054686f756768740000000000000a407761726d616e6a6d000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047145ed5968b3088d1332e1f318e20b782989f8d4f0db439d9d5a29bf0d52552f5c7941292213d16b315": "0x0000000000000000000000000000000000054840736100000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047145ed84a25925e6b15cef26871166ae1372e4e1b7c59cc227a75ba9e857548a063f3d9ae602710674c": "0x00000000000000000000000000000000000000000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047145ee8405cff42241194339db8b404ea216d60433f00ed67b0cdcd9e29d21355615d967161db0cb04c": "0x040000000002000000000000000000000000000000001f5354414b454e4f4445207c2056414c494441544f5220414c4c49414e4345000016407374616b656e6f64653a6d61747269782e6f72671b6a696d6d7974756465736b69407374616b656e6f64652e64657600000c407374616b656e6f64655f000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047145f0d8890ee3f281f94237cdf8ab6530170cf7256c211e15b3a53100bd495cd668bbe4de875741450": "0x00000000000000000000000000000000000f42696e616e63655f6b736d5f32380f42696e616e63655f6b736d5f3238000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047145f151dc76721212cf68991c22752cfedfc52627d3fea5b6e138260c09a7bd3941a9bc27b0379dc72": "0x00000000000000000000000000000000000a7761666120736162650573616265000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047145f188f90ed9c0ccc0e2cf389e3f53bc3ab0777b1678b1fa13b9c6a8e428695928275ba1cc029bf7a": "0x00000000000000000000000000000000000c4976616e2052204d6174680000000000000b406d6174685f6976616e000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047145f1b8b6e45fb190ccca9cb5657907dcb0bb01d335b17564e77994536edd05ddd50524a9355c2221e": "0x040400000002000000000000000000000000000000000b5072696d61204c616273000000167269656765726a6179333840676d61696c2e636f6d000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047145f3e0959896bb537d25b05b9887ec97dc7b078d84d04a619575bbc450478c6d97d0772aba1865b77": "0x000000000000000000000000000000000009584361737469656c01010101000001000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047145f3f48a63730ca8508a514f13e955ec5401a19e0b64d325cb87a4ff62e50416ef73a834c99493b2a": "0x000000000000000000000000000000000009446f7473616d61780000000000000a40446f7473616d6178000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047145f4d5cce600e2badf85068f05bb04fc1d830745102b649680d7dd589524792942e24232ddbcff40d": "0x040000000002000000000000000000000000000000000b4541524e535441534832001668747470733a2f2f6561726e73746173682e636f6d001367726f77406561726e73746173682e636f6d000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047145f5c79ebd9a8464fb49d5777c5b6aebd9aa9a597ec5cc2e160c9657dfb261ef76752ff7b51781a16": "0x00000000000000000000000000000000000000000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047145f656b807ac9334d44d80863e2464a745a3eaa65cb6a7a336d86bd0390f75981c8e4735038a2d974": "0x0000000000000000000000000000000000074372696d656100000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047145f690a20b95f47ba3e892614b6c645f4f0d3d757b5300777b6d6730f024a8181925e9cd56376c86a": "0x000000000000000000000000000000000008476176486f6f6408476176486f6f6401010100000b406761766f66686f6f64000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047145f79e21c0cc427bbac2b14d62dc0c216e459037f76d0dc6f788f48976db1357ed97bf2dbf48a991e": "0x0000000000000000000000000000000000104d6f6465726e2e4d616e64616c61731343616d65726f6e20452e20476572686f6c641f68747470733a2f2f7777772e63616d65726f6e676572686f6c642e636f6d011343616d65726f6e406365676172742e636f6d000011404d6f6465726e5f4d616e64616c6173000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047145f86b540db6a05d1d635393a4855e718ea723244ecd115bfbf129fd71e44384f107bcc6905069f7b": "0x00000000000000000000000000000000000574616c6a07496b61726173000f494b4152415320564142414c41531450686f746f74616c6a40676d61696c2e636f6d0000074074616c6a33000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047145fb6a4114e90fbedc87dd7c321ad3dca39e53d05541bf9d17306d681ab556029b0f172156e12b603": "0x0400000000020000000000000000000000000000000009636172676f6b736d00001740636172676f6c6576696e3a6d61747269782e6f726715636172676f6c6576696e40676d61696c2e636f6d000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047145fb8bcd13578776d68fc7e1c641c663f8507e074bc989b520ec2c33b0733bd377ff67ccea372a035": "0x0000000000000000000000000000000000084a43727970746f0000000000000c404a43727970746f474d49000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047145fbfaa2a1a2510a7525c7a721c51b453cd55ceba8c86d183b45cdeb531c582159f21a05bb1122270": "0x00000000000000000000000000000000000f7370656e63657220766f74696e6700000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047145fe706d242d60b74f2fe5db865ff1f5e647cdacecea78d89979dc8b00c22d10cf52692937e948c28": "0x0000000000000000000000000000000000134d697363686965766f75732052616e6765720000001c6d697363686965766f75736d61726b657440676d61696c2e636f6d000011406d697363686965766f75736d726b74000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047145fe9709101b5cdf4e4d04514ed98bdef66d61cb7d50504a675095499e3a08b6f70e55e136af1654d": "0x000000000000000000000000000000000008424f524f42494c0b4a4f4e20414e444f4e49010101000001000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047145ff08099f8e90061ba99d08e1e0ba1738bd68e07bcfdea7f486400921abd04b9e1dd1ee6b8cea322": "0x00000000000000000000000000000000000000000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714601c869e08b51af7b04b58ffedd058a81a625819d437d7a35485c63cfac9fc9f0907c16b3e3e9d6c": "0x00000000000000000000000000000000000930784b68656f70730000000000000e404b68656f707343727970746f000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047146023f967e8019e7b344cb1cfad3f1924dfc180169cb9bded8af74e5f457f6528272093398f46fe62": "0x00000000000000000000000000000000000d4361745f4361746f77736b6912456b61746572696e612053686972696e6100001463616465747377617940676d61696c2e636f6d00000e406361745f6361746f77736b69000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714603d476d63191d24744b0a7d18985d2a3527d9d2498822644667f042af46231f51eee5bdbbf2b75d": "0x0000000000000000000000000000000000096d617276654c6574001d68747470733a2f2f706f7274616c2e61737461722e6e6574776f726b000000000c4072756461797275646179000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047146041d27bd4e9040932abc1ad7749a511ed7b24f535f0908561cd2f8d550e7f9689ddcf285bfcc845": "0x00000000000000000000000000000000000c54686520466f756e64657200000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047146046b114806eb5a2b4dc5c71e24bd3c05768294b875060b54e8b7663ae9658eec8b9f99568bb6e60": "0x00000000000000000000000000000000001341727420696e206d7920756e6976657273651341727420696e206d7920756e69766572736500001361696d756e66747340676d61696c2e636f6d0000094041696d754e6674000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714604a48dc92e39be9fa9d24f035ebf90c61da552b2317dd1703f5a216e4b02786af26f8b41f211e35": "0x00000000000000000000000000000000001043727970746f53706163654d616e58010101010000114043727970746f53706163654d616e58000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714604c2e1bdbd6e3e66aac0cfe2a889556f28599f18da991a0a352b26f3d59c81961385eaf6f037c3b": "0x00000000000000000000000000000000000b417274486175734e465401010101000001000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471460672f43cee923df4a4c04c002c7c58fd79b886d649cc5ed9367d5c1ec17e8946fafeadd9f17067c": "0x0000000000000000000000000000000000054b617465054b6174651b68747470733a2f2f6c696e6b74722e65652f626f6c696b617465000000000a40626f6c696b617465000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047146067f41bd57795d6945e90a1afc83f0c74a3ffe96b40c4ebb5397af04126bc2db23036c043be4a63": "0x04010000000200000000000000000000000000000000134361706974616c5374616b696e672e636f6d001b68747470733a2f2f6361706974616c7374616b696e672e636f6d1c406361706974616c5f7374616b696e673a6d61747269782e6f72671b737570706f7274406361706974616c7374616b696e672e636f6d000010404361706974616c5374616b696e67000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471460707c14d6e8780e128e3b8a2d3b98071ba399c17206f84350e65653537dbbd646cb5908efff9d49": "0x040000000002000000000000000000000000000000000f5a6564617a69204361706974616c001368747470733a2f2f7a6564617a692e636f6d13407a6564617a693a6d61747269782e6f726713636f6e74616374407a6564617a692e636f6d00000f407a6564617a696361706974616c000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714607fa85c571cb935f0dbc94eb3d3fde9a2fa187c0ed37d158bdcbd48374ecc306373f222e19a860b": "0x000000000000000000000000000000000008465249454e445311636f736d696320706f72747261697473000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471460b67be86271e2f36e99996cc6c41e39696f7c3bc4248e548473b68fe2ba26567771be07b7eb5b19": "0x00000000000000000000000000000000000a43415354414b494e470101011963617374616b696e674070726f746f6e6d61696c2e636f6d00000e40436173745f466f726b4e6174000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471460b684ec999e7b776c064ffd60471f3c2adf674a02e6ea11ce28f1981dca3394b86062f94aec3112": "0x00000000000000000000000000000000001242494c4c494f4e414952452020f093858201010121626974636f696e2e62696c6c696f6e6169726537383640676d61696c2e636f6d000001000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471460c583d95c1213880a72a8935ecfe766b95282b1902fb185171bb302d78bbc27dc5c89c25ef6c37d": "0x0000000000000000000000000000000000094e61726973657469000000196368616e752e6e6172697365746940676d61696c2e636f6d00000f404368616e753436313836313331000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471460cdf0b66deac356a06c780ffc2b9de1aae95dbcc7571e99639a5bd0a4646a9ccee387964be8837f": "0x00000000000000000000000000000000000a6f7a63616e20646f740c62696e616e6365206b736d000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047146114e2b6ec2830667a196ebccf96edb47307cda78135c6b89259a9f4a747320a379c6fd81127b367": "0x0000000000000000000000000000000000034d4a00000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714612039a711b36f21e810732f068b79d01edcc9aed808c3bf25efa395f8dd89ecf8f282cbebe3092d": "0x00000000000000000000000000000000000f42494e414e43455f4b534d5f343600000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047146138eb274d27f0c5a4ce39d360532d50a6c69d07829c49cd7e6578a426f2e99f2b09cdd287cb9805": "0x0000000000000000000000000000000000137a62632d776f726b65724f70657261746f7213e4b8ade69cace881aae5b7a5e4bd9ce5aea40000113439303539333632374071712e636f6d000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714613da82c3ef33267be14004eaae54231bada9111a86e3fa2fec1e94229b2d716bc90311cd75f1a65": "0x00000000000000000000000000000000000f62696e616e63655f6b736d5f34350f62696e616e63655f6b736d5f3435000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047146159604e6072a968e4f7e1546f461407d77e0147cfd55b204c151c6f6f5c3d121d93619bb208e576": "0x04040000000200000000000000000000000000000000096364626169626169000000136a69616e69406c6974656e7472792e636f6d00000a404364626169626169000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047146162ae27b1f4959cd2658699891fdc5afeea90415ba58333034b6e831e5c9f14c5a72a1abf10bc7d": "0x040000000002000000000000000000000000000000000c44656e697320476f6d657a00001a4064656e6973676f6d657a2e686e3a6d61747269782e6f72671c64656e69732e676f6d657a31373139393740676d61696c2e636f6d00000e4044656e6973676f6d657a3937000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047146163414a2df709441a5eac9a90f7102af1e06c3c94890e49e1fddad6086afe119f3477a34a098255": "0x00000000000000000000000000000000000c6b7573616d61206c616273000000166b7573616d612e6c61627340676d61696c2e636f6d00000c406b7573616d615f6c6162000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714617838b6d37dd7945ef462a72d35939b5584e9a29b33af86b356ce709bf022029f075991de1cdc4c": "0x00000000000000000000000000000000000944414f20495043490944414f20495043491168747470733a2f2f697063692e696f2f000d696e666f40697063692e696f00000a4064616f5f69706369000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714617d0fda1940698d00834960bbbc5d62f484f8dac939fed0d34781de56ca24596cd29728962d1f17": "0x04010000000200000000000000000000000000000000044253441342617264757220536f6e6e692044696d6f6e0000126d7264696d6f6e407072697661742e646b0000114044696d6f6e536f6e6e693431303730000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471461811f3dd86470107a377b96be092a5ef4e78cba0b9d33be2206d0ab6d31ebf6b9026f9bdbb84f51": "0x00000000000000000000000000000000000745626c616e630101011d6361737065727363686e61757a65722e313740676d61696c2e636f6d000001000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714618fd93a58f35389e2680e2c991a18cf7ba4710a51ba147b6856879a3047a03f8c647c69b953d630": "0x040300000002000000000000000000000000000000000751696e77656e0751696e77656e00184071696e77656e3a776562332e666f756e646174696f6e1771696e77656e40776562332e666f756e646174696f6e00000d4051696e77656e5f57616e67000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714619bd5898686aa365c4c4cb973301ccba822fd2d525c9ada03e8ded3a3c396e4bbf0e2107101e558": "0x04000000000200000000000000000000000000000000074c75646d696c000000146c7564646f6236373140676d61696c2e636f6d000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471461be688e5e7a221af444917451425779e3e5d876f510ff63599e80cefd31b596fd03d2a0fdf8a658": "0x00000000000000000000000000000000000000000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471461ec8191fc5989284252e6ae566173032638ceba452106c90dd62a83b9f56f32d87a8a5cf7156a7c": "0x0401000000020000000000000000000000000000000014f09f8c9f20616c6578616e64726120f09f8c9f001c68747470733a2f2f616c6578616e64726168656c6c65722e636f6d0019616c657840616c6578616e64726168656c6c65722e636f6d00000b40616c7868656c6c6572000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471461f27b90121cc03394243fe719e35099e11473b7e357af29ba960e0c0dc92ec37a04278e2760df1f": "0x00000000000000000000000000000000000b57616e67646f6f646c650450617400000000000f4077616e67646f6f646c65746677000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047146202f221c7d24475766f18a6eba78487bc0e570108e8c80d864be67c5bb6f8242420c0f43c955c1c": "0x040000000002000000000000000000000000000000000f43726561646f72657320576562330000001863726561646f7265737765623340676d61696c2e636f6d00000f4063726561646f72657377656233000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714620f714edca8297ae21e94b7c05630c70ab2867d6f30ec737042ed4525baf9b920b8df5b3161aa2c": "0x00000000000000000000000000000000000b4a75616e204541476c650000000000000e4077336e6a75616e6561676c65000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047146244e474aa91e041ae9749dfdee466ed67835efa51f04d74db27d75e919d7050e4f5b7f481f77a14": "0x0400000000020000000000000000000000000000000006535052494e00000019646f7473616d61646f626c616a6540676d61696c2e636f6d00000b40736172615f74726d73000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047146269f1c102c0bcd962088931a549261141670f3076ea53eb7fb0af2d5717fefbca6d16ca48eeca32": "0x040000000002000000000000000000000000000000000751756f72756d0000164071756f72756d6c6c633a6d61747269782e6f72671971756f72756d6c6c634070726f746f6e6d61696c2e636f6d00000b404c6c6351756f72756d000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714628acd4748784be3a2da2913d7db19baf0a41dc40a73d75bc6001ce1691c3ded78e4e86387881b4c": "0x040100000002000000000000000000000000000000000b43686f727573204f6e65000000126b7573616d614063686f7275732e6f6e65000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714628be056de9c8868da02ca3758e9d65bfa5ad00f3a258996a96f49323635e11866ec4d8924b8e316": "0x00000000000000000000000000000000000b53706972616c7761766513436573617220416c6265726469204469617a00001673706972616c776176653740676d61696c2e636f6d00000d4073706972616c7761766537000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714629a4d1544110b26a8f85ce44267618f170518db7da6321a685e61838d3efde0d62d46a10ea16b20": "0x00000000000000000000000000000000000a4a756e7175656972610000000000000e406d7970726563696f75736678000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471462c58c7418228d6852310e6542cccdcab43d1104aa442792b3198b67913966b339ae8303b7b8f010": "0x040000000002000000000000000000000000000000000c444f545f4b534d5f53544b00001640646f746b736d73746b3a6d61747269782e6f726714646f746b736d73746b40676d61696c2e636f6d00000b40446f744b736d53746b000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471462c6144c430228802e62b548856a9ff975d160a0df8219bd36a7807620ac1ae2eeeb34498ba3e470": "0x040000000002000000000000000000000000000000001064656967656e76656b746f722e696f0000194064656967656e76656b746f723a6d61747269782e6f726715696e666f4064656967656e76656b746f722e696f000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471462dbdca0ca2af18f4c440cddf43c86794b066df57248545bbfd487ca4bb653f97efca73d1c4c1949": "0x0000000000000000000000000000000000065365646c6f00000000000011405374657070696e5f52617a6f723737000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471462e240b15fe5fc9d40750e87a8eeb07ffb982670415979c0b6b8c33c27aa81c621b5c96df3148520": "0x000000000000000000000000000000000004524b4f08524b4f204152541f68747470733a2f2f6c696e6b74722e65652f486f757373656d3133524b4f000000000f40486f757373656d416c6c616731000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471463168c77524eff6872b83296f11b567d5dcfae7f23e88b1d4c33216002a6bb6a3892a801d4ca4c0f": "0x0400000000020000000000000000000000000000000013436861696e53616665204964656e7469747900000012696e666f40636861696e736166652e696f00000d40636861696e736166657468000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471463182e6ca878bb873e459ba69f3cfc7148ceb115a6be76c18bd69773eeeb6b5bd5240d3233ec0014": "0x0000000000000000000000000000000000104d69636861656c20446f75676c61730000001a6d69636861656c2e646f75676c617340676d61696c2e636f6d000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714633914b3a4ceda021eb38b0d5178bc680c10a204f81164946a25078c6d3b5f6813cef61c3aef4843": "0x040000000002000000000000000000000000000000000e416c69636520756e6420426f6200001a40616c6963655f756e645f626f623a6d61747269782e6f72670000000f40616c6963655f756e645f626f62000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714633b64caf2f93c5bd8856a8b804829eee642bf2b6b516e28958926179cf089338f2ea81a64470152": "0x00000000000000000000000000000000000b6d6f66666f5f6a6f6a6f00000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471463415cea64dd2404ac41d6bb0835464e8428f9393e3edd73b74aad6d978a9870ecf4e7eed1ed8c0d": "0x040000000002000000000000000000000000000000000f68656c69787374726565742e696f00001b4068656c69787374726565742e696f3a6d61747269782e6f726713746f6d4068656c69787374726565742e696f000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471463469200c98418da9e91c0029b5a22ff3799a39634f2cf1e89060f4acd5ab2855a4b91fae1150a3e": "0x040000000002000000000000000000000000000000000a506f7765724c61627300001640706f7765726c6162733a6d61747269782e6f7267146d696e7a756b76696b40676d61696c2e636f6d00000940564d696e7a756b000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047146354c3c5f32f80e56ce8f0f322c021ca4991c83240d0feb94ad1678835b51d228999252bf9223e49": "0x0401000000020000000000000000000000000000000020f09f90b05f2e2de3809020435259505449445320e38091202d2e5ff09f90b0001668747470733a2f2f63727970746964732e6c696665154063727970746964733a6d61747269782e6f72671468656c6c6f4063727970746964732e6c69666500000b40637279707469647338000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714638103b9b7fd6d8154902ac86eb3bc2e1ecf30533e2d9f1f1b034ac0dd35ff41f44da47384646169": "0x040000000002000000000000000000000000000000000669616d7a73037a73000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047146386fd585f1ea07542a041a8ffd0a0de1d7a09e1de1635a8fec8d94f3410ad806111ecc9e456a14d": "0x0000000000000000000000000000000000094d6f736772656174094d6f7367726561740000166f6c756d6f73733230313940676d61696c2e636f6d000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714639f42b914578e805412791fff5f735f273124674635bdae68a09229b99bc0bbd1ae0edbe83a9b05": "0x0000000000000000000000000000000000074e5f4c6f6b6913456c697a617665746120536f6b6f6c6f76611868747470733a2f2f696e6c6e6b2e72752f414b644576770018617274656c697a61766574617340676d61696c2e636f6d000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471463ac3c1368e584e17277877d44db05f92e11933c218cb6a0521f24896c2406e5aa60fefb204cd72a": "0x0000000000000000000000000000000000114c616c6f204d61696e204b7573616d611c4564756172646f204a617669657220476172636961204c6f70657a00001b6564756172646f2e6c616c6f3139393940676d61696c2e636f6d000010404c616c6f313939394a6176696572000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471463c5b9775db401c68e303bd9a1d343eb4a0b4bde59e42981bfcf6e0013b87835529233cbacb63e2d": "0x0000000000000000000000000000000000094a61636b6e46696e01010101000001000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471463d7ad13e4a5e5d66c7794b3f35a9636f38ce0e7fbc035b445f7d8cb19d2eb1c4deee97ca8e3dd6f": "0x00000000000000000000000000000000000d6b7573616d612070756e6b73046b73701968747470733a2f2f6b7573616d6170756e6b732e636f6d2f011a6b7573616d6170756e6b7368656c7040676d61696c2e636f6d00000d406b7573616d6170756e6b73000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471463d8eec7a22e3fe26f3913b4f1a51729f61ec915230c7de2a7d577e4da9034d02e3d047a9498cddb": "0x00000000000000000000000000000000000f4b41424f4348412050415241494400000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471463e692f33df6177fccbd7176021b4da713cb1d0acfcd28fdd2ed0657f34d7341e055160e67a5ce64": "0x00000000000000000000000000000000000a796573626f72796573056f67757a00000000000b40796573626f72796573000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471463e7faa7d3930e42c443fd5caf9808af1b7a5586e7717f4f85ef6d4762d0ed1aa98edb83577e957b": "0x00000000000000000000000000000000001041727420556e73746f707061626c650000001f6172742e756e73746f707061626c654070726f746f6e6d61696c2e636f6d00001040417274556e73746f707061626c65000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471463e8632182788bd60a439f839504ef07c5cf8daf62beb17546e808ed1026c8a683be8207245f300f": "0x0400000000020000000000000000000000000000000018556e69746564205374616b6573206f66204b7573616d610000001c756e697465647374616b65734070726f746f6e6d61696c2e636f6d000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471463ebead6dee4cc021cb5747641960389b41372ddf6c5eb13b7aca0e06193dc732c9975c2feacae3b": "0x000000000000000000000000000000000008546865204f6e6501010101000001000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471463f0045ef18b9c5c9468b8cad284058b157ef324f85ab25a84e890efc6d08b1068df790d06387953": "0x00000000000000000000000000000000000101010101000009406d657663686562000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471463f0f91780f2ce733674264b4be5fccb6e5b960a8259e2920a7d5a85774560360b76c2e219983d78": "0x00000000000000000000000000000000000944656c6f7344414f01010101000001000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471463f4f567548c9f8c2843d91b23b106e3020b7a903da075113d1aaca1db7ac30e119d6250fb6f5961": "0x040100000002000000000000000000000000000000000b48595045525350454544000012406c6f6b616c3a6d61747269782e6f7267146c6f6b616c40687970657273706565642e6175000009406c6f6b616c7070000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471463fce0f80bcc10c07006f88b83702ddc8509429bb2d29e8b0e538aa42f01b495f269f358beae5635": "0x00000000000000000000000000000000000853616d7361726100000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714640c0a62703f8c354ae4661aa6417a9200e77acc80beaf8222c4d6c43318e9ce44bb4827ba401a24": "0x0000000000000000000000000000000000074e61696b656500000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471464127eaeb41ddf9d8e73597eb622ce0a2ea8c15674502d2099bbc62cc9251269d31bd1fc0a56bf7f": "0x000000000000000000000000000000000007436f6361736f0000000000000c40436f6361736f73616d61000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047146419f57ea3f84915121b12be1a2b918b9d01ff05c3d2fe5a28769cb747ff9fd7ecafc320dd5f810b": "0x000000000000000000000000000000000010446f74204c65617020456469746f720e4272756e6f20c5a06b766f72631f68747470733a2f2f6e6577736c65747465722e646f746c6561702e636f6d0113656469746f7240646f746c6561702e636f6d00000a4062697466616c6c73000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714641ab77a8f62130ee4b0ce3fdd2e23b0be2314a084becb2f782302768fd25900e51b241c6a8b8b2d": "0x00000000000000000000000000000000000b506c617a6d617469636b104d61726b6f204d6968616c696e6563127777772e706c617a6d617469636b2e696f00176d61726b6f406d6968616c696e65632e73747564696f000010404d61726b6f4d6968616c696e6563000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714641f551ea31b85752a6cfd49c515150a2daf15df3dd7e94d3bbdbad7a2f2c47651b1cf12fc0b0a44": "0x0000000000000000000000000000000000076a6f686e647912416e647265204d75736573616d62696c6901010100000e40414d75736573616d62696c69000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471464212dfe8be1489d70ab4d54ff22e17eacd7d1a393811b4c555f60803c068e64470d74d55ed2223d": "0x00000000000000000000000000000000000a414e4f4e594d4f555301010101000001000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047146436bbd870b62a0a0475fa54014587f4211cf4bb360489a63b4e0d7c4dd03e2cca08bbc5adfb9f57": "0x0000000000000000000000000000000000064a6f72696b01010101000001000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047146451faf4c30c21127c329830176364028bd694be68b8e62b1cc3508a6779889926b6cc2a22d8d574": "0x00000000000000000000000000000000000a486173685370696b650000001a686173682e7370696b654070726f746f6e6d61696c2e636f6d00000b40486173685370696b65000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714645a2111e24537a2c088a8a35f9a31008c7ac0d4103078bb14b3d50213e4b92bf03ea98c081f173c": "0x00000000000000000000000000000000000b4441524b464f5245535400000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471464680adbdec0e1af3e2256acd251ae7db0c356b5b5aa4d67adbf25281d9d074d364d57398a60b31b": "0x0401000000020000000000000000000000000000000009457667656e526164001b68747470733a2f2f726f626f6e6f6d6963732e6e6574776f726b1540657667656e7261643a6d61747269782e6f726716657240726f626f6e6f6d6963732e6e6574776f726b000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714646ace64bb54bf1ca6b6d86d75692bc3d6f3c2c9b83173ce3b9e5e738adc16009c5d4a0d80e36c31": "0x000000000000000000000000000000000006517561647300000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047146478c35322287a2a38bc40bd7bb3dc77516be2d9fd9c02168506073728317baafe272267873ce80b": "0x00000000000000000000000000000000000d4d6574616d6f72666f7a7a7a00000000000010404d69737465725f4368657272797a000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047146480d6c21997bbbbd278adfb237acd334f2939c917a94a5acdd972ed468a743e7c562a6f1bf6ba27": "0x00000000000000000000000000000000000476764b00000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471464850ed977f64df0a49a4bc7683f6ffd027b75a783f6c5b182a633a22cc0605ba0abd470de9def5b": "0x00000000000000000000000000000000000000000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471464acb2a5e7697e7428778f95bd35e3fec4ee72a0d252c47097380c3ffdf93a9600b364ea119c0502": "0x0400000000020000000000000000000000000000000012524d524b2e617070206f6666696369616c001168747470733a2f2f726d726b2e61707017406272756e6f3a776562332e666f756e646174696f6e0f68656c6c6f40726d726b2e61707000000940726d726b617070000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471464b2511e92b6677ab1e8b074b1c82002a33e63338a04b974107769099111637275514fb0cd740978": "0x0400000000020000000000000000000000000000000017536e6f776272696467652042656e656669636961727900001d40776861747265676473666f64726a6b673a6d61747269782e6f726713616964616e40736e6f77666f726b2e636f6d00000e40736e6f77666f726b5f696e63000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471464b6eda43f595223dcbb7ca8b988aa2a9771a34d8ddde1bdddc4177d021a87a2e6559b58a4252d57": "0x0000000000000000000000000000000000064d6174745800000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471464bcffa5a054b3fbf06b28b48291aaf2818a2bf2276ef4bfb2702c9b1a651b58c8bd45c91d926d3d": "0x0000000000000000000000000000000000114d61726c75612047616c6c6572696573000000000000104054686547616c6c65727931313131000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471464c69542e90ec9f70223f0fec2f4aa58a1666aad88ff105170d3cbc67343f17070fa95047d0aac0a": "0x0000000000000000000000000000000000044e6174084e6174616c69610000126e67726f6d6f76616140756b722e6e6574000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471464f0f0b4da5c0746d0354e9fe5a5be336577b8759695e5c13dd9e07bd2bea414f2a47b88c2cca867": "0x0000000000000000000000000000000000044e656f00000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471464fffce989e2fabc6a0051ef580a2b9dd19a368b82ec20f9a605b0207f2e8d364e6c985b5b2ba871": "0x04000000000200000000000000000000000000000000064d49444153000014406d6964617338393a6d61747269782e6f7267156d69646173676f64383940676d61696c2e636f6d000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714651097b4998394e146d1b7fd733a68d1c3e53d6bfd7134a5803fe5a4033c2dc9eba2e31dc21c4a65": "0x0000000000000000000000000000000000076272656e7a69000013406272656e7a693a6d61747269782e6f726700000009406272656e7a6935076272656e7a690000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714651f9baac64c847fb004ba829fae5aec26aaa3aef02d67856a32c161d3d50807a17338bc06592a74": "0x0000000000000000000000000000000000056b736d6300000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047146522b168b23b5549d8e1ead6bf0091994d15f0df75afd35759da29eba0512ce3913b668fc656a229": "0x000000000000000000000000000000000007457572656b6100000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714652d11d1e91fe674e0588915142c9ed7cad4b2abeb48263fca36403643561fb0929da1949c983160": "0x00000000000000000000000000000000000c4d6f6a6f2053747564696f0c4d6f6a6f2053747564696f00000000000f404d6f6a6f53747564696f4e4654000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714653cf62e15004fa7a68f012e4e382e5eb35895b62f3184be8aa381109bd6a270d661c05ee8565930": "0x0000000000000000000000000000000000086d61657374726f00000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714654cf21a2fd00f055e520486d48edd5e6f31158b9960a0673503235c10135a57c147389815412162": "0x00000000000000000000000000000000000000000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047146553c10b93169dc66e8a3622a7355ab70892bc48236c461076d5163f55309b7e5d0a459d17c6272a": "0x040000000002000000000000000000000000000000000d57696e746572737072696e670000194077696e746572737072696e673a6d61747269782e6f72671477696e7465726b736d4070726f746f6e2e6d65000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714655dfea04bf9ae01f8b3e568239aaf85034f6f4a28e4d6b90a57ecf04de0005531f141d849aea160": "0x00000000000000000000000000000000000b417374726f4d6164647900000017617374726f6d61646479313040676d61696c2e636f6d00000c40417374726f4d61646479000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714657b24569b4318acd6e71489d5d3479fb29f2f7cf4b3a9534f72de76d0d76880066362330f818c09": "0x000000000000000000000000000000000008444172746973740a5065696e2057616e6700000f777065696e406c6976652e636f6d000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714657f579f3442148eea0ab1b08b58a3708b50ba9928c4e25ad71d68efcbb868a2f75b987d0e8e4108": "0x00000000000000000000000000000000000a575252696368746572000016407772726963687465723a6d61747269782e6f7267000000114063617473776974686f757468617473000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714659226a0e9136adf1010b8a9bac58b959a3b92e0ff6a1a2946d36a543b8f8d34a70f231c91f73313": "0x0400000000020000000000000000000000000000000010426c6f636b20416e64205768697465000018406372697374695f616e5f6d3a6d61747269782e6f726715736f6d6574696d65737340676d61696c2e636f6d000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047146595beebc30abfa94e56d4889d3aed021503759b7a8428959648af042d123e2a8f495179ee7abc53": "0x00000000000000000000000000000000000e456e72697175652040524d524b00000011456e726971756540726d726b2e61707000000d40416c706861697264726f70000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047146598a12412759f6926f23bd836ee246363cf6151d26b5d323c077e5d73697de6ea099d1e8368b937": "0x000000000000000000000000000000000007e5b9b3e5928c0000000000000e405a6544617343727970746f73000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714659cef47a15bd68424401b30707f2ef5ffbcf62a082f989655d8d542f4b49f2d0cef0e4bf622bc6b": "0x00000000000000000000000000000000000c43727970746f57696e6773001768747470733a2f2f63727970746f77696e67732e696f00000000104043727970746f57696e67734e4654000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471465b47ab9f3aec5ec06e3ed1e088da56a1e7ea6b57a856a0ead9e03bfbbd1ec74b33153e35015f10a": "0x000000000000000000000000000000000008546f6d69747a7500001440746f6d69747a753a6d61747269782e6f726712746f6d69747a754070726f746f6e2e6d6500000940546f6d69747a750008746f6d69747a7500", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471465bc13bbec192777643ccd0e9c3470bced3320d37d632da5fa7a7f13eda60bb6ca83ccb2ba0f495e": "0x000000000000000000000000000000000006504c55544f00000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471465c283803e3c51bba2c30b2305139eb8d015e3eef8b71accde489c01030153ee2599a5de59dfe869": "0x0000000000000000000000000000000000155449515549205449515549204d494155f09f98bc00000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471465f501be466f9b4b4c476e3612a313e1ce03f27e26affdf86137396fd1d38fee5b8902c9f0892870": "0x00000000000000000000000000000000000e4d75726174204174696d746179064d757261741c68747470733a2f2f6c696e6b74722e65652f6174696d74616b757300126174696d74617940676d61696c2e636f6d000009406174696d746179000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471465f65e549ed519ab389ab756df0ac71f85739a5ad44971dcd1f0afaf783daa1007cf3589c94fc1f3": "0x00000000000000000000000000000000000a436861742d436861740000000000000d404368616261737469656e5f000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047146644353ed65ec6a1589ad5b4e32f5317c485258bad05fab5a0d716971f7832fb565d6037ef4be95f": "0x000000000000000000000000000000000010556e636861696e6564204e696e6a61011c756e636861696e65646e696e6a612e737562737461636b2e636f6d010100001140756e636861696e65645f6e696e6a61000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714664fe17c743b2df5d09338c5be5ef14c6d2e27a0ac9e65ce1167d13a79584cb684cd11a9b7f1b977": "0x08000000000201000000050000000000000000000000000000000006416c65785600000014616c6578676d696e6540676d61696c2e636f6d000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714665285c8d09dbb63b44cc7489f7ee065a888cb76ad104715a6a9ad5b0d2be070949985734fe32f39": "0x04010000000200000000000000000000000000000000196f726c6f77736b692e696f2076616c696461746f72202331104c756b61737a204f726c6f77736b6913687474703a2f2f6f726c6f77736b692e696f00136c756b61737a406f726c6f77736b692e696f00000c406f726c6f77736b696c70000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047146652dea770af814592374b554ae5a1ce10e87eaf0b25b26d3d2680fb9bd59b32e203ded3a2936471": "0x00000000000000000000000000000000000d4e465420426162616c61776f0000001d6d69636861656c2e616b696e6d656a692e6f40676d61696c2e636f6d00000e404e46545f426162616c61776f000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047146663c4bca0fcc63836af143c60658947d49e753293cc454dee77beead3b919ce47c3467a12f6266b": "0x00000000000000000000000000000000000a596f75646c6544414f0000000000000b40596f75646c6544414f000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714666400683ecf9c61ac94924e4f863b0d6b74957b1641de4cd23dd809276a9f8ae5dc32c5eefb2717": "0x00000000000000000000000000000000000b576176696e20476f6f640000000000000c40576176696e476f6f645f000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714666ad47322da5d72a62b6efc3312fabe517bf8e1f407a00a676bf2112161ed1daeb0f5e784208b43": "0x00000000000000000000000000000000000973656f73657263680009776172702e777466000000000a4073656f7365726368000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714666f15289c2f579fba6b7bb322f0a9aecd1faa52f835110cfb228107676c28771a2a024a2bbdbf53": "0x000000000000000000000000000000000003454400000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047146670b1e816a2cedaaa2b3e0a8702aebcb83d552838a17902b2403b0f16c4e52a4514fe02df532e3c": "0x040000000002000000000000000000000000000000001af09f8c9020646563656e747261444f542e636f6d20f09f8c90001868747470733a2f2f646563656e747261646f742e636f6d001661646d696e40646563656e747261646f742e636f6d000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714668bbbac68a19cb7a02f7333e25590e4f568ae8a2ddc93a879e92e48fa3cf1666ac56e020c106d55": "0x040000000002000000000000000000000000000000000b436f696e53747564696f0000001a636f696e73747564696f4070726f746f6e6d61696c2e636f6d000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714668ce779b7a9f3801e76b9da6373b204c3db21d2a7097a79afcf32f642a516980ae26c910e70a35c": "0x040000000002000000000000000000000000000000000a4b5553414d41424f5800001740616e746f6e696f626f783a6d61747269782e6f72671b616e746f6e69676c6962657274626f7840676d61696c2e636f6d000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047146699d463bc3acb0176df0017195b220a733f294a1835837a8a8ec22d66deb8cacfcbeccaad77e748": "0x000000000000000000000000000000000005517565730000000000000a40717565736c6f7264000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471466a0ec80cc3122c082bf733f44a840f0a5c1935a002d4e541d81298fad6d1da8124073485983860e": "0x040000000002000000000000000000000000000000000b73616d20656c616d696e0000164073616d656c616d696e3a6d61747269782e6f72671273616d40696d6275652e6e6574776f726b00000b4073616d656c616d696e0a73616d656c616d696e0000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471466a17448b8730ba3089e132a7e8fe6484138542c6e44a303d0e66750a9381730bb421a28cad7f033": "0x00000000000000000000000000000000000777616c6c657400000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471466ab20bec2c8842b5c7a60ff74811eee72747ef1f1ae376eda2d3c8aab129f6c2cc76abaf59fb87c": "0x040000000002000000000000000000000000000000000a486563746f723c423e00001840686563746f7265737430363a6d61747269782e6f7267156862756c676172696e6940676d61696c2e636f6d00000d40686563746f726573743036000d486563746f7242233936313500", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471466b6b504ec5881431a57245f1409f422242aefe885d3b0c7227cfb00aa278c6b84e34a803c14eb7c": "0x040100000002000000000000000000000000000000000c415245434f4e542e70726f14417265636f6e742053657276696365204c4c431568747470733a2f2f617265636f6e742e70726f2f1840617265636f6e742e70726f3a6d61747269782e6f7267117765623340617265636f6e742e70726f00000d40617265636f6e745f70726f000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471466c21eb278416a36b6217be75d0c62d8fe8d921563198f317fc92f65025cf3d1d1bf2cab9b7cf732": "0x000000000000000000000000000000000014504f4c4b41444f542e4a53202d20524f48414e00000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471466d2ce8502374c4f9c4f65bbb181e89e5539eecf3cec64c02ff858973646fff1a72563e8fe81044c": "0x0000000000000000000000000000000000064469706c6f01010101000001000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471466d850d0167dfb3ff429460ae52548e754c712a7cfc75f1bf7c9295da165293ca52ccc686db5c02d": "0x040000000002000000000000000000000000000000000a5354414b4550494c45001a68747470733a2f2f7777772e7374616b6570696c652e636f6d16407374616b6570696c653a6d61747269782e6f7267147374616b65407374616b6570696c652e636f6d000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471466f1abaccca5dc5ea22523537072ddf4b80dfeedc797c613e8c2452a7f82f810b6e30ebb7281843e": "0x00000000000000000000000000000000000942617274204b534d00000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714671d243feb29878cc23a09ccefbe0b2e0bd6ca9e44ea9f9f566180c324f0ee94d750493b2a90d364": "0x0000000000000000000000000000000000104469676974616c20466c6f7269737401010101000010406e6f6d616463727970746f677579000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047146736de782d724588d2777ebda943e55cb791aa8437709ef3bb53c3231bd91a75b835439dd6ef4663": "0x000000000000000000000000000000000009536572676579373500000019736572676579736f6c74616e303240676d61696c2e636f6d00001040736572676579736f6c74616e3032000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714673b3b4a1ad50d479c644791dc08755b8abe4530f04692c895f2a4a93ab128acc17fc4fc0808372c": "0x000000000000000000000000000000000007477575676c6f00000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714675581c1eea085a9d8dba69752ffb04fa563b126a31b037c8bebeb73e3c66cacd7c8efab46bd3423": "0x040000000002000000000000000000000000000000000a70616e6472657339351d5061626c6f20416e6472c3a97320446f7261646f205375c3a172657a1868747470733a2f2f7061626c6f646f7261646f2e636f6d174070616e6472657339353a626c6f7175652e7465616d15686f6c61407061626c6f646f7261646f2e636f6d00000b4070616e647265733935000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471467568de3317e474e9a64ad79179d3f9e018447fa67d8d05d92f0d82e4dc731d14e516ae10a25d924": "0x040100000002000000000000000000000000000000000e496d627565204e6574776f726b001b68747470733a2f2f7777772e696d6275652e6e6574776f726b2f0016636f6e7461637440696d6275652e6e6574776f726b00000e40496d6275654e6574776f726b000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047146775a976f24cb02358805bce812d39a03405e454ea71401dbc7be353f65686c4c6bb30e656c8b76e": "0x000000000000000000000000000000000009486f6e6579706f741054657373616c69652046656e64657200001974657373616c696566656e64657240676d61696c2e636f6d00001140626f6e676d61737465723132333435000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471467baf0838d6b1b2ae02e07f40a4d21e0d5fa5ff929adf8b9bfeacaf06bd5987b2741522b01ba4a32": "0x000000000000000000000000000000000011446567656e206f6620446f7473616d6100000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471467bcc2ca4091537b5c7125e83d4230d1818f811230994a118ac01ccb73ceb2146a8a3f443ed75241": "0x0000000000000000000000000000000000056b61746f00000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471467d3e4a96a4337066e31ecbbe0f191c3a02509dec5145e1bf73c7ee1ef086904b36a8a3fc249e138": "0x00000000000000000000000000000000000c4a6f73686573756d6172650000001d69717569717565697175697175653230313940676d61696c2e636f6d00000d404a6f73686573756d617265000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471467f3ca507a532ccb2e1884c53071526483b14004e894415f02b55fc2e2aef8e1df8ccf7ce5bd5570": "0x00000000000000000000000000000000000970657079616b696e00000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471467f85c2c7218fd6c409c3164dee58108840f004e49ad5abcc680714ede7ea4a064986f268e396e43": "0x0401000000020000000000000000000000000000000007434855525255000000195468654368757272754070726f746f6e6d61696c2e636f6d00000b40546865436875727275000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471467fc0f66fe815ab410383630258381dd93b530a4c73fedb24d04aebe8cc7cc6ba4f7e008eef32f47": "0x0000000000000000000000000000000000066961676e6900000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471467ff75c4bc963c22fa77d65110d751716c8236da48f45bec37350fb0b36b6dbb8cef029fcba86b00": "0x00000000000000000000000000000000000c716267406576726c6f6f7400000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047146811e36909dc3ca59e42ace67151e0f94d4fd29937698d7ed05d8b5e663dde63c9227b0a3ae9334b": "0x00000000000000000000000000000000000a456c6c7920456c6c7900000012656c776972757a40676d61696c2e636f6d00000940656c776972757a000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471468180e8198681ff7e0d744a6f291a2dc1e6d744d5ae0747e314b046739be170638ecc185ff4a9b5f": "0x040000000002000000000000000000000000000000001e624c64204e6f646573207c20f09f988e436861645374616b654b696e67001568747470733a2f2f626c646e6f6465732e6f72671340626c643735393a6d61747269782e6f726710676d40626c646e6f6465732e6f726700000a40624c644e6f646573000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047146819d27a5574bf9d52f1cc1b6904a99f88fe1a80a09959ec14bf0c4505cab1c13af31d107b817b22": "0x040100000002000000000000000000000000000000000a4269746368617267650f42697463686172676520496e632e1568747470733a2f2f6269746368617267652e636f001368656c6c6f406269746368617267652e636f00000e406269746368617267655f636f000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714682226526c5637c6f4e893116c799faec7c11176104e134077d0d1902ae545b9db21fd842a773362": "0x00000000000000000000000000000000000b4c75636163727970746f0000000000000e404e4654736172656d796a616d000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047146823ed8df7d5f458c46ff658221e07564fde2764017590264f9dfced3538e283856c43e0ee456e51": "0x040000000002000000000000000000000000000000000f747572626f666c616b65732e696f001768747470733a2f2f747572626f666c616b65732e696f1840747572626f666c616b65733a6d61747269782e6f726717737570706f727440747572626f666c616b65732e696f00000d40747572626f666c616b6573000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714683a845d2e2728b9246469efac79c9f41621d250f07f19805a6596176d39826ce44253693ebd5b56": "0x0000000000000000000000000000000000084372656c6c657307546f6d61737a01010100001040546f6d61737a4a61726f737a3137000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047146844ca75100b198bc4b1960de3e58b7b296b26befd8d2588871a3fdb9c58bc3240fb5fb279bc0712": "0x00000000000000000000000000000000000c6d617474616c6163686961054d6174740000186d61747473636f74746372756d40676d61696c2e636f6d00000f406d61747473636f74746372756d000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714684be26b14283aeb2821c06b6812ffe1a79be4b1374799e641b89dafdd961d79720c299827a05802": "0x00000000000000000000000000000000000c49636562657267536c696d00000000000011407472656675636b696e676d656e646f000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714685887d42c2579e03839e4be40e252a56e2d7c8e89a0c8eb990df5910714fea61c6e1d3b1c4c5502": "0x00000000000000000000000000000000000b4441524b464f5245535400000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714687a668789176ce3a262b69b9bfcc58a6707cd9d6d68e30f6815920b3df7016a0d0315b21a45901d": "0x0400000000020000000000000000000000000000000004474f4400000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047146887fb7291f50ec61ac3c67396f49987dfeb090be1ff560b8e00eaa42218093f3043e59a352e5005": "0x0000000000000000000000000000000000036d65066d65746f6f000012616c65786c6a6d40676d61696c2e636f6d000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714689719bd3780b5a8d031f202a2d2aee29aa291ddea64d37b43c9120519e5508a6eeb8b61b232c553": "0x0000000000000000000000000000000000084465657044414f001368747470733a2f2f6465657064616f2e696f00106579616c406465657064616f2e696f00000c404465657044414f5f696f000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714689a20d8714b51d538cadf9abf7492ce1df73d8b7ee82e10c2a0571970e2aa5ded4b9a6f91a49833": "0x040000000002000000000000000000000000000000000f55766f20746563686e6f6c6f67790000001255564f746563684070726f746f6e2e6d65000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714689d5109a8aed88944657c9cc1d0202b2a9508ae547b03bf833352be16facad780b19b179cbd554d": "0x00000000000000000000000000000000000d536e616b6520436861726d7a0000000000001140736e616b65636861726d7a4e465473000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471468b195054093d962441ad818e57097e7d044b15fe0dcdf61742cf279444c5e8ffa9ae554ceb61c6f": "0x04000000000200000000000000000000000000000000037071000000127071686f73743540676d61696c2e636f6d000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471468c9be061f3c16c170e0cdf5c21bdd68eaa9eafec9fd9fc0b6123251406f01de516a06cecdefe64c": "0x000000000000000000000000000000000012576562332e3020666f756e646174696f6e12576562332e3020666f756e646174696f6e000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471468da324624114433da47e564f57cad4eb817c1e7d2287012d5fe459992ae2997995bc03dc55f3256": "0x00000000000000000000000000000000001354686530726967696e616c47616e64616c660000001f7468332e30726967696e616c2e67616e64616c6640676d61696c2e636f6d0000114030726967696e616c47616e64616c66000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471468ea576627e05a04fa0dcc186bc3f6b9fb943feca1bec230acda1bb80b3cb2f9d3ecc3e7d089241e": "0x00000000000000000000000000000000000b4d41442052414242495400207777772e696e7374616772616d2e636f6d2f6d722e6d61645f72616262697400186d6164726162626974323031384079616e6465782e727500000d406d726d6164726162626974000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471468ee2c2eedcec18516fc047d8cace5a7f17cc8605f1fa2de274ad27664a5ed7d6a33dd54e3dfe84d": "0x04000000000200000000000000000000000000000000104d494348495341524e49545a2049490000001a6d69636861656c2e7361726e69747a40676d61696c2e636f6d00000e406d696368697361726e69747a000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714691af4f75a591a304e4593da91318df8bdb35d247accf2db96e12f1d1a7bcae43c047c13991ae924": "0x04020000000200000000000000000000000000000000105068616c614e6574776f726b2d30310016687474703a2f2f7068616c612e6e6574776f726b2f12237068616c613a6d61747269782e6f7267156d617276696e407068616c612e6e6574776f726b00000e405068616c614e6574776f726b000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471469259d1259754a2ee8f80e4dd56979a1eb996faf0d02b804d4b8d3986687d1bb096ef61494881b73": "0x04010000000200000000000000000000000000000000084a6f686e6e7942000016406a6f686e6e796234323a6d61747269782e6f72671766696e6765726c696e6734324070726f746f6e2e6d6500000d406265726d616e5f6976616e000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471469283fb3584b29920cf1d73c4b30f8f97080ad60115e05a5105025201dbad0e95e245c6d78f43805": "0x00000000000000000000000000000000001a5374616b65204361706974616c207c205374616b652044414f0e5374616b65204361706974616c1b68747470733a2f2f7777772e7374616b652e6361706974616c2f1440626e65696c756a3a6d61747269782e6f726716636f6e74616374407374616b652e6361706974616c00000e405374616b654361706974616c000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047146952ec1f162d715fd2f6e5569a0398b8af4ecb4283a1dbeb06a94a1c093b8d2b8532b5944079291e": "0x040000000002000000000000000000000000000000000a736d696c656368656b00000016616c657878786b6c696d3640676d61696c2e636f6d000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471469546ab63701f3cde46a9306739edfedb7505df5e98e1212ba27f17dd964e4607da678379984206c": "0x0000000000000000000000000000000000056230726701010101000001000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714695b23e099c12086505eb7820f60d0949697617b2f3366bd616d8c7e96724aa681e0113f6bf45c46": "0x040000000002000000000000000000000000000000000676616c6b610000174076616c6b613a6661697279647573742e7370616365000000094064617461666f67000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714695dc1e151a40b7a60ed744aac415baf7621e0335ec5046c8edbaa6c164cb4134a1d7879ef5c0a40": "0x04000000000200000000000000000000000000000000094d6972736c61766100000016736176656c6f767633393940676d61696c2e636f6d000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714695fd23b8e9c5e7a24d1da766a4abeec540f5fcb3d9f07f4f1395c7eacdb2e277949f2f5c3a50f2e": "0x00000000000000000000000000000000000e526f636b585f4b7573616d613506526f636b581268747470733a2f2f726f636b782e636f6d0012737570706f727440726f636b782e636f6d00001040726f636b785f6f6666696369616c000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471469610a6934b675c69eafb1ad57ed8ee595ac311709e19ca5dae7df48680cf3c822074b2d69891d58": "0x00000000000000000000000000000000000000000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714696f75486035f5d11e94bf36131632d37719d822bd603d9675488e206d77a509c5bd31ac4ff5ab2e": "0x0000000000000000000000000000000000074d6f72656e6100000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714697c98e61ff7a035f436ddc71e0400b93ece90a48e94cf0e193c9157c4a21199bc32b6dca543313e": "0x0000000000000000000000000000000000204d495353494f4e20434f4e54524f4c207c20434f4d4d554e4954594e46203400000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714697ead568e820ccfd2eb07f02043788e254d9e2df57be11566d241c56302b91199b4647947af3020": "0x040000000002000000000000000000000000000000000846415241444159001968747470733a2f2f666172616461796e6f6465732e636f6d1940666172616461796e6f6465733a6d61747269782e6f72671768656c6c6f40666172616461796e6f6465732e636f6d00000e40466172616461794e6f646573000d666172616461796e6f64657300", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471469937a5fa154cc0722a58635dd1a211d33750333282985df00d84e87b160293d6b39e89ea4bc7d67": "0x04010000000200000000000000000000000000000000084e45574445414c144f7665726d6172636b202620506172696465461868747470733a2f2f616e6f7665726e6f64652e746f702f15407061726964655f663a6d61747269782e6f726714696e666f40616e6f7665726e6f64652e746f70000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714699a4e2e91f07769c8f44643be482988aa2bcd437f7de9722e6a8990e44e2a64c2f426ce3337f006": "0x000000000000000000000000000000000017466c6f7878204173736574204d616e6167656d656e74000000000000104074686567616c6c65727931313131000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714699c5d3507c778d4cecb620d2e44c2e64a400ff3fe531d5e4716897072fbda0fd33fd58dfaa5fa17": "0x00000000000000000000000000000000000b414e444557204e494f4e10416e647265692053746570616e6f761768747470733a2f2f6e696f6e2d73747564696f2e72750017737465702e616e406e696f6e2d73747564696f2e7275000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714699f178882ae3a35ec306760410fb8a67209ee8286fb9ecf86bf6dd864d277b7f3830b288f319267": "0x00000000000000000000000000000000000b677265656e6d61736b3900000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471469a2abccefec01421488aef5fe1d334d513adde87cf781758c6d9c6841cd1925b3b1fcd27f2e6e51": "0x04000000000200000000000000000000000000000000076b6f706f6e65000013406b6f706f6e653a6d61747269782e6f726700000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471469b743ba383eda3afe7d71599a2b67c5085142c626641ccfc1f44919270fcac28d2ecfd41e0c7e3c": "0x0401000000020000000000000000000000000000000004496365000011407a6172313a6d61747269782e6f7267177a61723133696e617a69617440676d61696c2e636f6d000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471469ea407a9f4730a1de5813cb17d418545d0c39927cf50adf35e0a5676f4f9ff8ee9125dfb1cf1a0e": "0x0000000000000000000000000000000000124368616f7320436f6c6c6563746976652000000018696e666f406368616f73636f6c6c6563746976652e6363000011404368616f73436f6c6c656374697665000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047146a15d0669087eed9208735c92b8b6d8391241b17fffd2cd8a74ea8c713cd5ad058360fe8615d1c2a": "0x04000000000200000000000000000000000000000000064a756c6961000018406c6567616c5f6a756c69613a6d61747269782e6f72671e6a756c69612e7374656d7066656c4070726f746f6e6d61696c2e636f6d000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047146a20805653256a9b76dbbe01275e2d5edc1aa637fa5e9e3f83b2eaf5338f3de24332be755548b018": "0x040000000002000000000000000000000000000000000641676176650000002161676176652e6e6f6465736572766963654070726f746f6e6d61696c2e636f6d000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047146a22a847a729096bb6c51bd8c8b45c224054c4ade99572611c2c41d499e26493c32e93e6868edc70": "0x00000000000000000000000000000000000c547572746c65204d6f6f6e0000000000001040576f6e6465726c616e64734e4654000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047146a2edd04aff025a00a71c6a0fbf9b63ac089c5395bdea4917a84aabb3475d4454147c4d24ce1013a": "0x040100000002000000000000000000000000000000000c45726e7374204b696e74730c45726e7374204b696e747300000e656b696e7473406d652e636f6d000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047146a398ba50f12d00734e23dcaeb2f272db78575091eb39369fcee10abf1bfc53551a9b9ec94b94c41": "0x040000000002000000000000000000000000000000000841757374696e5a000012407a6f75745f3a6d61747269782e6f7267146c65726f6e677a6f7540676d61696c2e636f6d000008405a6f75745954000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047146a4f96f9cd70bd9472e7ccd983b92c5ae60481a636eab0fe42269c9f43c302a74f9dc65e0fbe202b": "0x0000000000000000000000000000000000175375627371756964204c616273204f6666696369616c135375627371756964204c61627320476d62481568747470733a2f2f73756273717569642e696f2f0013736f6369616c4073756273717569642e696f00000a407375627371756964000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047146a6c65861cbfd4f690ebd94a58a07211dcf05c4164ebab8c3abaca45f16f793fbe34072ae7b9ba08": "0x0000000000000000000000000000000000054d61726b00000000000011406d61726b5f656d6265725f7279616e000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047146a6e72184ec057bf2838ec53e79c47d990272aa7c797218bcbdb229dbb4a083890ebb47a143387e1": "0x000000000000000000000000000000000018444f542056414c494441544f525320414c4c49414e434519444f542056414c494441544f525320414c4c4c49414e43451b68747470733a2f2f646f7476616c696461746f72732e6f72672f000000001040444f5456616c416c6c69616e6365000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047146aafc9e20cbf801c6e2d7ed8cf2cde362abfdf7d9fa95859c20f906d98ca7aeb305a723cdba08927": "0x0000000000000000000000000000000000104b7573616d6120496e766164657273001e68747470733a2f2f6b7573616d61696e7661646572732e73706163652f00196b7573616d61696e76616465727340676d61696c2e636f6d000010404b7573616d61496e766164657273000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047146ab589167a0b898fcc9f261e20561ee1a137a7c03770706d09a6f85e36e7a313f04d92faefbd3d43": "0x040000000002000000000000000000000000000000000942494742414c4c5a0000154062696762616c6c7a3a6d61747269782e6f726716696e666f4062696762616c6c7a2e6e6574776f726b000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047146acaf91ac46baae4f280f5a4ff014f822ccb22c7482c0b0c688b0fd288f57ea28fcef55ef7fa1451": "0x00000000000000000000000000000000000a4f6f6f63746f7075730d5061736b61204d6172696e690101167061736b616d6172696e6940676d61696c2e636f6d000001000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047146afd27c18040cef1a2af46cca496f67510c65b4ed9f745ff058392bdf7526b99764fb54eb6a1fd03": "0x00000000000000000000000000000000000b4672616374616c456c6600147777772e6d617968656d6e6f6465732e636f6d0000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047146b1e4c1928a48d22a604120d3444af15fde1d4b1906795e462d4978bbd0ad2995312293221af136c": "0x00000000000000000000000000000000000a626f6e64616e76656c0e416e64726569204f6368696576001240616e76656c3a6d61747269782e6f726717616e647265792e76656c646540676d61696c2e636f6d00000d40416e6472657956656c6465000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047146b22402cd56d342a42e3f1833e3a53fbc58fc821cbc960242707bf6570504a0ce6d62de52df1fb3a": "0x0000000000000000000000000000000000076f6e64696e33000000136f6e64696e37373740676d61696c2e636f6d000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047146b2c66241f33f7627cbce8173250e3191a2ff3c05d37a116d3956565fd029fdf531795e3f429b431": "0x00000000000000000000000000000000000000000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047146b3ea68cf38610c0e697c9f32c96c1d09daec35b2d6881c22c01a315dc9e44e17a1a1454c7a33f36": "0x040000000002000000000000000000000000000000000d5354414b452e5a4f4e45203200000010696e666f407374616b652e7a6f6e65000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047146b602156dcd19a36e0b1d428d91be9ef7f6933b17ecfe93b41dc32014329c8f47697c43d11142121": "0x00000000000000000000000000000000000000000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047146b6157a13ed645fa040298f71f02d7b6a67c0ecee7d7a62ea51dc6daecebf4dd9ad72e0510537a58": "0x040400000002000000000000000000000000000000000a43757272656e63797800000014656574696365706f7440676d61696c2e636f6d000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047146b72dbbac6798f2746fe2480205384715045cce22348bb6e69153e172c8780cdfdd9f48177edda29": "0x04000000000200000000000000000000000000000000067961726f6e0000104079726e3a6d61747269782e6f72671179726e40636f64656c7578652e636f6d00000a407961726f6e736b69000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047146b793eedafb74ea99424aaa1e5fbf3eb4200f5686578f97d514f46f90093271607e7309ffcd5ae2e": "0x000000000000000000000000000000000005556c796100000017616c7661646f6c796d70696140676d61696c2e636f6d000010406e61756d6f76615f756c79616e61000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047146b8a8b66e5aaceb88ee2a383ae9ce2d6589f1b285935d8f4930f78e65edc311971df2526d2f55132": "0x00000000000000000000000000000000000101010101000001000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047146b9579021acd44d76a4e6c8afc7a8bd02ff300b3dd1edca19adae52cb65c1908935abba4e193a705": "0x00000000000000000000000000000000000b796f6e6763727970746f00000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047146baf8445decbe4302880ceaa5b3bfd387562510764a2324bca0444751ccf843dba6d9950cb6eaa6d": "0x000000000000000000000000000000000008524d546572726100107777772e726d74657272612e6f7267001665617274686361726540726d74657272612e6f726700000a40726d74657272614f000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047146bbba429de58b1c6ee8e0a7379fb0908719062234d2982188a3b31eb3aa895e6046981b865479b29": "0x0000000000000000000000000000000000155261696e696e20416c7068612041697264726f7000000016416c706861697264726f7040676d61696c2e636f6d00001140416c706861697264726f705261696e000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047146bd6f5cbed6591426e0b706961e1b5f3b545003ff3544f22feae738534cefa08be15d523f52ff114": "0x00000000000000000000000000000000000f4f647973736579404b7573616d6100000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047146be5d0bab82378087042479798003022a5753c8547cb0de8ef25e2471e40889ff3909fe714e24c5d": "0x0401000000020000000000000000000000000000000007414e414d495807414e414d49581468747470733a2f2f616e616d69782e746f702f1440646270617474793a6d61747269782e6f726714616e616d697840706f6c6b61646f742e70726f000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047146bee5533ec8299d8ce116bea2fcddd47f5540ab01eb225b9cb60b053d5f0dd863d33ce89a6da4055": "0x00000000000000000000000000000000000000000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047146bf5f668cb5d93dad21839a4704482a87db32156b9990a0eaa841fb2ae49e362cba1f0d5ded52376": "0x00000000000000000000000000000000000f67616c657261732d7061796f757400000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047146bf9c9353fd020348c33b686a457b74f9b1a61b4446404e522d122064d6713ffacee88bfa9a15861": "0x040400000002000000000000000000000000000000000b53796e61707469636f6e0000174073796e61707469636f6e3a6d61747269782e6f72671a73796e61707469636f6e4070726f746f6e6d61696c2e636f6d00000c4073796e6170746963306e000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047146bfc5690a062a1afacf62b7427d226aeaaa925a52f3b0dee7c343124b0adb8785b3fa48694a0b94e": "0x0000000000000000000000000000000000094a484f4e20524f59000000166a686f6e726f796172747340676d61696c2e636f6d00000d406a686f6e726f7961727473000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047146bfdbf25ef8b99373c016a81d6b5a5d805e1b21e8e0bb9014ba2dfcd7d128251b5dfc30502b3037a": "0x00000000000000000000000000000000000b4769676d696e64204949001468747470733a2f2f6769676d696e642e61707014406d6d61686572653a6d61747269782e6f72670000000a406769675f6d696e64000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047146c01c6b0489d52fa600031e4527046dcc067d2cb23fc6cb1970d94e9251fcc131cd5f23b6ca6d476": "0x00000000000000000000000000000000000c446164647920416c65782001010101000011404461646479416c3238393835303436000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047146c12977fdc424f56cea296c4097c6926c86d188eb65b0f77877584512ba5054f7c52873be1a0580b": "0x040000000002000000000000000000000000000000000c4d65726b6c6546726f7374001768747470733a2f2f6d65726b6c6574726962652e696f18406d65726b6c6566726f73743a6d61747269782e6f7267156d3475353461643440616e6f6e616464792e6d6500000d406d65726b6c657472696265000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047146c1c74353498a63bf41c4ce9c03cf28414bc4e05a5bd6d5d79e72f700a38d5c722aebd796608c44e": "0x0000000000000000000000000000000000044b534d00000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047146c22738133d6c7a48e9da09f277ab09ea322900d4c6e0e3d3221c1a2b702f72590545e851fa9aa72": "0x00000000000000000000000000000000000e6c6c616d617a70726f6a656374000000186c6c616d617a70726f6a65637440676d61696c2e636f6d00000f406c6c616d617a70726f6a656374000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047146c23be321ba1d5692aeb5a90eb2107b7490991ac059fc314c28974cb318c16f75f04241085fe936f": "0x000000000000000000000000000000000011416c656a616e64726f2050657465727311416c656a616e64726f20506574657273000017616a6f73657065746572736840676d61696c2e636f6d00001140616c656a616e64726f706574657273000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047146c3f94c82b8b136c880aa8e4ef5d44c88e477371270a5d5187b12475a39b620f0b813bd002966024": "0x0000000000000000000000000000000000124d697373696f6e20436f6e74726f6c203100000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047146c4d2026575763437cdc1a6a5a7f23437b6528edcdf553d0685f940a4e6e85579727ef3dc574563a": "0x04000000000200000000000000000000000000000000114365727448756d204d61785374616b65000018406365727468756d2d6a696d3a6d61747269782e6f7267136b7573616d61406365727468756d2e636f6d000009404365727448756d000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047146c53b7f96dcb583d9c2b14c09923911fe0ff6918b7c7702a91762aede2c2cdd0f1f0bdcf7b9f2a5a": "0x00000000000000000000000000000000000b4441524b464f5245535400000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047146c6da4b2c10d05fda63297294a9d13df4e9fadfa013e8e6855d330075c55f9347bc4a63a883a8412": "0x00000000000000000000000000000000000748726f6d6f760d496c6c69612048726f6d6f761b68747470733a2f2f6769746875622e636f6d2f4d656e74616c47001967726f6d6f76746865666972737440676d61696c2e636f6d00000d4048726f6d6f76496c6c6961000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047146c6fc4e27d0976af0043984dd2239bb88a209976e33ca5cd20ca0479096d86aab7e9b6137d5c2d62": "0x000000000000000000000000000000000008426972646d616e00000017616c65786a7573747761697440676d61696c2e636f6d000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047146c7206770c39d9295a5f7eb7050fb96d8d7895d9afce428a064ce66e3b094805bcad9a8e68cb9934": "0x0403000000020000000000000000000000000000000013424946524f535420464f554e444154494f4e14424946524f535420474c4f42414c204c54442e1868747470733a2f2f626966726f73742e66696e616e6365001668656c6c6f40626966726f73742e66696e616e636500001140626966726f73745f66696e616e6365000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047146c748650b11aedf08eeb78c1dd6b2244b18b549a0c3cab933c680dbc18b411764be1ce4667f41649": "0x040000000002000000000000000000000000000000000948616d7a696b35330000001368616d7a696b353340676d61696c2e636f6d00000a4068616d7a696b3533000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047146cae0ce72d947795c8ad53e6aa24a6208566faab7d3e203476531e2ee2b4c7d0d77c80245791a00e": "0x040100000002000000000000000000000000000000000c506c616e636b204c6162730c506c616e636b204c6162730000156c616273706c616e636b40676d61696c2e636f6d000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047146cc4e49307ea87327232db7b484171854543c6b3d42b95f6a16f4742d2f683d97fafb45e9bcdca34": "0x0000000000000000000000000000000000076d6f6a64697000000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047146cd2b2fd45e2e3d0702a6dc9592ec94ce9e1f07e2a0559d7f43f932101bace2400d0e92419218732": "0x040000000002000000000000000000000000000000000a73746b656e393939390000144073746b656e39393a6d61747269782e6f726700000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047146cebd0b9de064aab0e038990f47761a17f45c2bb01c4c7746f4ad67c7d0c1dfbd6915372faae911f": "0x040400000002000000000000000000000000000000000a2a2a2a2a2a202a2a2a000000196c756e61722e706f6c6b61646f7440676d61696c2e636f6d000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047146d01b9ac106696b20ec8ef626347c834d4d964b525fb46f8db2910e11d88c0100e62590d10ac990f": "0x00000000000000000000000000000000000f4b7573616d615f573353746f7265002168747470733a2f2f646573746f72652e6e6574776f726b2f726d726b2f752f4b001f4b7573616d615f773373746f726540646573746f72652e6e6574776f726b000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047146d12ad5162806a9cca76c36de0085c8c561dbb64575cb016d4d6e7cef42b666d3ea978543f1c935a": "0x000000000000000000000000000000000008736b756e65727400000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047146d1339be09f0555c5c229899568bac5fdc0ab838a23ee5391f704eac09ec1bdde78841beed461b6c": "0x0000000000000000000000000000000000074b7573616d6100000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047146d301a445678938ac43aabf384c6baf54ef9712a96be7c46533b538c05d4e6c687fe09b109664b28": "0x040000000002000000000000000000000000000000000a4d616e7472614b534d000016406d616e7472616b736d3a6d61747269782e6f7267146d616e7472616b736d40676d61696c2e636f6d00000b404d616e7472614b534d000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047146d34ca1ecaaeb6174471abb5438fa95f8c85b8d5a417df0a6a38b4372874f27f30f20645f3263830": "0x040000000002000000000000000000000000000000000b5975647573204c6162730000154064757979756475733a6d61747269782e6f72671579756475732e6c61627340676d61696c2e636f6d00000c4079756475735f6c616273000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047146d54b71cad5f64b392e2419c0839bb61ec6ab6aae9fbb0c4fc9e519138faba9ae9e5eb4bd17f836b": "0x00000000000000000000000000000000000d616e746f6e696f5f323030320f416e746f6e2050616e6665726f76000016616e746f6e696f5f3230303240696e626f782e727500001140416e746f6e696f3639373637343938000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047146d5ba05b78a2e080daa4917008c6339bc42960ff491ffb03c3a6ddfc2b2b045d1c24112383398252": "0x000000000000000000000000000000000007686f646c337200000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047146d74d28ec12105fa9e2ef38fe8e04e6f04dd146920ea60a5eb88dba8aeb59cba116768220dff632d": "0x00000000000000000000000000000000000a564953494f4e415259034d4a0000196e6674766973696f6e6172796d6a40676d61696c2e636f6d000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047146d77aae7d9cc2c6b6a08d5461e12b86fb79830fc2c45b9df0883ea74d91a02ae0c8ba8519d90f91e": "0x040000000002000000000000000000000000000000000b6372617a796c616e6464000017406372617a796c616e64643a6d61747269782e6f72670000000d406372617a796c616e646464000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047146d7865ba4ce38d13803c48fccb86dbda70ccfa6ac01c6246a558cd1ed3082276e3ec55ca850e1520": "0x00000000000000000000000000000000001373746576796861636b6572207c20524d524b0000001673746576796861636b657240676d61696c2e636f6d00000d4073746576796861636b6572000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047146d81d41850c8478a76016fc20a6457ff8953bf29686c5698c28bbfa860669ddd07b386c910f1107d": "0x08000000000204000000020000000000000000000000000000000016f09f9a82205a756769616e204475636b20f09fa68600001840726f626572743a776562332e666f756e646174696f6e17726f6265727440776562332e666f756e646174696f6e000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047146d8e6ab01df42c15d25af2fedd4eb672f218932fde44f97f10c1d7788efd0079957ffad4f186ae78": "0x040000000002000000000000000000000000000000000b6b69616e656e69676d610d4b69616e205061696d616e691e68747470733a2f2f6b69616e656e69676d612e6769746875622e696f2f16406b69616e656e69676d613a7061726974792e696f0f6b69616e407061726974792e696f00000b6b69616e656e69676d610b6b69616e656e69676d610000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047146da178aac6ca938996ef2b0677180342454254d3b508e6ce27545440454a0e810cbc779af50f476b": "0x00000000000000000000000000000000000763616f67656e00000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047146dae9d8fdc97e46a740e01932711bd4fd74b1c85696ef68396a6f11437ef8b8f44815103ffdbd942": "0x00000000000000000000000000000000000d4348414f5320414c49454e530d4348414f5320414c49454e531968747470733a2f2f6368616f73616c69656e732e636f6d2f0000000011406368616f73616c69656e73636c7562000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047146dcb518544a17d04f4fb2a6f05eb4f0ef01e695d677ffd9f940af819590642305c12924e203f9143": "0x04010000000200000000000000000000000000000000074d626c6f636b001368747470733a2f2f6d2d626c6f636b2e696f14406d2d626c6f636b3a6d61747269782e6f72671576616c696461746f72406d2d626c6f636b2e696f000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047146dd970d8cf026efb58ef09d3489cf843247e53debd2d08faabf4953de4eda8a0221474a1ec42e51d": "0x0000000000000000000000000000000000023500000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047146ddff06071871e051c3f1f94a947e045496deb2fb43db180a284a1f0f141875865aae404d0b38f17": "0x00000000000000000000000000000000000d536c65657079204c656d75720000000000000e40536c656570794c656d757273000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047146de5c15d472fd831e4e00e63c3647fc8c0a3d1b163ac988b6f0a7c3d05a01e209d4adef8e285037b": "0x040000000002000000000000000000000000000000000842696b657234620000001272656b6962346240676d61696c2e636f6d0000094072656b69623462000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047146df179326c6132ac783485f72737efdd4e0c86f1097b1deea2a1ef0ea22514a081151293f8e78d77": "0x00000000000000000000000000000000001b54616e656c65657220616b612074686520436f6c6c6563746f720101010100000c4056696e694c6f6e646f6e000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047146df74e3c08670c34887a557f77bf1881bcf40ba6c2c8d41f819e5630997472cf310c76b8679f7d00": "0x00000000000000000000000000000000000873616e696f6b7900000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047146df9089f721a647b5e18f2acdd0df1e1379c4e45df53fd18ae057e351a2f7df26cf6538bf1f3951e": "0x00000000000000000000000000000000000a4c6569662057796e20001d68747470733a2f2f6c65696677796e2e62616e6463616d702e636f6d00126c65696677796e40676d61696c2e636f6d000009406c65696677796e000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047146dfe113c3c0ddaf4a65e518d273553f951a8b5de9928449255508036636aafab13e479e51fa83153": "0x0000000000000000000000000000000000106172616e656c6c612e6b7573616d6100000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047146e0bda57536f0f7afe8ed746b2f0fafda336e27346a75f2f03db0f73a3e73e1ca6deb3676e14d139": "0x04000000000100902f50090000000000000000000000000000000000000000000000000000000a4d61747453616e746f0000001b6d617469617373616e74616f6c61796140676d61696c2e636f6d00000c406d61747473616e746f5f000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047146e137c0fa3493007c85e3aa75711f5028f297d018c3e20ae87e5c605a4a42c32d075ffc5a2b1aa2a": "0x00000000000000000000000000000000000f42494e414e43455f4b534d5f353300000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047146e1af8908544b70bbaadb6c3e6fb2482077a53cdba093a8ad605991be5a8f692c348c96cedb3b310": "0x00000000000000000000000000000000000f42494e414e43455f4b534d5f31340f42494e414e43455f4b534d5f3134000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047146e2b59d3240a71b136bad3dc145e2a9330d4339cd3ae78ad38899297f90179c89e1c164e7db9792b": "0x00000000000000000000000000000000000b417263686976657273650b41726368697665727365137777772e617263686976657273652e61727400186172636869766572736538383840676d61696c2e636f6d00000f4061726368697665727365383838000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047146e492261936ee303a8a1e3cbfa50d90dd8c3387e41849ee31bade6c9dd7631949b278e063ba0604c": "0x0000000000000000000000000000000000094b7573616d69746100000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047146e49b5b6b41150cb5648a5099cc672def900b179b0b166c0cda43c5741fa016a0a4e59159eb4cc4b": "0x00000000000000000000000000000000000d50726179657273345261696e0000000000000f405f50726179657273345261696e000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047146e4c492ee4a04b7be0e388350540bfbcc4ec71eed079ac582106107fb7e4c3e0644a78ef77090f0d": "0x0000000000000000000000000000000000084752554d4c494e000014406772756d6c696e3a6d61747269782e6f72671b706f6c6b61646f742e6772756d6c696e40676d61696c2e636f6d000009406772756d31696e000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047146e5600c7cb67a52de262091990c95c2667f621831f3215e8fc2a0958daa5658f4ce7c548fd687070": "0x040000000002000000000000000000000000000000001433394b7573616d6120436f6e74726f6c6c657200001a406175746f636174616c797469633a6d61747269782e6f7267116b656e6c303940676d61696c2e636f6d00000b406b656e736572736f6e000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047146ebf663bc0ff3d824445227fdc045db50d470f830869813c458eaa12071681d76ff022a7b9b5e750": "0x00000000000000000000000000000000001a4265636b795f66726f6d5f7468655f626c6f636b636861696e13526562656b61682052696368617264736f6e0000000000114042656b695f66726d64615f626c6f63000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047146ec642500076ba25a6c5f0595d6ed85d6260bc682d4a68a4b4e605d43c67d56f2765d19698549772": "0x040000000002000000000000000000000000000000000b5374616b656c792e696f0000124069696363313a6d61747269782e6f72671161646d696e407374616b656c792e696f00000c405374616b656c795f696f000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047146ef36fb6f6a6627954d552eafb3c32b82bee18d1093507b22d300293d0691948950fb2a6cfbf1d12": "0x00000000000000000000000000000000000b4d616b6569747265616c05416c65781f68747470733a2f2f6c696e6b74722e65652f6d616b655f69745f7265616c0000000010406d616b6569747265616c5f617274000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047146f007ed8cae8e00c428480e94271bfdffe5fba698c5049093175433f81dde2e8f2f656a228995312": "0x000000000000000000000000000000000006626c6f6f6200000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047146f162ae750478cd420d36d6d4b71407dccd0a9fe417f847296503b1db88b49034e72b107177d5e67": "0x0000000000000000000000000000000000106675636b746865636f70732e6574680000000000000d40665f636b746865636f7073000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047146f1853e1ebaebf497a688ccd0cad14cf3e26ad4b10c0775968bac5ff48f77a8c4b09cc3c3d77ad23": "0x00000000000000000000000000000000000b4b75726f43727970746f0000000000000f404b75726f63727970746f525047000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047146f2598efe3f47fa4e622f17425a56e7acc6bcd2b36f6912005287c470d94a3deb0f0ba39f8f41f75": "0x00000000000000000000000000000000000753616d6f6c6f00000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047146f2b5e9f208392888cf6773ed595b6b8f123786931160f5162f826be90f00ba77493312a768e9e2d": "0x00000000000000000000000000000000000f424154544c454b414e415249415300000019626174746c656b616e617269617340676d61696c2e636f6d000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047146f337845d3ff300d84ef1a151887ad6d4baedf802cfe9ade9c4c9ca57747723f0b3d7ca956997f7e": "0x00000000000000000000000000000000000d546865204e61727261746f7200147777772e6d617968656d6e6f6465732e636f6d000000000d404461626167686f646c6572000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047146f360d963f230c31180b25c72c11ca6b74d6601e3684642afbe828f3e7b45479a42d0b84fc8cdf12": "0x00000000000000000000000000000000000b446f62726f646979554108416c656b73657901010100001040416c656b7365795f313936393131000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047146f3d6f5d8945a2a9d896f718b4ad053ba53468ba0347060b4a80f03fa72e9c14da5e2e7ea80e3f2c": "0x0404000000020000000000000000000000000000000008426974446173680000001a6d65726365646573736f72656c313040676d61696c2e636f6d000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047146f3df2817b3b9c94e44dba99bb5810bdc7a2a1d32a4b021ac735ef01322f57be7b51210f46d3b323": "0x0000000000000000000000000000000000074c656f6e5f4701010101000001000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047146f56186447cd7ef15aa188fa54383921d848228f0e40540f07297c6241a05e63f675ce5ec53da525": "0x00000000000000000000000000000000000f666f6f7462616c6c68616e67303100000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047146f630b718e317f68aab8c369bfc11e722e4328afbcf0bde98b014ac292eb9a33e745acd3c4e820cc": "0x00000000000000000000000000000000000d484f4c44504f4c4b41444f540000001c636f6e74726f6c6c657240686f6c64706f6c6b61646f742e636f6d000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047146f7f4b41e08c803b185c5ef33d3d91ed9167e35bff60265cec83c040ed7766f256ce0f599da6c749": "0x00000000000000000000000000000000001056656c696e6f7661207c20524d524b10436872697374696e61204d6979617209726d726b2e6170700013636872697374696e6140726d726b2e61707000001040436872697374696e614d69796172000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047146f808393005db1390cdd6d75a061aa70b5d57bd30e693cecb8e7a392788262319da19105c0f4604c": "0x0000000000000000000000000000000000084e61706b696e350f526567696e616c642053747568720000127274737475687240676d61696c2e636f6d000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047146f99dd7465b93e507c6e2eb7daa3efe47026b0aaccc5c24d5a8c36387f471d5ad10b63a269bbc11c": "0x00000000000000000000000000000000001541746f6d757365202d204b7573616d61204d4b311541746f6d757365202d204b7573616d61204d4b311368747470733a2f2f61746f6d7573652e63630010696e666f4061746f6d7573652e6363000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047146f9bf1c5c47f9bff1c378d545f64248bedae80ec34f8f29551fc9f814f8491f8fea50f10fff6e229": "0x00000000000000000000000000000000000b4441524b464f5245535400000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047146fbe924612f6781f544bbcd309eadfd42df83e1483616da5dbccf5a8cc0bfcdc023c4d310580cb2d": "0x00000000000000000000000000000000000f596f6e6b6f204d7567697761726101010101000001000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471470014f24dcab4fe440a6b2797a5499aaba937f5931186ce4ec4831af09c1571f185e68a0a926451a": "0x040000000002000000000000000000000000000000000846696c6970706f1246696c6970706f204672616e6368696e6900194066696c6970706f3a776562332e666f756e646174696f6e1866696c6970706f40776562332e666f756e646174696f6e00000d4066696c6970706f77656233000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471470023b9d2a2c164748ca001326b583070e370be3bc6680d09cad47649584a5c992bd388c693b9a54": "0x040200000002000000000000000000000000000000000f4b6576696e204c69207c20455043000014406b6576696e6c693a6d61747269782e6f72670f6c696a756e7169406d652e636f6d00000e40647573687573616e6a75616e000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047147006767d397f2ca9ea767408daed5fa84321c8d73e1353b847391877cb07ede4de41a98c010fe702": "0x00000000000000000000000000000000000000000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714700eadba413b7d7e9a017a02ac5e0464e0fe81c2db6d53396f85e7cc4818fa63972ddba87c1db039": "0x040000000002000000000000000000000000000000000d4d617968656d204e6f6465730000000000000e404d617968656d5f4e6f646573000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471470175c9772705b5ba28f7a2b2fd4fd83e0dc9c67d22fea19d5e755aedc336a973afa342ef2642147": "0x0000000000000000000000000000000000094d69636b794e465400000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714702bcefac99fd4dd8679aa82b4485f9035d099869dc380bc36b390ae89b77a21b1dfb8db3de56d54": "0x0401000000020000000000000000000000000000000007746477736e690000000d3040746477736e692e6e6574000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471470381211b81bd578b208742339c55723f8834a3379a95ba73073d7583a7d381ed6ec1b860f46692b": "0x0000000000000000000000000000000000043737370000000000000d40766c6164626f6e64373737000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714704211a750c9b855eed08a5b10b1835610d66ce4fa273c8e2436b978c9f65442efb6074871b48a6a": "0x040000000002000000000000000000000000000000000c50726f766520436861696e0000001570726f7665636861696e4070726f746f6e2e6d65000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047147049f2f99a873c94c00f86f5f5421e98f7ba345ccd996c53412f39308ea854053fe650ca7bf44f75": "0x00000000000000000000000000000000001242726967687420496e76656e74696f6e73001d68747470733a2f2f627269676874696e76656e74696f6e732e706c2f0000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714704fd4d990de5befa2062502692e27d3608be0d008ea4b92ec004291e439f90b050bef5ec7f0f23f": "0x00000000000000000000000000000000000d506f6c6b61646f74746572730d506f6c6b61646f7474657273001440706d656e73696b3a6d61747269782e6f72671c706f6c6b61646f74746572734070726f746f6e6d61696c2e636f6d00000f40506f6c6b61646f747465727331000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714705bdbc11ece35d4b43cfa22c3d218af6782a4d65b8f3634fce7cffea162940ca819714f49747337": "0x00000000000000000000000000000000000d3320457965642042696c6c790000000000000b404243727970746f6e73000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714705e6ea755bbf165fee29a5ceb96897553f0573c57f2824416ab0160259c6dedd23dc9553e7f7979": "0x00000000000000000000000000000000000c506f6c6b617370696465720e506f6c6b617370696465724c7500000000000e4061696c696e67797532303138000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047147061508d0facf9d35a1a549172a49f7591155007c51680ad8ad77571cea04acd1b0b84459e779234": "0x04000000000200000000000000000000000000000000073078546f6e6500000000000008403078546f6e65000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047147067b025e697cd29c8ceb1c664df2d960b92a98620baf455b678d17a8c066832ad463537dec7b916": "0x00000000000000000000000000000000000e416273747261637420536563740b54796c657220526f776500000f746a726f776531406d652e636f6d00000e40416273747261637453656374000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047147073fca8d293ce1f104f30a7ce921de97e2b0953c03b1b52290417f02ddbf93f00d32560ce6cdc73": "0x00000000000000000000000000000000000014486f706520446f726f746879204d7572706879000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047147074ebffa575049570886222c37e2ae242e928891fa622a6117888450059ea48efb53048e2b7d46b": "0x000000000000000000000000000000000005527572750257010101000001000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714707a1c5ae852ffd0d6e82061804fecd8a01e8c288670158557d1e0d29fd43965d6d9a18f456d9e5c": "0x00000000000000000000000000000000000e63727970746f20706965727265076c6f7572646501011a6b6576696e6c6f757264652e70726f40676d61696c2e636f6d000001000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471470862ef001da720f4c91bbedabe6c9691a94cf18545d962d105c46e421a187a1762475116b6e3931": "0x0000000000000000000000000000000000104162737472616374204d6972726f720101011e617274627961627374726163746d6972726f7240676d61696c2e636f6d0000104041627374726163744d6972726f72000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047147097277b2a5e0e0c74c08ab30239142fa489802606f4ba630d10ae640d418068e557125f7ab21437": "0x0000000000000000000000000000000000044a444c00000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471470b0ccf61769cfd8360745c8f812f88313ecea48072c02d3af2e0879f0788fb42ca57d2a08308913": "0x040100000002000000000000000000000000000000000a414747524547415445001b68747470733a2f2f6167677265676174656e6f6465732e636f6d16406167677265676174653a6d61747269782e6f7267206765742d696e2d746f756368406167677265676174656e6f6465732e636f6d000010404167677265676174654e6f646573000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471470b521035124345e708abc87f99cb7125a4485ab287fe649da93d7f63d94f1723eff0702ce271b38": "0x0000000000000000000000000000000000104f6666696369616c204b75646f7473104f6666696369616c204b75646f74730000196b75646f74736f6666696369616c40676d61696c2e636f6d000010406b75646f74736f6666696369616c000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471470c16b639ae50cfd227dd8d2161a0ec5c16d32bb404f4397db4eec7a0384dec4434653c46d6b4e68": "0x0400000000020000000000000000000000000000000007616e73616368144141524f4e2054494e4720534541204b494e4700001574696e672e6161726f6e40676d61696c2e636f6d000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471470d819a2c84da4c51854e80d2ab67fb4b12a0372a7345e933258591fa524445f98f9e228c6c2d157": "0x04000000000200000000000000000000000000000000054f7461720000000f6f746172407061726974792e696f000011407368616b617269736876696c693237000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471470e8af948020788b9023c272646be7fdd636e3f40a760528e8d3ed13a56a7f60b70dfb0865e01057": "0x000000000000000000000000000000000006566c75796e00000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471470edeff14bdc035a2290b0d093c2c0a08acdb392bed5b03a80bdd6654e950ff597feeb3c9b9fa831": "0x0000000000000000000000000000000000114d79436f696e7461696e65722e636f6d001968747470733a2f2f6d79636f696e7461696e65722e636f6d001761646d696e406d79636f696e7461696e65722e636f6d000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471470f0a3ba8fdc51ba04c760ba8b16be7af64b5fb7e1b3243abc8a02ffc7e87fde86fa29f6ed3c5776": "0x0000000000000000000000000000000000076f6c657a62610000000000000a406279627972616279000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471471116de1a587c32588a4ed0e6c34d0464f85f9b7017fac279d96a1a581c00df0a2d68e655836b75d": "0x00000000000000000000000000000000000b537072696d6f4d61696e0000001573616261697072696d6f40676d61696c2e636f6d000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047147112ba5d6dbefa86fa8cae363fae322ca18adf9cb334426c0d8a4eda052ae2919136fb2aaf810d2b": "0x00000000000000000000000000000000000a43726f636f64696e6f12456b61746572696e6120426c696e6f76611163726f636f64696e6f2e64657369676e001a64696e6f63726f634063726f636f64696e6f2e64657369676e0000114043726f636f64696e6f44657369676e000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471471136285006adf116270f8a05e7e0281bc17de3331550f81e8089dad4b80614c028c0c816a872566": "0x00000000000000000000000000000000000d534652204465706c6f7965720000000000000d405346525f5f53747564696f000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047147133801574a23097407c5d153353f5dd34183ce2c8b55e6b7858de0baa2a568b7c577ae65f04623b": "0x00000000000000000000000000000000000b6b68616e6f6e6472756d076b68616e6f6e010c406b68616e6f6e6472756d0100000c406b68616e6f6e6472756d000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471471338c87abd75247bec65f0d42a638f8ecec8206173fe2953dfd914fe6285ad35812621e09e8373e": "0x00000000000000000000000000000000000757697374617200000016656d696e34696b3139393340676d61696c2e636f6d000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714714f1bba6aeb57ed503830ae159d84972115565fb0d195f5c84d0b3aedf7661f14923f434c482e58": "0x040000000002000000000000000000000000000000000455534100000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471471807145847ce7520a9e6fb48b9423ae5939f07fe1d7f41a6c1ebe3d2135e94af94b7fd717a47418": "0x0000000000000000000000000000000000096d6161726d6170611e6d6172696f2061727475726f206d616c646f6e61646f207061727261201b7777772e696e7374616772616d2e636f6d2f6d6161726d61706115406d6161726d6170613a6d61747269782e6f7267106d6172696f40626f796b6f742e636c00000a406d6161726d617061000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714718a792663e13c111e015452870e49b4e4c3e054556b19683e8895586bfa58638a74a5782ab4f712": "0x040000000002000000000000000000000000000000000e414c45585f3031205354415348000019406261626c6f7275626974656c3a6d61747269782e6f7267176261626c6f7275626974656c40676d61696c2e636f6d000011405374616365794d3033393337393233000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714718c7c930a9f7254d86997541d3de5e602951b87a658d2b1f239a44b1aa7db63926677175a296130": "0x0000000000000000000000000000000000044b534d064252554e410019406272756e616b616c6c696e653a6d61747269782e6f7267186272756e616b616c6c696e653140676d61696c2e636f6d000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714719741a00f0f258052b508058d399f2d273c624adac51fc2e2e9083a0d13cb59e515c83178b91f08": "0x0000000000000000000000000000000000054e4f4952054e4f4952117777772e6e6f69722e6469676974616c00146472696e6b6e6f697240676d61696c2e636f6d00000b406472696e6b6e6f6972000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471471a62c336559149c727cdf9587aa815816cbf027b2040a04860e0ca6863df676ab65e79aed5dfe12": "0x00000000000000000000000000000000000c596162615f44656c7578650000000000000c407961626164656c757865000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471471b1a690490b9b855030a81483b3f65ad2904fd32cbcd5d3a534e9617e0c1daf610acd4e1d851821": "0x00000000000000000000000000000000000a646965676f6e616b7500000017646965676f5f6e616b7540686f746d61696c2e636f6d00000b40646965676f6e616b75000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471471bab60978c7657ac0af8f315fd5c43e3a9d5f24986cff822296343aef9c3c9e9c98d7b8c16dc770": "0x00000000000000000000000000000000000f536c696768746c79204a756963790101010100001040536c696768746c795f6a75696379000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471471bdd65031f8d5b4264b8f4a0be4ca7a9b8c7a8a08a119d549bebb1be6049b2947d363cf06f1e749": "0x0000000000000000000000000000000000076261796576730101010100000840626179657673000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471471ce39b31932f385f616ea43a83d30c7e9cd14c07f2534d4e1d983feb50af44e2e101786f1174d5a": "0x000000000000000000000000000000000008537461726579650000000000000c406879706574617269616e000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471471d47d954dd610d384e78712d71e4663b0673f11b9b9119d41b6a74c3ab3e1cc49b2c26e45f2c717": "0x0000000000000000000000000000000000104c6962726172792047656e65736973104c6962726172792047656e657369731368747470733a2f2f6c696267656e2e66756e0000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471471d6f804bbc175ce2c2fcfda3ef3753aaef240f2d5048bf365a746ac9ad94836ad72d9e4030d217d": "0x0000000000000000000000000000000000074e61744172740101010100000e404e6174616c6961735f417274000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471471ea140dfcf364da7e3b8fd929dbbbd1986cc76d08bd7d45710b54ebd933c2545bbcaf1981b4f02d": "0x0000000000000000000000000000000000064c4558584f0000000000000c4069616d736f6c6578786f000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047147214db08aea29f4c2a5bd5797da40fe8be1b94dd3260ef86d6b01cfc891c5c1cd160ad7fa198de57": "0x040000000002000000000000000000000000000000000a726f746b6f2e6e6574001268747470733a2f2f726f746b6f2e6e657418406869746368686f6f6b65723a6d61747269782e6f72670d687140726f746b6f2e6e657400000f40726f746b6f6e6574776f726b73000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714722083cf8467cb9174725e8d7159b39aa5dd43117d6354ba8f5ebd00f73b484e0b397477ce8fa949": "0x00000000000000000000000000000000000868756e6973616e00000017706170616d6f6e2e676f2e3040676d61696c2e636f6d00000d4068756e695f63727970746f000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047147231a73eec660398046ff960b0d51db710b8ca414171afd47c9612311b69fa9416622dfb42a33124": "0x04010000000200000000000000000000000000000000073330383072611f33303830205265736561726368202620416e616c7974696373204c74642e1468747470733a2f2f3330383072612e6c74642f13403330383072613a6d61747269782e6f7267107465616d403330383072612e6c7464000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714724c7c15464878b07802118deb1bdd268c44247e6804781b4548c46e8442a63af94682f2586fd54f": "0x040100000001006c57c10b0100000000000000000000000000000000000000000000000000000f4d792043727970746f204769726c001968747470733a2f2f6d7963727970746f6769726c2e696f2f00157465616d406d7963727970746f6769726c2e696f000011406d7963727970746f6769726c4e4654000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714725a86431f305963b0537038713a322f80aecc5a647740589a2ab3a9f558d66e1edff7dbcf321034": "0x00000000000000000000000000000000000f537572662042756d7320436c75620000000000000e405375726642756d73436c7562000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047147266c84e2a6ccd54865a0192a7b1bf11f1915b156b8a80e5bc2983a38d075ecafb9fcecd13980210": "0x0000000000000000000000000000000000144d69737465725f436f6c65204344204d532031000018406d69737465725f636f6c653a6d61747269782e6f72670000000c4031393238333734367a7100075f6a706d665f00", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714726d01a4c80d6ba32af509d174981a76e0ea8736ebd955e869e7aa3df90d9782dfd27f8d5275877b": "0x00000000000000000000000000000000000e6d61696e2e73616b692e6b6f7500000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714729ca592de7e6cc0349febe9138f7c4f2123246970770df11b411268566c25bcf71377d23717285e": "0x00000000000000000000000000000000000f56696c6c69616e20417274697374001968747470733a2f2f61727469636b7573616d612e636f6d2f00136e6674766966657240676d61696c2e636f6d00000f4076696c6c69616e617274697374000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471473006ea8baa58afe58f26dd10efac24a7fd1813d6aa72a8e60bee976f7da28e492ad033fc1822315": "0x08000000000100902f500900000000000000000000000100000002000000000000000000000000000000000e4172674e6f646552756e6e65720000001c726f647269676f2e62617272696f73393040676d61696c2e636f6d000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047147304b924b222e0c7dae5efb233d7bdc68fc16135030559ee44b6372ef24650ca982158e8ae9b1c34": "0x0000000000000000000000000000000000077761766530360101011c6672616e636f69732e6c6567656e64726540676d61696c2e636f6d000001000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714730966358482a89df88d7cb742e81b397cdef5f7cb474cf2df150c46a450316042e096240b132b7c": "0x00000000000000000000000000000000000f42494e414e43455f4b534d5f31310f42494e414e43455f4b534d5f3131000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047147315356594fd4a95bcb17afaf0c76d9419961b476bda55ae861b5ddc7517212e5ffe51739ce7110e": "0x0000000000000000000000000000000000074152544b555307416172746f6e17687474703a2f2f7777772e616172746f6e2e6172742f144061616172746f6e3a6d61747269782e6f72670e61616172746f6e40706d2e6d6500000d40416172746f6e447572616e000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714731673ba1d1b7d986e311246667f84dd2c1d2c2d2125f71c1364b217deab8ef23eacfc4c693fa64a": "0x00000000000000000000000000000000000000000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714731adab152229ba0b659069707b696d313e7ca3bae3a5f2c4951bc142487185e254d35f7af56c40b": "0x00000000000000000000000000000000000670616f6c610d50616f6c61205475617a6f6e1c68747470733a2f2f7777772e70616f6c617475617a6f6e2e636f6d001668656c6c6f4070616f6c617475617a6f6e2e636f6d00000d4070616f6c617475617a6f6e000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714731facdea878555ec6f4c6d200f27c4b02afdd345dd02ea77dc45c05b79dcdd2c5709418a0658503": "0x00000000000000000000000000000000000d63727970746f566f7274657800000000000009406673675f646576000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047147321f7eac82ba0a6d68f13f9cf8966128c622327bd4819ab2a9ee1532587bb04ebc99e5e993b4ca1": "0x040100000002000000000000000000000000000000001a526567697374726172202331204775696e656120506967203200107777772e6578616d706c652e636f6d0012692d61696e742d6e6f2d656d61696c2121000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471473445c1fa17d2f30828005347ff7053e6a83a61075859529c9ae6f85ea952e2d44d8b5667209933d": "0x00000000000000000000000000000000001a4d6f72677261746868207c486f757365206f66204368616f730b4a61636f62204b656e740000156a61636f626b3130333040676d61696c2e636f6d00000b404d6f72677261746868000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047147349ec625640077690a8aa6a4593bba62b920c5dd3f580b4bafa5b6c3b567dbaf5598d3f0963466a": "0x000000000000000000000000000000000012546865204e696768742047616c6c657279000000176e3167687467616c6c33727940676d61696c2e636f6d00000e406e3167687467616c6c337279000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714734b6c90edb07bd010f22d753c18dcb34da3b1573e4ecdff30f6d3b2642b1864d3bd7832e5cf9721": "0x00000000000000000000000000000000000759616b696e6900000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047147351a6242479e8c754adb573ab2fe5551264b00100828e552e8ff391fcf975b85ce81f900a2f5b32": "0x00000000000000000000000000000000000101010101000001000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714735585e3f384f206eeae02b784e8ec57b81c2bbe0cbed5bd3cb5dcc98f76d81c99edeae3a2aaa85f": "0x0000000000000000000000000000000000074f70706f757300000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714737675dbae64b33e3284bc8ce3083b62e671d1c5bd61db5b3fea95a77967341ca8834a69cffcfd5f": "0x040000000002000000000000000000000000000000000b53554241455445524e410000174073756261657465726e613a6d61747269782e6f72671a73756261657465726e614070726f746f6e6d61696c2e636f6d00000c4053756241657465726e61000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047147378c2b706979cac06ecf3372b3e7ece785bb3ac73d9f9b458fe48856ca1a524e929f794e8c17320": "0x00000000000000000000000000000000000b4b55534157414c4c4554094d4f4f4c494e45580015406d6f6e5f70736575646f3a4d4f4f4c494e4558146d656864692e62686140676d61696c2e636f6d000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714737e39e875eb0a9662e891cdb404830ad46eb5fc896e60670f658032c6914f08fab6f79d7b2ccf57": "0x00000000000000000000000000000000000e4a6f6162204e697761676162610000001b6e697761676162616a6f61623130303040676d61696c2e636f6d00000f404e697761676162614a6f616232000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047147396af96b1f453f59e826b5434525d00c118f3f6b0a29b7f432be7bbd18659d472c5f07298e76949": "0x04000000000200000000000000000000000000000000096d696368616c6973001b68747470733a2f2f6269742e6c792f6d696368616c69732d696e00176d696368616c69732e66724069636c6f75642e636f6d00000d406d696368616c69735f6672000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471473ba145c306b74dbccb16cd79f56a5405f9cdd0dcf58fcad90a18beb2398e77175d36ff52eb2cf3c": "0x00000000000000000000000000000000000f4b7573616d612048616d73746572000000186b7573616d6168616d7374657240676d61696c2e636f6d00000f404b7573616d6148616d73746572000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471473d68690216574fd6c6d70ef9d0c65d3371ed462bf273c97368bc1cf484d361ffc7e453f2eeef457": "0x00000000000000000000000000000000000000000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471473e46c80f9d62c235e8f1c9a2103345a007c30d9238d3ddde738792ca155c520ca3d5e6f71c11153": "0x0000000000000000000000000000000000073275326e32690b637269737379616e6e201868747470733a2f2f7777772e3275326e32692e636f6d2f0017637269737379616e6e33313340676d61696c2e636f6d00000e40637269737379616e6e333133000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471473e5d8ceda089f22283a608f6cd382190e64f646c648318ba0cef6e3177d31e0d7bd753ffc28e70b": "0x000000000000000000000000000000000005416c657800000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471473f4bcd1862aa772d67d4382c3093feb355d01710902f2e705a2ad23b41bd67a006f5e82137f1d58": "0x040500000002000000000000000000000000000000000744616e69656c000000146f6e6564616e69636840676d61696c2e636f6d0000114044566f726f74796e63653133333335000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471473fdff1bc4baf9bb02700d16339ef586cc2850916f3a1556ab9cc6ec0fc649b0dbda00eeaa3acb72": "0x000000000000000000000000000000000008486174746f72690000000000000c40486174746f72694e4654000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471474083880a0b640654a003aeae28534daddcc861d7d3e91b576683544217044cefcf4803ced1fbc69": "0x04000000000200000000000000000000000000000000086d617873616d340000000000000e404d756469745f5f4775707461000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714741fac12b13370280685555e8c1a13943f5c7702c73b2f447830c65030eaccc6b924eabd400cbd4f": "0x000000000000000000000000000000000007616d616c696b01010101000001000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714742651abfff8b63f6efa3511e9ccc0610b2002fefe0d71f5faefaf5b0cc88b07fef66b2b1cf2ac35": "0x00000000000000000000000000000000000000000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471474271bdfa6ae1a69da47518aa64a1ff00dd57c2ff1727281161e074938a18a6096b1babdbd7d1e06": "0x00000000000000000000000000000000000b52696368617232363834125269636172646f204865726e616e64657a1c68747470733a2f2f626c6f636b636861696e673939392e636f6d2f010100000c4072696368617232363834000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714742888be1295ba6bbaead6c7fb94fc60bece91d9847eec0b31d78bce6152066713100b34a839505b": "0x0000000000000000000000000000000000056552654c000000146572656c2e676f716240676d61696c2e636f6d0000094053746162316c30000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471474406008848ff57f0c82db2f36c07bfec5b0740ed71bbf04598091b6d37990d6bf84c959e3a4abff": "0x00000000000000000000000000000000000743726978757306436573617200184063657361726361737669643a6d61747269782e6f726716636573617263617376696440676d61696c2e636f6d00000d406365736172636173766964000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714744b3cf73bf091eabcd7eb9a65ba6073a4b69584560dac24856d42dd86c2626369f9e8cae4ff4746": "0x00000000000000000000000000000000000a4465657020426c756500000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471474559469cf43f4e2c4fcd7297103660b29d0123458798ecb8bdb13eecbc41a9c04530e9d13159f74": "0x00000000000000000000000000000000000830785041494e5a00000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714745d268c749fdfe7f456c1a72c215f5a9ca81bb0df28c94111eca509b92500b47c2b31f8bfc59d7a": "0x0000000000000000000000000000000000096b72616b61746f6100000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714746c4fe5893bfd45e09fc6d479ac74e565c808896aea76e5fdf7246342e37e353c5c94efb64b3f67": "0x00000000000000000000000000000000000653415459410000000000000e407673617479616e617665656e000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471474716d14814cef8d82f736294488b59a485d55f39a68754429437d762a2973da86c68a69dc70ab59": "0x00000000000000000000000000000000000b626f7265646b6e6565730000000000000c40626f7265646b6e656573000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047147475f3aac064f73442831969ffd0acbbf3f772b0456bf8efe1217f291efa8feb4e989f85afa43c33": "0x00000000000000000000000000000000000661727475630000000000000a4061727475635f6374000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047147486007852d722beb28d79f911d3438c510261d54ebf88c62527eb890a806c921fb67177d5cc2248": "0x04010000000200000000000000000000000000000000066c75313931000012406c753139313a6d61747269782e6f7267196c7531393173756273747261746540676d61696c2e636f6d00000000066c7531393100", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714749169ed52de2b9f4854e348f7dba33f64383ac0cb3cc067b4fca99fc2b72710cb78cc9c4e1bd343": "0x00000000000000000000000000000000001c4e49434b2753204b5553414d4120312028455854454e53494f4e2900000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047147499a373d4b2f70f8419a4ac409fa4e7bec032c696c526fac10ff9114d928df56ca0bf9e9ae29149": "0x04000000000200000000000000000000000000000000104d41415254454e207c204153544152000013406669657865723a6d61747269782e6f7267166d61617274656e4061737461722e6e6574776f726b00000b4068656e736b656e736d000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471474ae4b04f564e823e42dd6f52f63bcbaf33ac5fb58a55537539f1ed9f811c1341329e975c71a4930": "0x0000000000000000000000000000000000055376656e010101157a32363039353232373440676d61696c2e636f6d00000b40416c7269635376656e000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471474b0f64b9469490136260874c384616f8b5a95c2411b348c39fff27cce76cd42755d8d6fece3431b": "0x00000000000000000000000000000000000764636363757300000014646f6368656f6c4068616e6d61696c2e6e6574000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471474c050d87caa47647e4e0465c71777ec6af833a58cd011d79e25a7ff7c0a0dbdd7f8128f95bf2347": "0x00000000000000000000000000000000000a627261776e646f6a6f0e4272616e646f6e204d61636572000016626f626279736f7833323240676d61696c2e636f6d00000f40626c6f636b736272616e646f6e000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471474c0ebf8c6444329b22c3558e9004c7c046c943774f9f95a6459ade5b4aad4180d7159ebe4119a24": "0x00000000000000000000000000000000000c50696e6b204f72616e6765134b69746368656e7a6b7920262047726f6f6400001870696e6b65646f72616e67657340676d61696c2e636f6d00000f4070696e6b65646f72616e676573000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471474c3ae49c1416014a0afbe96d21f06c21f01a6e501750fe36c0e4697b8431fab6f94a558541b6446": "0x0000000000000000000000000000000000053230373500000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471474cc699b7926e3dd6a935bf6362c818dd3106b1b36b6ae8024e257a1a626ae763aa1b4858ad2a239": "0x0000000000000000000000000000000000054d4945530000000000000d406d696573746572696f7573000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471474d82617272f8f5c901a175702ec27245aa892dd1bcf5cbd174d3db6eac6768ca832fab149273429": "0x0000000000000000000000000000000000056d61747400000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471474d9203d38249c605c58ceb3d9af8f7088d7f2ae7496000c0d358cbecd774629a4f03e413497637c": "0x040000000002000000000000000000000000000000000662697432300000001461373931363032373640676d61696c2e636f6d000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471474e73ec4f7c76752d65d5c1484e5faf8ad32907ab729add8ffc2ffe0f29bc18015bec2c3f8ac7c66": "0x00000000000000000000000000000000000b4441524b464f5245535400000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471474e91f24b625d4c85eb083f19535ddfc1936497ce8db7b4dfb4af273000c4e2b9148077da9260547": "0x0400000000020000000000000000000000000000000008414d49522e454600001740616d69726b68616e65663a6d61747269782e6f726719616d6972656b626174616e69373540676d61696c2e636f6d00000c40655f616d69726b68616e000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471475229331a2dbb39412313fce4a12f0d70df33b7e34d5d4465c36287f220e43ea28005ac76322132f": "0x04000000000200000000000000000000000000000000084b726177696563000015406b7261776965632e3a6d61747269782e6f72671c6b7261776965632e76616c696461746f7240676d61696c2e636f6d00000f404b7261776965635f7374616b65000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471475257b58fe3742e82ca47b427122fbbfe8de659ddc23844cac97f091453869825c922079c350ac2b": "0x00000000000000000000000000000000000a506172617368696e730e766164796d206f6c69696e796b00001a766164696d73636f7270696f33313140676d61696c2e636f6d000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714752ce2fc0e55cd08ac33b989d0b4dd35d2fb8af4cd04cc5a3831e59023cb884044f5cda0541f1064": "0x040000000002000000000000000000000000000000000b4d61746843727970746f001c68747470733a2f2f7777772e6d6174682d63727970746f2e636f6d17406d61746863727970746f3a6d61747269782e6f7267116d61746863727970746f40696b2e6d65000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714753ac717444b23dd1cf3e5e0a3f8f198a63f5f7284fe493c23e88161d92d2cd418e52d050e3bd22b": "0x040000000002000000000000000000000000000000000ff09f8cb46a756e676c65f09f8cb4000014406d616e5f6375623a6d61747269782e6f726700000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714753bb535f9a5c087d4e6d6256f56677bcdbc0543f1a2c40aa82497b33af1748fc10113b1e2a1b460": "0x040000000002000000000000000000000000000000000f4c75636b794672696461792e696f000018406c75636b796672696461793a6d61747269782e6f726714696e666f406c75636b796672696461792e696f000011404c75636b794672696461794c616273000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714753d125c2bf217855867f9ad84580fdde5310bb3bc75271259aa2e8b2c2c98fc249fce382e1b3871": "0x040000000002000000000000000000000000000000000d506572666563742d6e6f646500001940706572666563742d6e6f64653a6d61747269782e6f7267146b6174656b7261737640676d61696c2e636f6d00000b406166696b736c697465000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047147550c5deabfe47ad2c1bc0240190ae1f8f11a721be76cd4b628e0ba46eb943bd040cdb4c93883513": "0x00000000000000000000000000000000000c4e65642052796572736f6e0c4e65642052796572736f6e010101000001000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047147551fa3a9029b0b45c8c6d9b15990f00bae2cb1ada580b4542762816af1644539183aa12906923d9": "0x00000000000000000000000000000000000101010101000001000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714755c80f8e6c4a211e0a847a82939b522cfc1e77ec7067dba177ea048e7241bb47415e867e1149d5b": "0x040000000002000000000000000000000000000000000a56616c69627269756d0000164076616c69627269756d3a6d61747269782e6f726718616c65787469636b6f7269736840676d61696c2e636f6d0000114046616c6c73456c6973653531383139000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471475682a0307a79151dc5097277a9b8a83b3886f07f7ea245f1f487de234aec097ea6ad84d2d71343e": "0x00000000000000000000000000000000000843484d522e494f0943484d522e494f201068747470733a2f2f63686d722e696f010d7468656d4063686d722e696f0000094063686d725f696f000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047147571a6ecb5a2dbf4548dcb6c3aabe041e7f7ee65af37818dc7ff1ff1a4300008100322c39e9c610b": "0x040000000002000000000000000000000000000000000c4d65726b6c657472696265001768747470733a2f2f4d65726b6c6574726962652e696f18406d65726b6c6574726962653a6d61747269782e6f726714696e666f406d65726b6c6574726962652e696f00000d404d65726b6c657472696265000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714758982f5e32232cc0a223d7867531f2390fd0eb3a2ba98d93ea437e2cd466997e2912a83ac278a01": "0x040000000002000000000000000000000000000000001062756c6c735f616e645f626561727300000012706570657065703832406d61696c2e7275000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471475a0d6509fc0241396a4d072a866d0159f05d71a556328aac66e6615a6317e3ef3e1ea8809bd211f": "0x040000000002000000000000000000000000000000000a6d63626561737465720000000000000e40647269736d65676973747573000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471475a38f0aede221241069369c13e300464594a119fec27d43ff2a939abed871a8fbc0e0610bf6736d": "0x00000000000000000000000000000000000a506f7368506572727900000019706f736870657272794070726f746f6e6d61696c2e636f6d00000c40506572727932506f7368000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471475ccfb98243b897452cadfbd70405e7a8fe22235a0d0eeaf7cffc9644b3a3ccd8b5177cbb56c3c57": "0x0400000000020000000000000000000000000000000009616e64657273656e00001940616e64657273656e303730373a6d61747269782e6f726718616e647265693037303730313140676d61696c2e636f6d00001040416e6472656930333334333837380010416e6472656930373037233131353900", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471475cdc28c14a9cc2afa39f29d6a982110baf95aa0df5ea004d5bd47384487c755bed36e36685caa39": "0x000000000000000000000000000000000007596f6f6c757500000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471475d0e8e1b508954d865adbf7513359dbe7c0a088bec21c757875053271f78b003f2442b42720dc31": "0x00000000000000000000000000000000000c44757374696e20204c65650b44757374696e204c65651768747470733a2f2f6269742e6c792f334f6d67517069001564757374696e4061737461722e6e6574776f726b00001140696d63727970746f687573746c6572000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471475df5a7f3c11bfadc2519ea66bb836e7ae7d3491feaa78a9f3ea413e94c386ab086580f208d31432": "0x00000000000000000000000000000000000a4c696564324865726f0e416e6472657720546f6d6c696e0000126177746d61696e40676d61696c2e636f6d00000b404c696564324865726f000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471475e1678efd9c765a8255ea05ae1ce1c34195681672bdb31e2b8bf9b5d39a3f22a84191d40953dd20": "0x0000000000000000000000000000000000064b75674d6f00000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471475e225b4667968a73461d66688269f501b405d7c0ffff6b767f705c5057a833d7ff7749cbfee384b": "0x00000000000000000000000000000000000f4d65746150617263656c2e636f6d0b4d65746150617263656c0f4d65746150617263656c2e636f6d000000000c404d65746150617263656c000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471475e3c5fb2fc81969a22ae2f665befd20682d417e794ee4836e534dab09632319e7e0fa66537cab16": "0x04000000000200000000000000000000000000000000124e65774f6d65676156616c696461746f720000154063656c726973656e3a6d61747269782e6f72671363656c726973656e40676d61696c2e636f6d00000b404e65774f6d65676135000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471475fc0cc738d3f7c5e8ceea4a5b67c6502a4d1da2b7f2c09498bb0584b6410d0dda3e242748635f4d": "0x0000000000000000000000000000000000054d6f4844054d6f686400001672617a6974616a3130313140676d61696c2e636f6d000009405370756e6b4d6f000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714761bdb16cf74a422cc1653dc9247ac12fc2c0dd939ef12fdadd7d244e74b0975be811e4843f35352": "0x00000000000000000000000000000000000476697109566963746f72696100001376697175652e767a40676d61696c2e636f6d000008407669715f767a000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714762278ddd7f9d2fe420ae612725091be044c1275af4ac86541f24a1848edb4c357b36b816839da09": "0x00000000000000000000000000000000001556616c656e74696e65204b69746368656e7a6b79002168747470733a2f2f696e7374616772616d2e636f6d2f6b69746368656e7a6b79001761656f6e7765626563616d6540676d61696c2e636f6d00000c406b69746368656e7a6b79000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471476436269fe98c06f8453d0ccb4af13c4b487ae02866867342e2fe6fe124c430824f583ddcb7e9e59": "0x00000000000000000000000000000000000d53616e676f2058616e676f201054616e6e6572204a61636f6273656e00001c74616e6e65726a61636f6273656e34303940676d61696c2e636f6d00000f4053616e676f3234393331363937000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471476552190c60e7f90a0495a650d73c54c563ad571868583a27e8b209f2f2f4cc31c67f332cc331769": "0x000000000000000000000000000000000003626400000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714765a1861cae96efbeaedc22b9e782d9d4d40aa5f1f3e4de97fb3268e30d0de993a03bc65359d8c1c": "0x00000000000000000000000000000000000a616e6e61206168686100147777772e616e6e617361676164696e2e636f6d0018616e6e612e7361676164696e6e40676d61696c2e636f6d000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714765f38af2758527ade93f42cc38c7609e349ca89bb1480dbd59541afc27c843526c5a3fde0fc8c37": "0x00000000000000000000000000000000000e3648414f53206f66506865656200000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047147661b26815a3370c9ef2c74b5a6820a16eb04205a9d177c4244a94cdcfe1275039ef8704480a3905": "0x040000000002000000000000000000000000000000000763796265724700001440786379626572673a6d61747269782e6f726712383876676b383840676d61696c2e636f6d00000f4076616479686f646c6572373737000c637962657247233438383900", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714767231bfd9d9921676d33240f4b328bb3536f2f5f43ecafbeb3694a7e25598d81bba69ce69506168": "0x00000000000000000000000000000000000a436865756b204e616d00000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047147680539dbbaf0658cecae006fbf10a81337d87455340ce6112b125a971482490e02d75a27bb2c33c": "0x04000000000200000000000000000000000000000000064561726e58000017406561726e787374616b653a6d61747269782e6f7267166561726e782e7374616b6540676d61696c2e636f6d00000c404561726e785374616b65000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047147698861f374eefe70ce1cdf8f0c7f65b38b034bbd62a2c51eb4f02bcf4ce6691c01ad2f50bb01841": "0x0000000000000000000000000000000000094d6f6b756a65616e0000000000000a406d6f6b756a65616e000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471476a3455700cb811448f31778f2cd7b542127a81c6399a5dc333c691cda16418ce9dcf2023d3b230a": "0x00000000000000000000000000000000000000000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471476ad7533e77fcf9ee4d08b1a297dde589fa652c4e340037e5108c7e7fd7fb94631e02cc5602e5a4f": "0x00000000000000000000000000000000000867616c6572617300000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471476c091a5cfc0b569cc10aff3a4e5cf2f467d1ebcff68b3a06d432ef8bad605064fc88866429b7000": "0x000000000000000000000000000000000005416c657812416c6578616e647265204c6f6d62617264010114616c6f6d626172643340676d61696c2e636f6d000001000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471476d10d82508ddae096e24e9b5ab82dc275b82318a52cebed1cae3e25be096d5f288229b256359e43": "0x040000000002000000000000000000000000000000000b537769737320506f6f6c0000000000000c4053776973735f506f6f6c000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471476d4bdfcc3fd9b0f169844782440a77d789ef60cf8b4dca2caaffbdaef8842105e401a6628aebe11": "0x0000000000000000000000000000000000134a65666665727920426c6f636b4d616b657201010101000001000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471476d8de28c15a8e696a51e7f4c64e59e468d49709561ab3d04062aebd5c0f297a491a8002f2a72250": "0x040100000002000000000000000000000000000000000a4a696d6d79204368750e436875204368756e204d696e671d68747470733a2f2f6d656469756d2e636f6d2f406a696d6d796368751f406a696d6d79636875303830373a6d61747269782e7061726974792e696f176a696d6d796368753038303740676d61696c2e636f6d00000f406a696d6d795f63687530383037000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471476eef4ee4756ace55c00bdb5472e548ff2126b45ee064c8dc4a28ec22bacedde0b94ec691ca5d648": "0x040000000002000000000000000000000000000000000c416c78203220737461736800000016616c6578657940766f796e6974736b69792e636f6d000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471476f257bc22f38143849b3cc4c3aa80841d99f834aeb0b204a65bf71c9ccd6577945e75188397554a": "0x0000000000000000000000000000000000096173656e7475726b0000001861686d65642e73656e7475726b40676d61696c2e636f6d00000a406173336e7475726b000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714772841a40326b32e5e7a3f7b33d6abe2f9510091af389384bb1ab14ab421c4b3bd6bcf795fd54873": "0x0000000000000000000000000000000000084e466d617263690000000000000c406d617263697061616e63000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714772b6dd134dbece18e428bc5c22f213b32118358403cf626ddeed283fa946889b5512e92eadd8a61": "0x00000000000000000000000000000000001359757269476969207c20524d524b2e6170700959757269204769691668747470733a2f2f7777772e726d726b2e6170702f0018797572692e6769726a616e736b6940726d726b2e61707000000a40797572695f676969000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047147736d72637ca5ab07af655360c0cf90fcb636adb5caa425cf3911b2707fa85a86ed8cf16e590d216": "0x00000000000000000000000000000000000a536572686920322e3000000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714773dee8f55ce5355f6354361a43b2ac461373d645f232de95222e5a067e4dfae25752e1f5a92c855": "0x00000000000000000000000000000000000a566c6164696d6972530101010100000f40566c6164696d6972535f627463000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714773f55df525fa6d534ea169f0bbf6ab861377b3e9cc34e52ffa3f1674f887b71b14b32404221b135": "0x040000000002000000000000000000000000000000000a73656279747a6130350000164073656279747a6130353a6d61747269782e6f72670000000b4073656279747a613035000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714774da64b663dd7d90eedf5b5991e93ca6682d493f8684926b6b63234410e1486ab77d2f32c0d997c": "0x000000000000000000000000000000000004676b320c4761746f724b6f72707332000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714774e798df2f721b6945e3aeeed6199fd8d6847051b2a2d934dc9829eedaa45cec70271e37403d050": "0x000000000000000000000000000000000010444543454e5420504152544e45525314446563656e7420506172746e657273204c74641868747470733a2f2f646563656e742e706172746e657273000000001040646563656e74706172746e657273000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047147775da760598d092885ba76f4524bc17e5b1bfa2a4adf9b232fb8fa878637d8a9a9fe9ab8de2db4d": "0x00000000000000000000000000000000000847616d6544414f00000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047147784c0640018c813102e184cab1726546391446bfb60b78b2fa78a927f7bf2bd4a734cfeb62c8909": "0x040100000002000000000000000000000000000000000d444953432d534f46542d31300e4469736320536f6674204c74641a68747470733a2f2f7777772e646973632d736f66742e636f6d154064697363736f66743a6d61747269782e6f72671876616c696461746f7240646973632d736f66742e636f6d00000e4044697363536f667457656233000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714778e5b823e917c204e1b7df1c25a717adfd14ac5b1c65729320a22679677aaa76a874481fb47e140": "0x0000000000000000000000000000000000054f7365720aed95b4eb8f8bec9db4000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471477a8f518e90d0d2cbe1c8831d018fed582688b5e75be3c9983ac1761fb24a916451c6999c0c66f5e": "0x00000000000000000000000000000000000a73796e636c75622d320a53796e636c75622d32000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471477aa5087f8d73da5f298ab8705f9d69a9955907f011b1d7eb853967859fcc6065deb0b2152f99b2f": "0x040000000002000000000000000000000000000000000a677265676f7269757300001b40677265676f7269757370657472693a6d61747269782e6f72671b677265676f72697573706574726940686f746d61696c2e636f6d000011406269616e6361696e74686563697479000967726567676c612e00", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471477ad80c392d951980a16d6fd4dc2954c449699e5f6e3c7d2f0dc64df5b8008135fd60eb3eac61e6f": "0x040000000002000000000000000000000000000000000c7733636f696e73202f20320c7733636f696e73202f2032000010696e666f407733636f696e732e696f00000c407733636f696e735f696f000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471477b2306d55618a8bdaf9e258248303362ed9d0b45920e6dc07a1bfafd053c4b7a345340fd4bd9357": "0x00000000000000000000000000000000000b77656e6d696e747369720b77656e6d696e747369720e6d6f7573652d64616f2e636f6d001577656e6d696e7473697240676d69616c2e636f6d00000c4077656e6d696e74736972000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471477b87309f6cae82ef455298acb3f8ea6f9d027b7c64a09fa48e70e793797ab0671a65fde287ef917": "0x0000000000000000000000000000000000115a657573205468652042756c6c646f6704524e44000014726e646c763230323140676d61696c2e636f6d000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471477ba939f01b84a579c498e54dc6d09282842bd6c3d6add63c626b0838149004d3fe55df18467424a": "0x00000000000000000000000000000000000f4b7573616d6120596f204d616d610000000000000b40686564766f7963657a000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471477e7c81b688e86ab38a7ddb36feebd8be00186f38273c7b9c0f3415d0dbcf9425af23baa7e86454e": "0x0000000000000000000000000000000000000000000000000f403038324b7573616d616b696e67000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471477ef359c63039c607a7a5f759444657faa370e0c7648ea82b7de38d94095646afa9889dff83a2b3b": "0x00000000000000000000000000000000000672313076340464616e00001364616e2e3130763440676d61696c2e636f6d000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471477fd1e387545e3290a84cc0f8014ad2583df5d2a0298128a8096160a1303b5700785e59acebe4f06": "0x000000000000000000000000000000000007503474746f6e00000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471478002396ad151eccf413237f470027cfdcbad3f3ec8a4bd0eeae013767ba226d4b8ed4e422e61f01": "0x00000000000000000000000000000000000f706f6c6b617263686e6f6d69637300000019617263686e6f6d6963734070726f746f6e6d61696c2e636800000c40617263686e6f6d696373000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047147803fd5293bb10b7f40a5105916d3b2e8d8dbc33dd65990b50002d116e41833ce2fa96c8619f7229": "0x0000000000000000000000000000000000065061756c420b5061756c204272617475010101000001000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714781495c979b2e4523a4ac0daf927a452ba14109b8e0c334aad8f0d2d2fe2605346eb14c4745f4f5b": "0x00000000000000000000000000000000000000000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471478255621fd0ac553544ff9f7dd373ef4057deaae18a4cac212e8ab6c3ddd696af9b6f945c1336e08": "0x0000000000000000000000000000000000094f6a6f6669726d650a4f6a6f204669726d650000136f6a6f6669726d6540676d61696c2e636f6d00000a406f6a6f6669726d65000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714782e7be4e56dc7e9ae963c00a7c164fce3f4a8ed94ba0a87e83cc1a7b192726836819cf1f63c522b": "0x0801000000020400000002000000000000000000000000000000001356616c6964436861696e73204b7573616d61001868747470733a2f2f76616c6964636861696e732e6e6574154063673135383335363a6d61747269782e6f72671668656c6c6f4076616c6964636861696e732e6e6574000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471478331d8cc49f0ef276f45a1045fe47a639befe802be7eeea599080222e2f45fba46492039609cc07": "0x040000000002000000000000000000000000000000000ff09f95b454555845444ff09f95b400001a407475785f696e5f74757865646f3a6d61747269782e6f72671774757865646f2d77686974654070726f746f6e2e6d65000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047147839058a91da35f1a263c8ff41827b72b0e7c7f2dddf460cf61bd57cabe37e1936ac5451452c8119": "0x00000000000000000000000000000000000e506f6c732061206c276572612000000017706f6c73616c65726140747574616e6f74612e636f6d00000b40706f6c73616c657261000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471478401030f0261c10a49deb88afa394b7eb478483a65a8c8f060b7de319dc6f65776a84d9e8f40e7e": "0x040000000002000000000000000000000000000000000e56414c4944414e44554d2e494f00001e4076616c6964616e64756d2e696f2e6c65653a6d61747269782e6f72671c76616c6964616e64756d2e696f2e6c656540676d61696c2e636f6d000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047147842c8fa2321f1331c8631eed8177ca1e36107697b82afdcdc5ca1a3221796e8e614f3a6fee09c3c": "0x040000000002000000000000000000000000000000000964616c6d61444f5400000018726f686974726168656c34383540676d61696c2e636f6d000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047147844550bde08fe13c40c37aeda337a3d84628534a349c778f4718fb9f6e6c5f0c9bdca2b5e44fd49": "0x00000000000000000000000000000000000d466c697061636164616272610e466c6970204163616461627261000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714785d8583e9b989bc9ca9b80f86dcc4755225a09c681b3f26f8726727be13e22edce6d9606f90c605": "0x00000000000000000000000000000000000e73686974697362696774696d650a44616e204261756572000015626175657264616e353340676d61696c2e636f6d00000f4073686974697362696774696d65000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047147866877cb9f3ebb8002112fe63749d3925cc0f36c9440450f21fe76c46a36e5b3343bf47d8c27400": "0x04000000000200000000000000000000000000000000054e696b300000144073616368696b303a6d61747269782e6f72671c73616368696b6f2e76616c696461746f7240676d61696c2e636f6d000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471478793b4db20d123c8e111a2e445cc0f64b5809496887b3130718d969db6637c0ebf1118c39b15c55": "0x040000000002000000000000000000000000000000000c7733636f696e73202f20310c7733636f696e73202f2031000010696e666f407733636f696e732e696f00000c407733636f696e735f696f000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047147883a128c175fcda5c7c138d8c7e2fa8a340509d00abee2e593ee159d44aaed005e6cd715fc3a962": "0x000000000000000000000000000000000005f09f908901010101000001000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714788ce32e00a517a71a6704e77a51c290fd77bc04c40e080df04cbe0d05c6153809e315bb6aba2f7c": "0x00000000000000000000000000000000000f53706163657273206d696e74657200000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471478a36b37e7c8a45b4c676770b34941cb7911f0ae00880839f51ad31da8c0eb3703b10f37e6ec461e": "0x000000000000000000000000000000000009417175615461696c00000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471478bdc0755cc0041a684d341d7bd4328296ef486454ae52c31e38b1420d509d66e34a473ce15c4914": "0x00000000000000000000000000000000000d56657865644f7374726963680000001756657865644f737472696368407961686f6f2e636f6d00000e4056657865644f737472696368000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471478db62c47c6f528d0a4713b1197cab2fc64ebc8f1f65b3c6d76a8e64d13d61a4e7e6d26018fbb8ab": "0x00000000000000000000000000000000000c474d6f724469652044414f00000011696e666f40676d6f726469652e636f6d00000a40476d4f724469655f000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471478dc64ae118a61a2b80adab283f96e115f1bcc05211dd11e75ffa4257dcc33cf704d019606094739": "0x0000000000000000000000000000000000066c75636961066c756369610e7068616c612e6e6574776f726b08406469656f683b00000007406965686575000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471478edf2d109908df4067f9883bbb39d48af456babb990409e10567c251c7237cb8709b56a7ec5786b": "0x00000000000000000000000000000000000963617272797765620d6b6920686f756e672068616e00001465636f2e6b6868616e40676d61696c2e636f6d000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471478fa03421f9ba61e726ef17b500f436cf596935acac782c71a423d35a959f3e6831f13c34db9d71d": "0x0800000000020100000006000000000000000000000000000000000a58796c6f44726f6e650000001978796c6f64726f6e654070726f746f6e6d61696c2e636f6d00000b4058796c6f44726f6e65000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714790543fc3e74b681e0f527663883fadc99963738cc81dd244d866241b296cb6d54596c296170534b": "0x00000000000000000000000000000000000f4573706163696f2043726970746f0f4573706163696f2043726970746f0000196162726168616d406573706163696f63726970746f2e696f00000f406573706163696f63726970746f000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714790d9013966da8e5aa586da0f7eb3da5b7ec7dfc89be91b6ec1ed7fd82aab54aebb6d71423080868": "0x0000000000000000000000000000000000087061736375696e00000011702e6272756e407061706572732e6368000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714792c8b74a404b20220e6f95ce6c0d08f1578ea375de14bbf04d449cf817c1b0b576edd00add11d5e": "0x000000000000000000000000000000000006426c696e6b0000000000000a404b534d426c696e6b000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714792db7b2b1e449a2d0c696806e3f6020040241eefddbbbb6ef5bf870f4c77feaac4775d26e7a662c": "0x04040000000100902f500900000000000000000000000000000000000000000000000000000009706f6c6b61646f74085472616c646f740000116a677472616c40676d61696c2e636f6d000008406a677472616c000a7472616c5f6c656c6500", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714792e04f3dda19263a61514d5cabf81b3f62650806870ad83b2e5059538b846b6dd9963e010566a17": "0x040000000002000000000000000000000000000000000a504f535448554d414e0a504f535448554d414e1b68747470733a2f2f706f737468756d616e2e6469676974616c2f204076616c696461746f725f706f737468756d616e3a6d61747269782e6f726719762e706f6e696d616a757368696a40676d61696c2e636f6d00000f40706f737468756d616e5f647673000f616e74726f706f636f736d69737400", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471479400eb594b6cde92ac4cde57f9b59d92a58b75a696fc7c8f23f63f0e507145f1d0ef3413a0a4255": "0x0000000000000000000000000000000000104e6962626c652062697473204b534d0c4e6962626c6520626974730000196e6962626c65626974732e61727440676d61696c2e636f6d00000d406e6962626c655f62697473000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714794c7db721956af68a56b1da8dc3f4bd58630c15f5754ee634528a007ab510c86a7e1fe6e62f4166": "0x040100000002000000000000000000000000000000000a414c46415354414b45001668747470733a2f2f616c66617374616b652e636f6d0010616c66617374616b6540706d2e6d6500000b40416c66615374616b65000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714795234d3f309d6d928806960ed2b5fe0085bf2a7119dfa7d5aafa82cd6a4c13ba365e6f60b351e2b": "0x00000000000000000000000000000000000d4a616e6973205069706172730d4a616e6973205069706172731f7777772e696e7374616772616d2e636f6d2f6a616e69737069706172732f0018706970617273666f726576657240676d61696c2e636f6d00000e407069706172735f6a616e6973000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471479585c82582ba5886c8f9ce90ef15bbb188d6b310bf351d0ab7db5b56ad0c612a2f59faef49ad307": "0x000000000000000000000000000000000009766f6c7465726f6e0d456463656c20426572696e6718766f6c7465726f6e2e61727473746174696f6e2e636f6d0017656463656c2e626572696e6740676d61696c2e636f6d00000c40766f6c7465726f6e3364000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714796a244fdb685192402f9f91c708b2f2bce4117ced908fcc3d2627b9f49cab6eda2aa0466800d90b": "0x040000000002000000000000000000000000000000000b4541524e535441534833001668747470733a2f2f6561726e73746173682e636f6d001367726f77406561726e73746173682e636f6d000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714798bc3485a0137f5de4a268c87586c0396cd8a46f0bcffd0229bd1075894df86d3c95193b27efc2e": "0x00000000000000000000000000000000000000000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714798f3d8958aea0ecce17aeb93e8c317b03168d3459ad0214f0ab47d844d7b22033b79d8e45508c04": "0x04000000000200000000000000000000000000000000154c6f6e67204e65636b2056616c69646174696f6e0000000000000a40626f6c696b617465000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471479ab4299c1df4149c2ed7fff877c4b79589f9716c09946592ff894a011fd5f462b3e0517f1bd562c": "0x0000000000000000000000000000000000174368616f73204269726473204172742053747564696f0000000000000c4042697264734368616f73000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471479bca3c1ed2e66e5daca1f54b717110efd2c4ddba6a4a2af7794a66a38bac564e2eb93a627bfec1a": "0x00000000000000000000000000000000000441737504417375010101000001000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471479e65a55eba330a3ba169058d0c44fb1c127201307004ea2f54930043ac06a7ee0fc6a2e2293b329": "0x00000000000000000000000000000000000749534142454c0000001a63727970746f737562694070726f746f6e6d61696c2e636f6d00000d40737573755f63727970746f000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471479f44e04fbf309e0e8ba1059e1e856708fda311f1e008afeff98f61978b96740f4b566bf29f32352": "0x00000000000000000000000000000000000a6d6f757365363439320968656c6c206e6168000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471479fd3f4b616af04ea62f28c78bc6e6f0fa30808f5c8f203a4881c77fb732a00089fde9ad87ded73d": "0x0000000000000000000000000000000000085348494b4f4241094164656d205a6f72000019706c616e6574616c6d616e61634069636c6f75642e636f6d000010405348494b4f42415348494b4f4241000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047147a0fd3be900ddd6b0a7ac5be69a8243f8880d5fd015b2e8f8f30ce6c7162f8bcb5ad1a1fa4246d32": "0x040100000002000000000000000000000000000000000b426c6f636b736861726410426c6f636b736861726420476d62481668747470733a2f2f626c6f636b73686172642e696f001468656c6c6f40626c6f636b73686172642e696f00000d40626c6f636b736861726431000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047147a246b025078730ed4fa8184e7ea69dbb3cbee71cfd7490803d457140d5d57d0e53a49a887bc4a06": "0x00000000000000000000000000000000000c6578706563746368616f73054769616e2168747470733a2f2f6c656e737465722e78797a2f752f65787063746368616f73011a65787063746368616f734070726f746f6e6d61696c2e636f6d00000c4065787063746368616f73000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047147a2939f6c5b0bc2542a463a7a8813a1272eb8605af0c83660ce65b57d3d5f85ffa5eeff31793ad21": "0x040100000002000000000000000000000000000000000a416374697661746f7200001a40616374697661746f726e6f64653a6d61747269782e6f726718416374697661746f726e6f646540676d61696c2e636f6d000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047147a3a19d147ea88111e0df3bee6fe15fd9bda70092476cf116506064e04aa9388bfb5cc95fe9a7836": "0x000000000000000000000000000000000007636861726c7903435200000000000b40435261796761737365000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047147a44a3d1b39b54493692082b41c6f2cad15ba58a7c962c2f435ec4e6638aedb2c851a90bd4f03f11": "0x040100000002000000000000000000000000000000001a6e2d667573652056616c696461746f722023312053746173680c6e2d6675736520476d62481668747470733a2f2f7777772e6e2d667573652e636f154076616e74686f6d653a6d61747269782e6f72671563727970746f2d6f7073406e2d667573652e636f000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047147a5bd17ec506c9c5d2365c4c6c0e812a77aabfb804bf75ece6c010669c21fcff48edf5208a3e3a63": "0x0000000000000000000000000000000000076b7573616d6100000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047147a87c1a545342f8db6f53125f95e71a35535efc16d86142bb9547ee9e24abc8e74fdcef0b078ce50": "0x00000000000000000000000000000000000864656e697378660644656e697301010100000a404446656c74616e6f000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047147a8cdcdb01c0984188e5872b9f167067f4643d21128ebcebd8a017e601055451432503af1703cd7a": "0x00000000000000000000000000000000000b487970657220436c75620000001a68797065726c6f636b6564636c756240676d61696c2e636f6d0000104048797065725f436c75625f6e6674000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047147a98a4b9eacb17aeaa77918b3029d54685efa54738d2dfb3a172cdddf800b7bb1189e1717220e472": "0x00000000000000000000000000000000000a496e65666661626c6501010101000001000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047147aab7b06334f0de4562ff43de6459fe64e03e965644c3ae5aa94d383c6eeeddfe96a85777d196603": "0x000000000000000000000000000000000005534841510553484151000011736861712e696e74406c6973742e727500000c40534841515f5457495454000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047147abcdd59281433e90a5cc2047a1215e4758a0cbfc07d10b287327c0929e780d7be8642874c4b7606": "0x00000000000000000000000000000000000a79615f616d61726f6b1159616e61204e65766f646e696368656b00001a79616e616e65766f646e696368656b40676d61696c2e636f6d00000c4079616e615f6e65766f64000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047147ac654eefb24124154af43ebc6cea9969e01ad1cdb66b1d82c291f1aab334cb3f854f67ad68a9a26": "0x00000000000000000000000000000000000c47686f7374204167656e740000000000000f4047686f73744167656e745f4f47000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047147afcd22bd458c5e66aa7f16d0ce7a6288dd1d2f1779fafb18d4c60ee78e89ab3dd3bc0979aad386e": "0x040000000002000000000000000000000000000000001b4d61726b65744163726f73732d426c6f636b4275696c6465727300001c406d61726b65746163726f73735f62623a6d61747269782e6f7267196d61726b65746163726f7373626240676d61696c2e636f6d000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047147b2722eb6380c719b4b2436a2db80368af17fb8a41e3895f3e1ae305d705eda24a60e20ee5055e02": "0x00000000000000000000000000000000000b457265626f73303530360000000000000c40657265626f7330353036000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047147b2a45dd87ad9b19a6ad826eb856ef28698449bf4103a10f62f5f20ed4604ea2c1c62068cb26200e": "0x00000000000000000000000000000000000006416c696e61000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047147b35d7021f4bbfded244ce5d458028ab10f9ba6eef01fda2953990aec9f433c2badd94d982918e0a": "0x000000000000000000000000000000000009444f546e4441534809444f546e4441534800001b646f746e64617368617274776f726b7340676d61696c2e636f6d000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047147b3c1c60afa16946d463b40af00de0a725978a340e77acec44981702cb83d3f6b7eba082effe333d": "0x040000000002000000000000000000000000000000000b4b534d2057616c6c65740000000000000c404554585f43727970746f000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047147b695b311c79a7fc5ab511f883a11f02c9af8054b409f4878f98b04f7cb9eba289b8a0297d79173c": "0x0000000000000000000000000000000000074c65737465720000000000000e406c5f776f6f64666f72657374000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047147b85696876ff480a6e72261b4e3c4405420177b2d56a579337eca2fb61e849a66ae35be7b0f0cf02": "0x04050000000200000000000000000000000000000000104b616e6973686b612052616a707574106b616e6973686b612072616a70757400001d6b616e6973686b613633393372616a70757440676d61696c2e636f6d00000c4b616e6973686b6152646a000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047147ba630360149afeb56e9233d9889e00e3c03f1cc20dd23c0dab8ea23e5b60fc423b0e631f2a19b47": "0x00000000000000000000000000000000000d434f4c4c41544f52532e494f001568747470733a2f2f636f6c6c61746f72732e696f0015636f6e7461637440636f6c6c61746f72732e696f00000d40436f6c6c61746f7273696f000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047147bb29bc9d1b02b887063da8fb9f496867aaed0e760ed9866ce51c4e91dd7e4a341f9af7086f08c34": "0x00000000000000000000000000000000000e5061772d6665637420506177730e5061772d66656374205061777300001770617774726169742e6e667440676d61696c2e636f6d0000104050617766656374506177734e4654000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047147bbbb302ea3c73fd6a1e7cf7558378809fa376f7eec7b065d30759f8a4e7b721ec2ae74b313f0855": "0x0400000000020000000000000000000000000000000015616e6472656974612d76616c696461746f722d3000001540616e6472656974613a6d61747269782e6f72671b616e64726561662e7370657a69616c6540676d61696c2e636f6d00001140616e64726561667370657a69616c65000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047147bc80f4306d5529f7a54e6a55c0453407909789a06c3ee6719f8735ac370d6f17dc342717fd76819": "0x040000000002000000000000000000000000000000000b5374616b6520506c7573000016407374616b65706c75733a6d61747269782e6f726713636f6e74616374407374616b652e706c7573000011405374616b65506c757343727970746f000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047147bd011e2b24427fd3ac61927f22210f94e610302612161d8b654db31a59babe728e48c3365313440": "0x000000000000000000000000000000000005426c6f6200000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047147bf2c0491ddcbed34e908afcf0fb6b394bd1a043bc8b226fac33b4742731b9cde5d324f450eb3006": "0x0400000000020000000000000000000000000000000018454c444f5241444f2d544543484e4f4c4f47592e6e6574002068747470733a2f2f656c646f7261646f2d746563686e6f6c6f67792e6e657415407061756c2d6769653a6d61747269782e6f72671d7061756c40656c646f7261646f2d746563686e6f6c6f67792e6e6574000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047147bf3bd886ed78f2a3e01274f4de899bd98847d7bb544371503102f4d5a201aae95187cb850f4ad2d": "0x00000000000000000000000000000000001072617269736b617465626f6172647301010101000001000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047147c042a4fb9dbabf496bb0203d41e1ba3170850ee862f64c451b09159d9344d10b641feed65d30162": "0x0000000000000000000000000000000000086d617263616d790000000000000a406d617263616d7931000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047147c1466766d8e06522ce1929ab903f695bdeeeb79a588774d71468362129136f1b7f7b31a32958f98": "0x040000000002000000000000000000000000000000000d696e636861696e776f726b7300127777772e696e636861696e2e776f726b7316406461667269636173683a6d61747269782e6f726716636f6e7461637440696e636861696e2e776f726b73000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047147c1a4ee18bd3983f5262b0fe348437cc140f47a9fd3818787fc5b72fdbf2a79693b599d464416f7d": "0x00000000000000000000000000000000000a426c61636b7374617200000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047147c1bddbb2e7b2b75a85040fb4858bb0af5be5d20833d58a0b093c35927090deed8a2a6ec8ca95d4b": "0x00000000000000000000000000000000000a506f6c6b614b696e6701010101000001000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047147c1f3ea8d8d889e4aa6716504b6e349996c6b7d6832a2103f48fcf53ead6a647a36af9eee8ad6733": "0x00000000000000000000000000000000000e46726964612047616c6c6572790853414e4354554d000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047147c24fdc8783352eda417107f4162f22d0f8d00f4d4498216cb35682c90240b59ef80a93d6018d520": "0x00000000000000000000000000000000000f506f6c6b61646f7420576f726c640f506f6c6b61646f7420576f726c640000167465616d40706f6c6b61646f74776f726c642e657300001040706f6c6b61646f745f776f726c64000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047147c2fabb1c3a36f8f280a78e265cd8a5274321bf5d0036e20ec9aa7e145667fce26f6e774c2516773": "0x00000000000000000000000000000000000c43727970746f4a6f65323300000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047147c35760e1493bdc39244b39ea5a40c289a1bae88df2aafb1c7024e53a8ba9924065aace7b5f17d1a": "0x0000000000000000000000000000000000096d61756e616b656100000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047147c36ab3c7817f712728ea7cd638962b92ec6405e7b5572b67cfbc96c7c2fc7becf4cddb22b50b02c": "0x00000000000000000000000000000000000e4e6163696f6e2043727970746f07416c657820470000176e6163696f6e63727970746f40676d61696c2e636f6d00000f406e6163696f6e5f63727970746f000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047147c379f62304c02a738bf717e43124f5679168a3ab1ef2490662f9b08508c5328786ea7c8fda2d72e": "0x00000000000000000000000000000000001242756c6c69736820e382ade38383e383890e444d20666f72206f666665727300000000000f4062756c6c6973687468656b6964000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047147c55d4e4996a81667670dd46299698281a6d0034fdd5484979f6f96ecb0f181e96442387fd1bf831": "0x00000000000000000000000000000000000b5346522053747564696f0000000000000d405346525f5f53747564696f000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047147c7bec710790ac95948ce1d407b5915c413f1b4813162a9782bacedbff9bf43844df10e5612a4d33": "0x0000000000000000000000000000000000046b6f7401010101000001000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047147c898863ee64a53fd0fcf4956cda58392e1602fa60d6bcb408356ad853287beaa4c33962b6440f20": "0x00000000000000000000000000000000000d72616e646f6d626973686f70001d68747470733a2f2f7777772e64617461736369656e63652e6172742f000000000e4072616e646f6d626973686f70000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047147c9b151305dcded7e26969331bf77ce04768009026a5362d51e5bccc12f788b8cda2a43ef218bd04": "0x040000000002000000000000000000000000000000001856462056616c6964696572756e6720f09f87a9f09f87aa001b68747470733a2f2f7777772e76616c6964696572756e672e63630017636f6e746163744076616c6964696572756e672e6363000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047147c9e204de64a64fe366850fd0d31d0261237699990f450e0b2cb41cfc4ec7b2ca6ebb7b0435d3654": "0x000000000000000000000000000000000005526f6d610f526f6d616e204368657265706f761f68747470733a2f2f726f617274692e61727473746174696f6e2e636f6d2f0013636865726f6d383140676d61696c2e636f6d00000e40526f6d613633323032343630000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047147cb3d8e166e9bea1044e495ecbfe9e4a4c436b753e3bd41b0249e45e7210ae7caa5e7bce20671e6d": "0x000000000000000000000000000000000009646170686f6d696e00000013646170686f6d696e40676d61696c2e636f6d00000a40646170686f6d696e000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047147cc6f5d138fccd7c32c57d0d50eea3e0561d15d28ffded023d7ea2489499d39ffd20c07bbbd11732": "0x000000000000000000000000000000000008486c616464696e0000000000000d40686c616464696e73616d61000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047147ccb553670cc1be59a9407f791aa5535102209c0d7c89f97f52f0f40b3091f672c5141aa11801f59": "0x00000000000000000000000000000000000a506176656c204b534d17506176656c204e696b6f6c616576204b72617374657600000000000e404b727573746576506176656c000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047147ce1a23eb5655e8050c8d2fdc12aabf21a31c0f6812cc0e7525597972ca0a37ab9bcef9f51650811": "0x040000000002000000000000000000000000000000000846524545444f4d00001b40636f6e6e65637465636f6e6f6d793a6d61747269782e6f72670000001040636f6e6e65637465636f6e6f6d79000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047147ce6fa220b1f0d1ba06446b3474c3d9dcfb759f3df134cf4b6620b2559c4e1b99d3be4d010378f40": "0x040000000002000000000000000000000000000000000a5354414b452d4f5053000011406876616c3a6d61747269782e6f7267147374616b65726f707340676d61696c2e636f6d00000a407374616b656f7073000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047147ce77bdfc2d91a1e54e20840d041d6626327c3ee6c0555e991b4e893e6b998f269bc85f1a7503f1a": "0x000000000000000000000000000000000006556e646572001968747470733a2f2f686f6c796368656573652e7370616365000000000f40556e6465726772617068696373000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047147d13ee9b5b531cc24ea378f0cd9285451e51e00c2e68851a57a36662990baa9226ab5c7734e05737": "0x0000000000000000000000000000000000065350414345054e4153411168747470733a2f2f6e6173612e676f76000e696e666f406e6173612e676f76000006404e415341000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047147d26f412c600f65a48745d28d9e9596ca41b7f7bcb03f874757f4f0716a7237e566662a6393bc125": "0x040000000002000000000000000000000000000000000852686f6d627573000000146b656c6d616e6d6d6540676d61696c2e636f6d000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047147d2dd084386fd77b18cf1686419c41dc5d3e76d373e3176c32c6d23c755fe1fc357f9c755ffc0019": "0x04000000000200000000000000000000000000000000075374616b696e000014406564776172646c3a6d61747269782e6f72671168656c6c6f407374616b696e2e636f6d000010405374616b696e4f6666696369616c000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047147d363e805ca7dc102e6dde560aa0f00b08d0db5e3c2f199181be3ca53d2e7a0a742aa5692433060d": "0x000000000000000000000000000000000010446553746f72655f4e6574776f726b214b6f747a7572204d6172696e6520496e647573747269657320507479204c74641968747470733a2f2f646573746f72652e6e6574776f726b2f19406a6f736961686b6f747a75723a6d61747269782e6f7267186a6f736961686b6f747a75723340676d61696c2e636f6d00001140646573746f72655f6e6574776f726b000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047147d3aabffb2e14c3d20dffa395a3019c0f32205ada0abe3d79389a209a7ec31e53ff55ebdeddff46d": "0x00000000000000000000000000000000000d466f756e646174696f6e2e5801010101000001000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047147d3c67d22eef172a8c20d46f86242eea89c400d5c478207e05c76bbab29a748af8aac90d627e1a01": "0x040100000002000000000000000000000000000000001256616c696461746f72732e4f6e6c696e65001b68747470733a2f2f76616c696461746f72732e6f6e6c696e652f000000000d4056616c696461746f72734f000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047147d411dcb862ed4531294b53cb96f295c8920789005ffe63ce3a3b02d8bd7591fdcac8cfd50ccae11": "0x00000000000000000000000000000000000c436f6c6c656374696f6e5a0000000000000c407261696e626f776e6674000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047147d44fe16767b62f23c52ad5876acd95595414a3e1c47afc410f9cc28db853b2f024dfec10d8bbd4f": "0x0400000000020000000000000000000000000000000016416e7469205374616b65205374616b6520436c7562001c68747470733a2f2f616e74697374616b652e6769746875622e696f001d616e74697374616b657374616b65636c756240676d61696c2e636f6d000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047147d4bc48ac25c63f1a68d2023d2a06f5042d7b2a268a330c38732d209b07bca2802ee241952235210": "0x000000000000000000000000000000000007436f74746f6e01010101000001000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047147d616786735a0c05f27568417dfb3873918d1e4316450de4e3af810622b72e9931863c31ed854f5a": "0x000000000000000000000000000000000015e284a2c39fc3b8c3b8c2b6c2abc3b8c3b8e284a200000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047147d647315c276b2ad56baa9b15ae335e108f3a6a84c2f6c8ddcea0a96477fefe9f5670a819802116b": "0x0000000000000000000000000000000000094269484f444c203100000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047147d6816787a83cc6cccb149c0e1f585be4511d6f942de360c39827f904cbdb9a8c572d580a8b95f0e": "0x040000000002000000000000000000000000000000000a736572676579303037000016407365726765793639363a6d61747269782e6f72671a706f7461706f76736572676569383640676d61696c2e636f6d00000a40736f6c73615f736100087373613131313200", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047147d73ff709d9ae6a4d53c9c6e61431448ceef1eb49542ddee942dd3d6c81c19d53efbab8acb02f00f": "0x0800000000020100000002000000000000000000000000000000000f426c6f636b7365656b65722e696f001768747470733a2f2f626c6f636b7365656b65722e696f1b40626c6f636b7365656b65722e696f3a6d61747269782e6f7267166b7573616d6140626c6f636b7365656b65722e696f00001040626c6f636b7365656b65725f696f000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047147d76b3fc859618eb1a41e8f79310cf5b804b038d19f28b535261fc5c1c3d1dcfdc49e6bf5a946d32": "0x04000000000200000000000000000000000000000000067a7a4265710000001466726f7a656e67756b40676d61696c2e636f6d000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047147d8fa5989cce248be07628deaa9c6fbbf2288f879396ff3566871c0dbce85c9e23764d15b810657f": "0x00000000000000000000000000000000001e44616564616c7573202d205374616b696e6720466163696c6974696573011f68747470733a2f2f7374616b696e67666163696c69746965732e636f6d2f001b696e666f407374616b696e67666163696c69746965732e636f6d00000c407374616b696e67666163000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047147da4d6e045faa8163a731ac0ae7375a2cce5b504484d91f1c49923b3425072e36e12b0afd5f2a857": "0x040100000002000000000000000000000000000000001542696e61727920486f6c64696e677320f09f92b01042696e61727920486f6c64696e67731d68747470733a2f2f7777772e62696e6172792e686f6c64696e67732f17407461636f747572746c653a6d61747269782e6f726715696e666f4062696e6172792e686f6c64696e67730000104062696e617279686f6c64696e6773000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047147db14798f78c92e409ed7dc92692f6d1b8bf5e71b68f9019a16f825e4eb71bb22c5bcbb9fec300d1": "0x040000000002000000000000000000000000000000000830786e3030627a0000144030786e3030627a3a6d61747269782e6f72670e30786e3030627a40706d2e6d65000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047147dc9a3488002e55b9ef65e3341a0a9e7e3b70c9af1ff1d6ee9e59567071bbf6f67940d5367532225": "0x00000000000000000000000000000000000c6c65616b65642d7a7330320c6c65616b65642d7a733032000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047147dd1665541d4746a38753d84c52f2cf326a92899fc7113242a46879511684ef558436b2ce95d8a7f": "0x04000000000100902f50090000000000000000000000000000000000000000000000000000000b73697854686544617665001768747470733a2f2f736978746865646176652e6d652f124068657866663a6d61747269782e6f7267127369784063727970746f6374662e6f726700000c4073697854686544617665000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047147dfe17f3928dd74c88480d4bfa9c9e6e217df08b61134f96a9f1b78713d3c56540d865296e530e0d": "0x00000000000000000000000000000000000d4d72204d616363686961746f0000000000000f404b696e674d616363686961746f000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047147e1d98e7b551be5a30fd1beaa72357f61ba1fe7e90aa8c5080fcd49b2c82e1b8315bcd9a223cbe41": "0x0400000000020000000000000000000000000000000014f09f909d2043525950544f424545532e58595a0000164063727970746f6265653a6d61747269782e6f72671e63727970746f2e6265657a7761784070726f746f6e6d61696c2e636f6d000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047147e2263555f112d23e0b27830a257252988efa5bf9d223ece5ce9eb120abe621bf5423deb2c3a8c67": "0x00000000000000000000000000000000000c496d6167696e6163696f6e00000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047147e5233edbec5e2e006e6492fc1524f365b7045cc047a7ecf6c1c2e147081f41b851219e4b1c5c245": "0x000000000000000000000000000000000009417374757254696301010101000001000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047147e550986ce912ea7305fe17c669dd937d1ed23df884dafef2d92b970bcb8f043ab297a3ed8a2ab01": "0x00000000000000000000000000000000000a496e66696e6974456400000019656464795f6a61636f62733440686f746d61696c2e636f6d000011404564776172644a3838313236303637000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047147e5d5a07a968882aa81126ca612e86be5e697a772a636776495ebc044916218a1286f9031ab7c038": "0x000000000000000000000000000000000006525c44656306526f6d616e000017726f6d616e706f646f6c736b40676d61696c2e636f6d000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047147e5dd4c385ce0fd8a810d21a048615e37979f5c5e4f8ec80853dcd1d961bf8c1a5d4048d034d151e": "0x000000000000000000000000000000000003585801010101000009404e465462795858000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047147e869f600c42271970b2d516a4815cecf618133b7987a8362995b78ae48035a1643e4bce5ccc5d3f": "0x0000000000000000000000000000000000096a617a7a6c6f737400000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047147ebcb68d19e2cb6d2ea8c3fc9696643972bb4d9af28b01fe9a7105b4530b337cbc31a2d3896b7025": "0x00000000000000000000000000000000000773616b614d75001e68747470733a2f2f646973636f72642e67672f7a71746d735932637758001573616b616d753230323240676d61696c2e636f6d00000c4062616467657262723073000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047147ecc461d41cccd863b7bd97ef2fbe878b2a978258f73697519dbf246e00514930f04daa24602b1aa": "0x000000000000000000000000000000000010e6b19fe58d97e4b880e69e9de88ab1047858780000067840782e78000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047147ece2f2beb48f825300255e8ee286bf5f0e90134d2d24b212b644b4da71d243ff1885f8d972bc23a": "0x00000000000000000000000000000000000101010101000001000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047147ed96b7d3f8a3e92083857fb5e068b7253110088fdc0431964252a7d2f46622d6b3cfc66be587c30": "0x0000000000000000000000000000000000085341544f53484900000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047147ee646bfe72c5b3abcac4380e7aa66426d530f0cb21bb82d67ae68ab51c86a20c87cd0cdc185da36": "0x0000000000000000000000000000000000095075796f5075796f00000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047147f34cefba02f9ae1b45943b4ed9825ec0f00a5d760c6fa50ac9cbe4f8d3aedcf807f8bf0bf6f5c0f": "0x000000000000000000000000000000000013536b794c616220436f72706f726174696f6e001868747470733a2f2f736b796c6162636f72702e6e65742f0017627573696e657373406b727970746f7666782e636f6d00000d40536b794c616273436f7270000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047147f3a10eaa5404047e2fc99f3a3ab840d9097da913d9516ca82943e0c61efcf1eef379ec46ed01f1c": "0x00000000000000000000000000000000000a486f6f6b65724e46540000000000000b40486f6f6b65724e4654000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047147f8c60eec0cc4d652827816806c65a098eef53ff0b47b7ae84b811119ffb96d519bbef1402e07b32": "0x00000000000000000000000000000000000000000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047147f9e55d7623ce6876ae93e7162785a77d3a2c0413a9ee04af1b948ba5df9ac191552b72e1dd49b71": "0x0000000000000000000000000000000000064372616e65000000000000094030786372616e65000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047147fa561eaceb076e25ad683920f3457b2599f4669eb42fdbea3b475b38f85fe6afd74203c6117ea1b": "0x0000000000000000000000000000000000204d495353494f4e20434f4e54524f4c207c20434f4d4d554e4954594e46203800000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047147fbcd6b06fe4b789aaf84aa2cb81d84aa9c578081a5f107723eac3fa3af95df8d72e025840ffeb71": "0x00000000000000000000000000000000000c4173686c6f73654b736d310f417368204c6f7365204b736d20310000166173686c6f7365406d61696c66656e63652e636f6d000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047147fe79549034d8b46a2e1685f62b2a1a996a2a1ba10ac6836c2b72174cab1bd1c6907454e6365fb70": "0x0000000000000000000000000000000000144b696e7473756769202f20496e7465726c61790e4b696e7473756769204c616273000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047147fe8792204e9c295d0f95f0b6b0f3784199f064eb87e6230aba869addbe2898705673d06385f1179": "0x00000000000000000000000000000000000e4375656e7461434f4e594b534d00000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047147fe9ee2c58e8b05db88f14766b6b332c755a2a08ffa22c4783a73ececa4062d64e24ff80c9165c5d": "0x040000000002000000000000000000000000000000000e49204c6f76652043726970746f0000001d63726970746f616c62657274627572676f7340676d61696c2e636f6d00000f40495f4c6f76655f43726970746f000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047147ffbd1415556c174eed8aa4c0f53370d2d6cea6c89603ba8155d80856e81ff4f45fc4eb4df8bd019": "0x00000000000000000000000000000000000b446172696162616e616e064461726961000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471480060d7753f9b8d6680f824acef4a0bcd554d24e911c75f8453f4979a433016d521023d625ad5706": "0x00000000000000000000000000000000000977336e3a206a696d064a616d65730000136a706f686172613740676d61696c2e636f6d00000d4053747261774861744a696d000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714803d5aecf59783b17628a5be63c4d3c8dbb96c2904b1a9682e02831a1af836c7efc808020b92fa63": "0x0400000000020000000000000000000000000000000006626b636872104261737469616e204bc3b663686572001140626b6368723a7061726974792e696f0f6b7573616d61406b6368722e646500000740626b636872000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471480463187525d27801c22d9c0275c636dbd1efaedf149337a591a85423be5ee06e0b459bd7db75c32": "0x0000000000000000000000000000000000000000000000000a405369725f506c7835000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471480728ec7d78ba2aa1cf7204d94b6e54fd231fddd65147458abc6350f084bb65d8417702c4d0c934f": "0x00000000000000000000000000000000000b70697462756c6c69736800000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047148079574f18bbad18449df0c2eb08117322b4037a5dfac6b84385228492b377a1b6871791f344f357": "0x00000000000000000000000000000000000000000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714808ebc416a42b5dad4dd0db36826124c944cd84245cec4db714bf5e22cd7354f06d855fb39e358ad": "0x040000000002000000000000000000000000000000000752616661656c0000124072616661656c3a70726976617a2e696f00000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471480997bddfac735ca6e92c07e2a51a497bd1b6d9769dc3dd9342184b22cd903ad5bcfb1f5df973918": "0x000000000000000000000000000000000008536f6c4d696e650000000000000b40535f6f6c5f4d696e65000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471480b33d9bdfb990d7ece16124407c7b88b0ef392c160d9ce49dc9f57d14ebf88ec1f5c0a8171d5a0a": "0x04000000000200000000000000000000000000000000055855414e000013407875616e39333a6d61747269782e6f72671b79616e676a696e677875616e6d61696c40676d61696c2e636f6d000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471480bb42a185021da0ee4ada127e6b71655f2b821dcef49b1b7a9c2c2533dd7bb686f6cf25d6a43c56": "0x00000000000000000000000000000000000f536f6e616c2042616e65726a656500000019736f6e616c2e62616e65726a696940676d61696c2e636f6d000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471480c30a7cda5adab606ee04dbe5970b2babe888f787f22e17da71ae752427427611a869f8a71f2a70": "0x00000000000000000000000000000000000f4d656d65636f696e20436861696e0d4d656d65636f696e2e78797a1b68747470733a2f2f6d656d65636f696e636861696e2e636f6d2f0000000010404d656d65636f696e436861696e5f000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471480c3b8a059192b8fe0b174435a2214def3b876b9c695b812cb5b4f58de2948b76abee22c98a45445": "0x0000000000000000000000000000000000095461616b7769747a0000000f7461616b7769747a40706d2e6d6500000a405461616b7769747a000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471480c4e0efde12fff3981467bc43c55319c70cde08e341fe0629c34bd92bf3fcc25d33e7f990c22466": "0x000000000000000000000000000000000013445220537472616e67652053747564696f730a4452206a756e696f721f6c696e6b74722e65652f4b7573616d615f42697264735f41636164656d79001c6472737472616e676573747564696f733040676d61696c2e636f6d000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471480e633d9b260415a7c504d6e49be15d262c72336d6cb5cb00c96471a168cf8bc5c9e5388d91be86b": "0x0000000000000000000000000000000000044d3244114d6174766979204d617473697075726100001d6d61747669792e6d6174736970757261313140676d61696c2e636f6d000010406d6174745f6d6174736970757261000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471480f72a77b66dd393b36020ebe1f4954611d109e2badcd2e8aa7e104f43dd3b09d728f187894a32f1": "0x0000000000000000000000000000000000205350414e49534820434f4e54454e542026204556454e545320424f554e54590000001a626f756e7479656e657370616e6f6c40676d61696c2e636f6d00001140426f756e7479656e657370616e6f6c000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714810a268051077a1deabf400732513443aec4f98d477ce3bea66725f271c496c8e52e7a6f5d6e2c4a": "0x040100000002000000000000000000000000000000000d444953432d534f46542d30350e4469736320536f6674204c74641a68747470733a2f2f7777772e646973632d736f66742e636f6d154064697363736f66743a6d61747269782e6f72671876616c696461746f7240646973632d736f66742e636f6d00000e4044697363536f667457656233000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714811067f8be6075ad60b5c072d3e0f45cfcb0fb99318f17c49fcc6bbbde23e392577a30d7bedd9f5b": "0x00000000000000000000000000000000000b506f6c6b612048617573001b68747470733a2f2f7777772e706f6c6b61686175732e636c75620000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471481325f28f848ffe9a411987e278e1a1883853fcfb029d8a17c08f44880bfe2492473744de632e830": "0x0000000000000000000000000000000000076b7573616d6100000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047148132e691730eba14b6b5cd171f242e060b0d16566e21961dec966e34cb5cc667b08923b248c07749": "0x00000000000000000000000000000000000d416c696e61204c6f73657661001f68747470733a2f2f6c696e6b74722e65652f416c696e615f4c6f73657661001668656c6c6f40616c696e616c6f736576612e636f6d00000e40616c696e615f6c6f73657661000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714813ba8ca144d6d26562427d438fcaac2c2be2b22bdec3d8c65b11048d013e77c0d4f21f7215a490a": "0x000000000000000000000000000000000006486f614c5800000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047148150bb2411acc76d1aee272e3633e036e6f22d4da4a65c844b515353161e8f7186b2c2e71e7b0a5f": "0x00000000000000000000000000000000001245636f4672616e6368697365732e636f6d0661646d696e1245636f4672616e6368697365732e636f6d001861646d696e4045636f4672616e6368697365732e636f6d000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714815938890f454d06be78a8a56ca63c88f3035d0dadea57cf12d42c7d8ef61795deec2dd98ca0393e": "0x00000000000000000000000000000000000f42696e616e63655f6b736d5f33340f62696e616e63655f6b736d5f3334000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714815a863bd5bac191942f56470b01e3fb44288e85a90be6bacff225537a556eac4c61f25930284b66": "0x0000000000000000000000000000000000114361205465747261206f66506865656200000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471481644b5c9a9a13e69a9ebf1328e64aac1cf749436ec602945693a088d0ffb823da08dff6bc4fd739": "0x040200000002000000000000000000000000000000000c52554259e2808bf09f928e00001240746174616e3a6d61747269782e6f7267166b7573616d612e6e6f646540676d61696c2e636f6d000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714816714a6c487ab8b56495460066a5fab4be4b0634c41f0e550f4f3e4d3436924364ce98d8678372d": "0x040000000002000000000000000000000000000000000a4578747261436f696e0000104079726e3a6d61747269782e6f7267187961726f6e736b694070726f746f6e6d61696c2e636f6d00000c406578747261636f696e5f000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047148173fc75c8868e7434c4c671dc3f4b52d14b36134e3ab9cb71580ad6130331b0e16aacecec396e75": "0x00000000000000000000000000000000000f6172696e61736d69726e6f7676610f4172696e6120536d69726e6f76610000196172696e61736d69726e6f76766140676d61696c2e636f6d000010406172696e61736d69726e6f767661000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714818371d947b2dfe99e6f2c2051af39eb875189cb0584c88f9979e8a11e196fd709788bdc360bb303": "0x00000000000000000000000000000000000000000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471481a8aa27b7c69abc7c7d2fe83c4af79c49136f0f8c5f1a00cd8d0aa91c94fe74d0145cb96d688f66": "0x0401000000020000000000000000000000000000000009454d4d414e55454c0000001864656d62756f6e67616374726f40676d61696c2e636f6d000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471481ca6b2d789063a60c57c0853ddd25eba3342516d472dc386718377fd76df4485eeb60a105ac7055": "0x000000000000000000000000000000000017526f79616c20536f6369657479206f66204368616f7317526f79616c20536f6369657479206f66204368616f732068747470733a2f2f726f79616c736f63696574796f666368616f732e636f6d001e6368616f7340726f79616c736f63696574796f666368616f732e636f6d00000f40726f79616c736f666368616f73000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471481d06e4180e1ea3d46783c52055cd65e6c7b0cc7ffe525be5bd41a30837c25cd5f061802c1ff9707": "0x00000000000000000000000000000000000943727970746f42691041726979612042616e6f6d796f6e6700001a61726979612e62616e6f6d796f6e6740676d61696c2e636f6d00000a4062695f6172697961000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471481d88cd163efe288face4e155edc11a8a64d04d35885b5b9189172fb4c225a9c4c3ad2997a699121": "0x0000000000000000000000000000000000175468652059656c6c6f77204775792050726f6a6563740d5068696c697070204b75727a00001c7068696c6970702e6b75727a4070726f746f6e6d61696c2e636f6d00000d406b75727a65747765657473000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471481d8e79920233c8de01eae270edb18124aa8bd49e3eca870f25497795d1843e2bbe21ed2808cef20": "0x0000000000000000000000000000000000084b756a696e6e200c4b756a696e6e20526d726b0000166b7573616d61646a696e6e40676d61696c2e636f6d000009404b756a696e6e52000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471481e1f270e2e851570e7aaf6634a1bec0cd73d40e2a69c31d160cd76f4dc3d06ceb3ed1bc58636e3a": "0x0000000000000000000000000000000000074e6f76757358000000166e6f76757378617669657240676d61696c2e636f6d00000b405370616365426f6279000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471482175dad66ffb1f228f8214ba1b29fbf1d1a0a45f760803cf6539ef1b1739b05019e017b85987a24": "0x00000000000000000000000000000000000a4a6f686e204c756b6500000018696e666f2e6a6f686e6c756b6540676d61696c2e636f6d00000e406c6f76656a6f686e6c756b65000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471482177f02309c6644de455bc9951b3280b717735762428896bcc146adba12c9e4dd2c4a1316f95432": "0x00000000000000000000000000000000000000000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047148218a521e794df69d80d984a8b722fa16d8b8b5d39b18a3074a8d57450f44a072f3bf27f3602ee10": "0x000000000000000000000000000000000009637665746f6d6d790000000000000a40637665746f6d6d79000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714823f88e31299deaa7c7546e35503a5716aadd49f18be0bf4e04e65db300e0d9822fd7f2a935c1d12": "0x0000000000000000000000000000000000076b404e61727900000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714824e4641808c73d2acb9eb46f872884c2b988d65fe151ce9ca720b9fed0bb3831861429e25bb7853": "0x0000000000000000000000000000000000054d4f4f4e00000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471482560819c55b16b2badd9daa2bcd66e001195e14fe7c6d176a7295734db2f46f05d7d4d38a097922": "0x0000000000000000000000000000000000084b686e656d7564001d68747470733a2f2f74696e7975726c2e636f6d2f327038656d6e753700196b656e6e79406b686e656d7564706f74746572792e636f6d00000e404b656e7a69654279726e6536000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471482a2945d18dc6de7685dc052a755ac3cecc0b0bd0d1405ade433d8463a3cabc1e5b7eedb13c08871": "0x08000000000100902f50090000000000000000000000040000000200000000000000000000000000000000064c65696d691752c3a96d79204269656e2042616f20506572657474691968747470733a2f2f7777772e6c6974656e7472792e636f6d001272656d79406c6974656e7472792e636f6d00000a407365787964656669000a52656d79233632373700", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471482a6377e5035d73b20e9d154939a016638b30c2015296620adc11207fbe0901296b53556efa4c81d": "0x00000000000000000000000000000000000c53686164794261646765720000184073686164796261646765723a6d61747269782e6f726700000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471482b8bce0892920f9ca3d904d81a1b1ba11bd6e391daa897b907ff89c5c5aebfe6f2da23292b8500f": "0x00000000000000000000000000000000000d5765796c616e645f46756e6400000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471482cc12483eced9790ede38c79ca874b40d63470229ef2d0de1453af484ec71f8af099bb3a37d7760": "0x00000000000000000000000000000000000f706f6c6b615f6b725f737461736800000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471482de5a96dc46220438036dd1fdee37c36c5a5718bda359f3c5eafb47cccbc1b47663b15c42e93879": "0x00000000000000000000000000000000000f526f626572745f476c6561736f6e0000000000001040726f626572745f676c6561736f6e000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471482f1848eaab32c01981dc5e72874e0606777ffff70cdd6f1f551a858a8f4bd2c25f06e3ea778fb17": "0x00000000000000000000000000000000000d74656964652d7061796f757400000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471482f289336c02a916220db94b831a3cd2a856fb540018c949b64ac01c0f3b2a8610be43f862a70b49": "0x00000000000000000000000000000000000f42494e414e43455f4b534d5f353000000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471482f319a69e3c81ac408d7f8ce355d1566fc9f796813bb4d3b09ae84279232b2349a1c1ec3f0df45c": "0x00000000000000000000000000000000000000000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714830a08ce1ea6aec346e3b7019bc2b1958609cab353fc3ff67417ea982a84fd43f8161b3b1f1de82c": "0x000000000000000000000000000000000008416e696d61726112416e696d6172615f65636f73797374656d1b7777772e616e696d61726165636f73797374656d2e776f726c64001b416e696d61726165636f73797374656d40676d61696c2e636f6d00000f40416e696d6172615f776f726c64000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714832b1944308e1804da331189f1e7a7a6055dab543cffddfe90888044d75791cfcc13fc02e5841664": "0x00000000000000000000000000000000000000000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047148337944019a68ea6a6500e450888dd3758b301a0f99d433264362547ca7d0f7631ea53871aa3be35": "0x0000000000000000000000000000000000094f4e454352595054000015406f6e6563727970743a6d61747269782e6f726711726f6f74406f6e6563727970742e696f00000b406f6e65637279707432000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471483731d75f677cc39943c8d0909cfa78a882249bd5d6aa9bc1abaa7ececfc470c6b0d2f8021f67b6f": "0x040100000002000000000000000000000000000000000a44726f696473697a650a44726f696473697a651668747470733a2f2f64726f696473697a652e636f6d0015796f676573684064726f696473697a652e636f6d000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047148378b2a58db8f57d444f83d9012f64dc4acd741cd22442e129a0c5d51e3fc88df1b464afe3dedf58": "0x000000000000000000000000000000000004526f6104526f610000157273616c64697661726640676d61696c2e636f6d000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471483932c1bdd63f4dd081159bf1cae87c5c026fb0fa008306db2b21d3a742b9da2508d44cb6e126955": "0x00000000000000000000000000000000000b456e64616e676572656400000017656e64616e6765726564626b40676d61696c2e636f6d00000e40656e64616e6765726564626b000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471483a221c8bc0e6066b2ed7a9394d1ed621c2e4200faed7ba856fbc722aa34996055b414d8517e712d": "0x0000000000000000000000000000000000064d6f797a610e4d696368616c204d6f6a7a69731c68747470733a2f2f6d656469756d2e636f6d2f406d6f6a7961383100116d6f6a7a6973407961686f6f2e636f6d00000f406b7573616c616d616e64657273000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471483ad6aeb3e5890e926090dc5275e53b65763f135108a9111289aa1ca6331a8ddb3440059cd33d75f": "0x000000000000000000000000000000000009706f6c6b61646f7400000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471483af75dd98f115fdc8156333178110191fa71e2c2d85af3f15cf5e4fc191e7a30d14fa03ba4fae01": "0x00000000000000000000000000000000000765696666656c000000000000104065696666656c3533353138323938000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471483ce59511097e6b62add0af948eba3b1fcd5cacde1f6fcc70f11ef75056f88ca4d11dcc5b080220e": "0x040000000002000000000000000000000000000000002049204c6f76652043726970746f202d204865616420416d6261737361646f720000001e616c62657274706f6c6b61646f74737061696e40676d61696c2e636f6d00000f40495f4c6f76655f43726970746f000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471483e3a5f61f9aaf705e7bdc8f8fefc667401cc90e1415d74771543ba45903e763cfec39609e80c67e": "0x00000000000000000000000000000000000c6461706861726d612121210000000000000d406b7573616d616661726d61000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471483f89e0f584ff0b7f60f9b64ebf26b9487c65ada132908745572692aef7cd9c987daf8c9c0c2ff3a": "0x000000000000000000000000000000000012e29b93efb88f20526f6220e29b93efb88f12526f626572742048616265726d65696572001b407270686d656965723a6d61747269782e7061726974792e696f11726f62657274407061726974792e696f00000a407270686d65696572000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471483feead6a196ca7384d58485b197a76a478bc70cec24386d631d07789a3fcaa9f2caf559e6f1197b": "0x00000000000000000000000000000000000d446567656e5f6d6f6f6e65720000000000000e40446567656e5f6d6f6f6e6572000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714840925591fbe6a29706c68ab8f36287cae3a10a27b1572ba848aab662978427464f456f6e7644241": "0x00000000000000000000000000000000001430785461796c6f72202d204368616f7344414f0930785461796c6f721868747470733a2f2f7468654368616f7344414f2e636f6d001930785461796c6f72407468654368616f7344414f2e636f6d00000b4030785461796c6f725f000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047148414c4f8c9a8cf81640bab9edc54d75165f1924f25f8b979f6b290c1b884b4c5a706bdd25e35b576": "0x00000000000000000000000000000000000f42494e414e43455f4b534d5f343700000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714841c66ae33e977e77eb07fd02281d018a4c45bab914fc6e2a0f81620663b53ab62432ae62a07194d": "0x040000000002000000000000000000000000000000000b4b6f6272656461627265000017406b6f62726564616272653a6d61747269782e6f7267146b6f6272656461627265406c6976652e636f6d000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714841d45054add5366d228fd275f3f92e8b6ccc56a9437582dc59db70153ab33cdd77562661adda60f": "0x04000000000200000000000000000000000000000000174461726b7374617220e0a590204d756c616468617261000019406461726b73746172313938323a6d61747269782e6f72671c6461726b73746172313938324070726f746f6e6d61696c2e636f6d0000114044466f726b6c6573736e6174696f6e000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714842664827980e15e54faa9f0cc59a977e73147865791a9272cd4980db5ff2eee27096d34ff2fab69": "0x00000000000000000000000000000000000b4441524b464f5245535400000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471484424b39102122b2f0c8760979e133469c6c41786f59b4a7c7c6eccad05ee675b3751b83d0684652": "0x000000000000000000000000000000000007544d575349590000000000000b40544d57534959343230000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471484438c43a102074910f57ab33929e8e7dc1f97a59d3e21f67fc50bcc92b4237cfe909749d907d227": "0x00000000000000000000000000000000000d436f6d6d6f6e7765616c746817436f6d6d6f6e7765616c7468204c61627320496e632e1868747470733a2f2f636f6d6d6f6e7765616c74682e696d001668656c6c6f40636f6d6d6f6e7765616c74682e696d000010406869636f6d6d6f6e7765616c7468000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714849d9d404714c4e49827c3338307099b89b70abd3f743768f9e98fed36c9f8de5c23684ad4cf0939": "0x00000000000000000000000000000000000000000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471484bce6312eb819d778608868cc221644fb3de1b580e43c0365dcb7bdfc43730edcd0af67afd3e67a": "0x00000000000000000000000000000000000b78567373706f6c6f4878095961726f736c6176000017646f6c7a68656e6b6f5f79617240696e626f782e727500000a40767373706f6c6f68000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471484c01eafe8e77b497036fc2cc5a44e28d92392be9d9ef3420fe2755cd50ee4f6d6cfc2eaa5888e40": "0x04010000000200000000000000000000000000000000054572656e0c4572656e2059696c6d617a0014406572656e7361743a6d61747269782e6f7267186572656e79696c6d617a61636340676d61696c2e636f6d000011404572656e59696c3134383133383930000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471484ccbb22b59b800b7213534fb02c7638d8d7caf1f62b983225c5aa76b8c14d249f7a704b50ba850a": "0x040000000002000000000000000000000000000000000a4c696e6b2073776170000000156c696e6b6173777561704070726f746f6e2e6d65000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714852be0a8606681ce165cb5a983d875ff3fedd96cf02bbda58aab07f644bc61b896a69e65d7b92d54": "0x00000000000000000000000000000000000b4e696f6e205265616c6d000000146e696f6e7265616c6d40676d61696c2e636f6d00000c404e696f6e4465656d756e000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714852c1c067967d16ce0347fd9c9ad8e56eef3dd3bcb364273bccac7261212336b24fc87928021d426": "0x000000000000000000000000000000000004505050000000177065706174726963696f323040676d61696c2e636f6d000009404f637572617331000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047148549b7fd2bfcfdd9bc0525c374a8198f3288a0733918321dfc26532e253d94da3a6a27a4c3e31760": "0x00000000000000000000000000000000000a506f6c6b6148617573001b68747470733a2f2f7777772e706f6c6b61686175732e636c7562000000000b40706f6c6b6168617573000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047148583ceea4c5e9e7682be679b08a867b9b6e92189ffaf6fe921e50e38c5204ae46450705fa0f39878": "0x04010000000200000000000000000000000000000000134b6f6e7374616e74696e207032702e6f7267047032701068747470733a2f2f7032702e6f7267144063726561746f723a6d61747269782e6f72670000000a406c6f6d617368756b000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471485aa231dc6bbaf55949fc105e6f977a37d0d44fb4feabcd0933d87c1f2b2fad95da2bd979bda234d": "0x0000000000000000000000000000000000094e6963654769726c10456c656e6120556b687661746f7661000017686f6e657968656c656e323840676d61696c2e636f6d00000f4048656c656e3639323133393535000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471485d657f1acd3f2c92458c79f1b8d080257ba31830f364170c90b6b173be1832ebace48595d193b2b": "0x040000000002000000000000000000000000000000000e4272696768746c797374616b65001b68747470733a2f2f6272696768746c797374616b652e636f6d2f1a406272696768746c797374616b653a6d61747269782e6f7267157374616b696e6737706340676d61696c2e636f6d00000f406272696768746c797374616b65000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471485db7559145dd87f504320903e1423f2143971b828c16bde706c9649054a2dd6226f4a552cbd7c4d": "0x0000000000000000000000000000000000064b726f627900000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471485e316d89f98284006783fab54c44733401db93381ce95dbdf7f8cae198a3abd281961d104a6a542": "0x00000000000000000000000000000000000442656e00000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471485ed039d265a7ffaa0601b089848ea1f1071885870523f61923c1e6e8000f68ac1a0e03025a21d0f": "0x040000000002000000000000000000000000000000000d73616c656e6b6120f09f8cb80000144073616c656e6b613a6d61747269782e6f72671473616c656e6b61627940676d61696c2e636f6d00000b4073616c656e6b616279000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471485f67a71efa822abcc3c76905f804cc082bf0dfebda879f5f6c3d37c0139e3e03bef1ed935121620": "0x080000000002040000000100902f50090000000000000000000000000000000000000000000000000000001151554152545a20627920554e4951554514556e69717565204e6574776f726b204c74642e1f68747470733a2f2f756e697175652e6e6574776f726b2f71756172747a2f001568656c6c6f40756e697175652e6e6574776f726b00001140756e697175655f6e6674636861696e000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471485f7724f745447635aad391e69d2500ab8d5d6992b8e38cfd3a5937a5667757a875e29a4281f7546": "0x0000000000000000000000000000000000074275726e737900000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714860033e5e332e23d6a2bd95c44c00bcad3fef2f7226ad90b8b93c3c1b9679236d5abfdb39c895844": "0x040100000002000000000000000000000000000000000a456e636f696e74657216456e636f696e746572204173736f63696174696f6e1668747470733a2f2f656e636f696e7465722e6f72670013696e666f40656e636f696e7465722e6f726700000b40656e636f696e746572000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047148613e243ad5accda52a6c52dc82940a36fefd1474cc0778517bb1a56b7bda0e308b6c19152dd7510": "0x040400000002000000000000000000000000000000000b4f70656e537175617265002068747470733a2f2f7777772e6f70656e7371756172652e6e6574776f726b2f1840776c69796f6e6766656e673a6d61747269782e6f7267166869406f70656e7371756172652e6e6574776f726b00000d404f70656e7371756172654e000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714861d071872c198e2a24e701429baee3c80ed77ab46977c581f43c21ffb13c5a6580366b17d4acb74": "0x040000000002000000000000000000000000000000000e4775617264612057616c6c6574000013406775617264613a6d61747269782e6f7267136163636f756e7473406775617264612e636f00000e4047756172646157616c6c6574000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047148621671899b86161726ac63a0a6a700ad7e1178fef89a87620bbc152a19f74708defc7f08bbc6556": "0x040000000002000000000000000000000000000000000a426c6f636b4374726c00000019626c6f636b6374726c4070726f746f6e6d61696c2e636f6d000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047148641dd739c11a1441994df5bf0f44342b1719bfbb1561286bd81b6d84f577f55ef45fe7ad6f50e4a": "0x040100000002000000000000000000000000000000000d466f72626f6c6520f09f8ea00d466f72626f6c6520f09f8ea01468747470733a2f2f666f72626f6c652e636f6d16406b77756e7965756e673a6d61747269782e6f726711696e666f40666f72626f6c652e636f6d00000940666f72626f6c65000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471486672c8d8603d645de7fc70edbc29190008415c3b6122dc6390b738453c6f1213b59942b2b76e54a": "0x040100000001002ca07d510000000000000000000000000000000000000000000000000000000843757272656e741546696e436f2053657276696365732c20496e632e1568747470733a2f2f63757272656e742e636f6d2f1b4063757272656e742d63727970746f3a6d61747269782e6f72671363727970746f4063757272656e742e636f6d000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714867ef0c5910d039618b37b11994703df397ba3817e5a3005c8fc91487518d31093f96dc13f8eae7a": "0x00000000000000000000000000000000000e456c6973616b7572615f61727406456c697361000016456c6973616b757261323140676d61696c2e636f6d00000f40456c6973616b7572615f617274000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714867fc6e4929b002af04c95a6ac10a0db5af28ac44776f95949dd543f494f8b8787925c41fccf7e0f": "0x04000000000200000000000000000000000000000000074f4e54555045000015406876656c61796f733a6d61747269782e6f7267186876656c61796f734070726f746f6e6d61696c2e636f6d000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714868406635a107a77f4677f381984864892b8f2646e8474586b5739666db1061ec17e247f1256a73f": "0x040100000002000000000000000000000000000000000b4441564552414d49434f0000124064617665723a6d61747269782e6f7267156461766572616d69636f40676d61696c2e636f6d00000c406461766572616d69636f000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471486998e21ddb35f37688e785a232855035798ed3859b39323e0a889a0bc91433bb2b7491d7552b541": "0x040000000002000000000000000000000000000000000e4761627269656c204e756e6573000000196761627269656c407368696674666573746976616c2e6363000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714869d5132140a00b380971274db9eafa67a4e9baaacec073a76949d8ac63e804fdb71680d0b27d618": "0x00000000000000000000000000000000000f53756257616c6c6574204e4654730a53756257616c6c65741a68747470733a2f2f7777772e73756277616c6c65742e61707000146167656e744073756277616c6c65742e61707000000e4073756277616c6c6574617070000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471486a03b31f22c207f6607dc83a7fc1f33c13e978ee3527fdb2c908ae6b5c0d2dee81bf30a01808263": "0x00000000000000000000000000000000000c426f747469636577736b690010626f747469636577736b692e617274001b626f747469636577736b694070726f746f6e6d61696c2e636f6d00000d40626f747469636577736b69000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471486a0b39405083331c0df6f52cc5815bbc65e071936fd135fb972c5d2b08f03e4c9a06ab2ba6b446c": "0x000000000000000000000000000000000008566f78656c6c650101010100000e405375707261566f78656c6c65000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471486a3835ceaaa8d91649b3af5a44c0a5a69f905bdbe203eeaaf5dea0695d9d3e307139236f1e92439": "0x000000000000000000000000000000000011546865204b494c5420447265616d657200000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471486a7a7c4bbbdc511e35a5bb9f11f2d71940593c4ff87fba89a7ab269825da6282025c43bf0b4c07c": "0x040100000001005039278c0400000000000000000000000000000000000000000000000000001f54657374204163636f756e7420666f7220526567697374726172202331201a54657374206163636f756e74205265676973747261722023311a68747470733a2f2f7777772e657468696e636f72702e636f6d144063686576646f723a6d61747269782e6f72671a63686576646f722b7265677465737440676d61696c2e636f6d00000b40657468696e636f7270000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471486c0d84c17d8fc6ecef2e5dd707eece5bce1ba22a95b527945e78b6ea1a1bf953b8623e9ceba8f77": "0x04000000000100902f50090000000000000000000000000000000000000000000000000000001c436f6e74726f6c6c65724163636f756e74426c6f636b6f6e61757410426c6f636b6f6e61757420476d62481b68747470733a2f2f7777772e626c6f636b6f6e6175742e636f6d1b40626c6f636b6f6e6175745f636f6d3a6d61747269782e6f726717636f6e7461637440626c6f636b6f6e6175742e636f6d00001040626c6f636b6f6e6175745f636f6d0010626c6f636b6f6e617574233131393300", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471486e44a960bbce9b16064f216e5b0598fd04f234902e175fdff5f78ac58d24856189cf89772c7711b": "0x000000000000000000000000000000000015546865206372656174696f6e2073746174696f6e01010101000001000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471486e553fb01bfcb3d16f24ecfa07199b88f010d94f47864ace2c0357aa4f37898f85cb39992e2036d": "0x0400000000020000000000000000000000000000000009476f6c646d696e65000000176272656e64616e766163613640676d61696c2e636f6d000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471486e69567b2fc7d85a44fe0211e518d4a7e0d647cb66979cafcf322d3427972abf875d29c7c76d501": "0x040100000002000000000000000000000000000000000f44616e69656c204d6172696369631044616e696a656c204d6172696369631068747470733a2f2f776f73732e696f1140776f73733a6d61747269782e6f72670f64616e69656c40776f73732e696f00000940776f73735f696f000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471486e97071fc27afaf9cb3ce3a07b00735ce0f68793b5717985758dbbf1fbdc95bb293adccaf6aea58": "0x00000000000000000000000000000000000000000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471486fafe6b0ee9fc1c9070bd80051c026f2ad47a498257131f7897df07f9ac2e4850fc0594ffb7c16b": "0x000000000000000000000000000000000000001768747470733a2f2f6465636f6d3838382e7370616365000000000d4073686172795f6465636f6d000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714870976f0672085c5f8ff75032359f0de13264a134c3e88089cf6a2a31e5cf3cdfe405a4e272f0508": "0x040000000002000000000000000000000000000000000d547963686f204d61736975730000000000000e40547963686f5f4d6173697573000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714871588d7f6c0fdd3002f931bb0cf405212de02243756d8ff665710af7fb234bfb1a50bb78ae1327b": "0x040100000002000000000000000000000000000000000b52617669204b756d61720b52617669204b756d617200154069747372617669693a6d61747269782e6f726715697473796f757261766940676d61696c2e636f6d000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047148715cdd917100e492ecd4b1267030cbe7bc4c16f0686b668c3b2c4a63887c4b72ed7e61cdbba8e01": "0x00000000000000000000000000000000000d544845204249472042554c4c01010101000001000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047148729829bc3420b4a8ce5570a948cf1f53af41b9ca5e693e27db42957b5feebd496f294083c7b3334": "0x00000000000000000000000000000000000c426f68656d69612046616d13426f68656d69616e20436f6d6d756e697479147777772e626f68656d69612e67616c6c6572790015426f68656d696144414f40676d61696c2e636f6d00000c40426f68656d696146616d000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047148736623ab752230ee06552c57e6cb90fb36289f12641459616eaba6ac6e12bc8df5d27b4348df364": "0x00000000000000000000000000000000000c75387a7257614d3241504e00000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047148744f5b40dccd408f29b23662a19aafa105a3b29cc512bdf7be3d2d90b9ccdac7c5bde9f690d2d33": "0x0000000000000000000000000000000000024d01010101000001000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714874cbacaa0bc1cceea8e9d3cfedc8afec25785703681d424e6aba10b728927b89d87a3776b47ee32": "0x08000000000100902f500900000000000000000000000100000002000000000000000000000000000000000d506f6c6b61466f756e6472790d506f6c6b61466f756e6472791a68747470733a2f2f706f6c6b61666f756e6472792e636f6d2f0016696e666f40706f6c6b61666f756e6472792e636f6d00000e40706f6c6b61666f756e647279000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047148779102a034bee1fee548f8308101986802a4f7e713699b60754d59b3722a83e049d7f9b3669344b": "0x00000000000000000000000000000000000b506f6c6b61446f636b320b50697a7a61205061756c01010100000c40506f6c6b61446f636b32000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714877fd9ae533b076ca8e01f1cd734ef1c9342f84af2616fbc4294fa67a820b8ce979cac5e10aa985c": "0x040000000002000000000000000000000000000000000d4b7573616d61204c6c616d6100000011696e666f406c6c616d612e726f636b7300000d404b7573616d614c6c616d61000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471487843e0e467379078c79cbd600c63f0cc90b34e7301b7cef8c93f7a404cbacecab96901fe53d4640": "0x04000000000200000000000000000000000000000000084c6f67616e7467000014406c6f67616e74673a6d61747269782e6f72671a6372697374616c2e726f737369383840676d61696c2e636f6d000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471487984f82dcc0d15b4a99af57418d7b0845ef9c692352b5ca08f7372fe7bdf6ba27ab3ccb139ffff6": "0x00000000000000000000000000000000000000000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471487ac7128ed93fd445e50e6e8499b921414360c3da7de7ca78544e38412bb6dc313383aaceb7c2068": "0x040100000002000000000000000000000000000000000a5072656d6975726c790e5072656d6975726c79204fc39c1668747470733a2f2f7072656d6975726c792e696e2f0015636f6e74616374407072656d6975726c792e696e00000b407072656d6975726c79000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471487b8b4219b989155bc4eccf7ab63522ed3545f9285b79e804b0eabae2cc508814bfbe29e22138d66": "0x000000000000000000000000000000000008534d532044414f0c534d532044414f20494e430f7777772e736d7364616f2e6f726701010000094061647362657461000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471487f8d378447f4f51b8a038b439b411fb7c6cc2d7315292a3d1649601641cbbe0825ab7fa90ce3002": "0x040000000002000000000000000000000000000000000c46696e616e6365204163650000001661636566696e616e6365734070726f746f6e2e6d65000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471487fe49129143221da4cac89e333e01f3718e89b1058470f721310828c70466cc6d460fe321238056": "0x040100000002000000000000000000000000000000000f6534792d636f6e74726f6c6c6572000013406534792e696f3a6d61747269782e6f72670f737570706f7274406534792e696f00000740496f453479000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471487ff181aa5f0d72d7603df59789b7e57153ab9fab5615620d3ef95cf7843c106b726ea5792ac075e": "0x0000000000000000000000000000000000194761627269656c207c2050726f6f66206f66204368616f7300000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714880e0c74f6c4f133daf0bff384569f5b20a6e27845a8926b37049833628f90aaaf1011ea6b5bbe52": "0x0000000000000000000000000000000000144c495a415f534f46495f4e46545f524d524b320a4c697a615f536f6669000010696e666f637672406d61696c2e727500000940536f66694e6674000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714881da501afe93dbc7cc45be885cceb3872d32ccea9670b1fb11ef4fa8ceb7f261605f7bd4d9d8d76": "0x040000000002000000000000000000000000000000000101010101000001000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471488240c4b087c954670d3d29a5674c684a378005daa252a0bdfb4138054278df93a60061965ae1354": "0x00000000000000000000000000000000000a43726f77646c6f616e06417274757200000000000f4047726564647948616d73746572000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714882ce79ebcfdf17062834a84148dad7c319b78d0f511593e0a882b0b81815575d37ee06fce78d060": "0x00000000000000000000000000000000001345726963207c2050696e6b6e6f6465205431094572696320506f6800144065726963706f683a6d61747269782e6f726715657269632e706f684070696e6b6e6f64652e696f0000094065726963703068000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714885ebea0f5080b1300f53cf59ee4bae1fc47b5df521d48a3cc2d02d5c15fd5d3bfa3d6a4a2e6a576": "0x0400000000020000000000000000000000000000000015f09f909f426c756566696e2054756e61f09f909f00000013616e74756e40747574616e6f74612e636f6d000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714887069bc3f84e008c6fdd542b5fec95757cddb7f88df8c14fbc998ae30352528cd0745a21f893a3a": "0x00000000000000000000000000000000000f74696d65666f7261676f7269736d0101010100000a404a696d4a65743133000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047148876172ab0d0bba3f89b361ea400867da22fa6a069fdd840819fdc24fee6cc3763b6cf3a8a20246b": "0x040000000002000000000000000000000000000000000c4441524b2d4b5553414d41000019406461726b6c657373323030313a6d61747269782e6f7267196461726b6c65737363726970746f40676d61696c2e636f6d000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714888912dae0a7ddbc8268b1d9ea3f3e28439ba92ab93da4a2788b33c3a88b0b8ec776590d5a1ff87c": "0x00000000000000000000000000000000000c4d75636861205069657a6100000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471488a1a9c29731ee3b388fbc33e4adebe4c8296ddf2cf1dcea98d5bb98589cc4965547552ca6dfc215": "0x00000000000000000000000000000000000d436963616461207c204e435201010101000001000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471488a90a53149b04c1fc77c33ab2d50bfa2e62c53701209166f5fdd2afd44e3d9d613c2deb29a2056a": "0x00000000000000000000000000000000000f4f6e652052617720417274697374000000176f6e6572617761727469737440676d61696c2e636f6d000010406f6e655f7261775f617274697374000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471488d2cf1d33c430800ed87826ce11d92d5c738c002d2a0deadc05ede81c6c72d3d22f0bb6e87c274a": "0x000000000000000000000000000000000007546f6d73636f00000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471488de95e48f84c3689085297d964ea873a23b63151b4c82189c1314c31fda6f2d71f83133d0877c5c": "0x040000000002000000000000000000000000000000000c56616c69644f72616e6765001c68747470733a2f2f7777772e76616c69646f72616e67652e6e6574184076616c69646f72616e67653a6d61747269782e6f726715696e666f4076616c69646f72616e67652e6e6574000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471488f2bab6b4633034bee287e579da5137412f2c3bd4d5ae4c6a11c4c420e04261157e04842a2ea641": "0x04000000000200000000000000000000000000000000104b7573616d696361204461626963610000134062756c726f673a6d61747269782e6f72671f73766562697261642e7072697469736b6f76696340676d61696c2e636f6d000011404e69636b7953613338353130363434000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471488faf51e2f7bed7746ff2d3857b6622883201338ade0e84de95c9be1587b549bf185e802d29e251d": "0x00000000000000000000000000000000000f62696e616e63655f6b736d5f34330f62696e616e63655f6b736d5f3433000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471488ffc163fa9907f076f9c831b885b8f1a216a27064fa793733b162ee06afb502a8cdbc2ccd6cc536": "0x0400000000020000000000000000000000000000000009594a52656e7561640000001c796f76616e6e7972656e6175643634363140676d61696c2e636f6d00000e4052656e617564466562726573000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047148902cecf825f2867273e55ba58de0184bb96e5e691dcc9171ec58658d2b94c42c7e4ca7574f6a076": "0x0400000000020000000000000000000000000000000011e5a4a7e59684206461697a656e2e696f000013406461697a656e3a6d61747269782e6f72670f696e666f406461697a656e2e696f000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047148910f5da4fb5fea048e84bb42675b4208dca0a9a06e3e16dfb1820208d363ea473056b4fa280c46e": "0x00000000000000000000000000000000000d417065204379636c6f70732104494f4e2168747470733a2f2f64726976652e676f6f676c652e636f6d2f64726976652f66001466657261726938333940676d61696c2e636f6d00000d4050756e6b324d6f6e6b6579000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714891b91a049c68e2f8ac73a177aa1ca00ba0fbc44e7d16f9855419e45d6cd9f517a369b9cb39d3a7d": "0x000000000000000000000000000000000016496e697469616c576f726c6443726561746f72303216496e697469616c576f726c6443726561746f72303210696e697469616c776f726c642e696f001c726f6d695f6a6f6e657340696e697469616c776f726c642e6e657400001140496e697469616c576f726c644c6162000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047148954d9b6c7704b5c0a912cf4f0c7894598d81d26f2c24f6e5c2541f312462bb576593e9dc549146d": "0x040000000002000000000000000000000000000000001051757069642056616c696461746f7200001b40717570696476616c696461746f723a6d61747269782e6f726719717570696476616c696461746f7240676d61696c2e636f6d00001040717570696476616c696461746f72000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047148954f8409a1908282288acef72d15ccf97030a0972ba24d944aa27a3e545d9a3f3f5b4e8b613fa36": "0x00000000000000000000000000000000000c61727461726f756e646b731420202020206b617468696c2073696d70736f6e1f68747470733a2f2f6172746d6f6e64652e626c6f6773706f742e636f6d2f001661727461726f756e646b7340676d61696c2e636f6d00000d4061727461726f756e646b73000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047148962ad14faa948d9eae8d17c39cd028fc4e889f74dad887d007342d2e5f76502098e7eea42980217": "0x00000000000000000000000000000000000d646f75626c6520706f6c6b61001d68747470733a2f2f6d656469756d2e636f6d2f40696e666163654149000000000a40696e666163654169000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471489667e9959f3863058411145513d689314c9a37396cc497d2f3758a382634f82b2525ca6d01ddd56": "0x00000000000000000000000000000000000b4372697370536b6965730000000000000c404372697370536b696573000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047148977e9fa22acb7d0d67a205808a76c0dfa0a5a14159d8ed04e0992d31a0671df21a813a8d6ce9b46": "0x0000000000000000000000000000000000094e4654206b696e67010101186875796368756e672e7068616e40676d61696c2e636f6d000001000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047148980286a570d6ea48865342bccbb2d7592528a183ad9ca54e1738bf98dd7c64e96f4cadf4739542d": "0x00000000000000000000000000000000000c4d656e756d65726f7639330752757374656d00001252757374656d31373440756b722e6e6574000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047148980acab3e7bb9bb1035801fd00144e10a3933ed859f8236bbffb93a7ac515bab9f1ca53cbb3f776": "0x040100000002000000000000000000000000000000000b4a7573745f4c75757575000000166c75752e6b6f6461646f7440676d61696c2e636f6d00000c404a7573745f4c75757575000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047148997871f06793d390456840228e994122a2750c966571ca20d2456db20a7cb84603ed8e2d5503776": "0x040000000002000000000000000000000000000000000b4441524b464f5245535400000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714899d77357f66a9b3fe56e0dbbdfa9b2197616f3f093228bb9dedcf5677377f4bcce42e4d0bd16eb8": "0x040000000002000000000000000000000000000000000e446563656e7472615374616b6500001a40646563656e7472617374616b653a6d61747269782e6f726718646563656e7472617374616b6540676d61696c2e636f6d000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471489bf72beff341fae9c0504f521d79782f9f198212be1b14b7df0f55e8ba9042f618c6bfd6894d920": "0x00000000000000000000000000000000000e4b52494c4c5553545241544f5200207777772e696e7374616772616d2e636f6d2f6b72696c6c7573747261746f72000000000f406b72696c6c7573747261746f72000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471489df2e19e8562faa88f04758ca57f3a570499fbcb3d10a8d4c9e62662d23223ab5abd805521f2162": "0x00000000000000000000000000000000000e546865204c61737420446f646f01157777772e7468656c617374646f646f2e636c75620101000001000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471489e71b2f143062e5c849c094a957256b4928ed7df80cef4b0e07790ca93c4e35877d6b6c47fb9c40": "0x00000000000000000000000000000000000c4b7573616d615a696c6c610c4b7573616d615a696c6c611b68747470733a2f2f7777772e6b7573616d617a696c6c612e696f00166b7573616d617a696c6c6140676d61696c2e636f6d00000d404b7573616d615a696c6c61000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047148a120585308557016e4020d8682b80d1b7112894cc302ae29735fa311760fda4068d8137033e315e": "0x040000000002000000000000000000000000000000000b4d617373205374616b6500000019656d626965692e6e6574776f726b40676d61696c2e636f6d00000940456d626965695f000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047148a1f3ec68da119f752843653b3cce985caef494fa794e3d6338708ff4f137a3955b5bd18a1ee9d44": "0x0000000000000000000000000000000000094b454e4750454e47000000156b656e6770656e67323340676d61696c2e636f6d00000b406b656e6770656e6733000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047148a2418436ea9d5744af70f547e94688d2d6398f17ae4b7854b44d38afecadab4615efa4979b45255": "0x00000000000000000000000000000000000c426f6e6b204d617374657200000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047148a2830d3f9783449b4e279c9042ff410055903287d4cb86f1349b46190239e07698150980e763a71": "0x0000000000000000000000000000000000064372617a7900000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047148a3ad77ce069992b8e83d322ee3b892a90f8ac2cc90eae3bcf4470d69ce11f4697072a7ac7ccb508": "0x040100000002000000000000000000000000000000000c48616e6f6948696c746f6e0000184068616e6f6968696c746f6e3a6d61747269782e6f7267116761626138324079616e6465782e727500001140476164646166693630373139353234000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047148a44d9fb97a9cc4cca90f519f1fa8e69ddd6fa48de4810638bf87b35e59f323ab28cc0e28bc2a62c": "0x00000000000000000000000000000000000d43727970746f2053616d6173001d68747470733a2f2f7777772e63727970746f73616d61732e636f6d2f000000000d4043727970746f53616d6173000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047148a5aa20d3da45f2d029918eebbeb816c3ca22773264f55a58d81c327ab4000d721dc791db0c8c84e": "0x040000000002000000000000000000000000000000000b6775616e696e653235310000001a6775616e696e653235314070726f746f6e6d61696c2e636f6d000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047148a60668e56121433b0a60407efbd5ce5c071f4267495f8722ad56a6027906052604e2d7d08d36801": "0x08000000000201000000020000000000000000000000000000000011436f736d69632056616c696461746f7211436f736d69632056616c696461746f721d68747470733a2f2f636f736d696376616c696461746f722e636f6d2f0019696e666f40636f736d696376616c696461746f722e636f6d00001140436f736d696356616c696461746f72000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047148a729a52375051e3b44422085bc3088cb79fb9e865d030771c4d2f7babd6b61702d277a2cacf271b": "0x0000000000000000000000000000000000044c463500000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047148a7300288338c9b2327497753b33243d0ce0f0e0d4a4c6e102b628d0ca2f49d606cff851203ee36a": "0x0402000000020000000000000000000000000000000005494f534708494f53472056431068747470733a2f2f696f73672e766311406a6f63793a6d61747269782e6f72670e68656c6c6f40696f73672e766300000840494f53475643000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047148a74772b80aee66a9ea44891f615653c14d58dbad115753afab7339dbc4cdfc5870f19fd47204c7b": "0x040000000002000000000000000000000000000000000a626f726368656c6c6f00001440626f72697366663a6d61747269782e6f72671b626f7269732e662e6f6666696369616c40676d61696c2e636f6d00000e404246616b746f726f76696368000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047148a7ddcbe937a53aea001e095bd9798f3f8e46931b31953568f444bf4de6245a5cfb81781de277d73": "0x0000000000000000000000000000000000106372617a796d61676e756d2e65746800000000000010406372617a796d61676e756d455448000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047148a9080a29f48df317ee04c70647cade0a0bbd6de1b0d21b21136271cd571809e3c1c59424e3e5f59": "0x00000000000000000000000000000000000830784172696368000000000000094030784172696368000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047148aa02eef8fa57876de87313ed608e73b1c5a4fe34d2336ef43ca2d6d308ae2cc419b932b356a232c": "0x000000000000000000000000000000000001010101186b616e617269612e626972647340676d61696c2e636f6d000001000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047148abf00f6f189f2ef4a5668af20fe1f0033cd223536a501acc9d39d384513ed2a14d6f41ec28c074f": "0x000000000000000000000000000000000014566c74726156696f6c6574732053747564696f010101164b7573616d614475636b7a40676d61696c2e636f6d00000d404b7573616d614475636b7a000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047148ac021761134a4cb6844aff218212e05dff7200a70bffe6b560703ec7541bc47795d3d85c966c14f": "0x00000000000000000000000000000000000d4d6973747279616c5f444f5400000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047148ac96f5c2c35bba5c4eaf39cf3853472cb4ee6809d93108ef7e95284dd5eea32f12a5d1bd0239006": "0x0401000000020000000000000000000000000000000006422d72616410427261646c65792041204f6c736f6e000012627261646c6579407061726974792e696f00000c4062726f6c736f6e313031000e62616f6c736f6e39233337343800", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047148ae3f21bacbd9a75dc9869be31db55e4f23085f9d300c4dbd6f04c2dac9df98911305b183770b74e": "0x0400000000020000000000000000000000000000000011566972657320696e204e756d657269730000194076697265736e756d657269733a6d61747269782e6f726700000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047148af64018762abc4c8644cf1aa56904c194a54bdaf91cc42a95a65bd2e7a6845026d0ca135d430522": "0x040000000002000000000000000000000000000000000d4a61636b20467269656e64730000001a6a616371756573767269656e73363940676d61696c2e636f6d000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047148af7bd58a91d6470161254fa03e07813f5eec8b0f734a2976d33a06ea4b57e88d611179e8a8f8193": "0x00000000000000000000000000000000000a53494d554c4143524100000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047148afa4a7f5b70a3e0904168b519b2745aa1480867fbc7db364c79e03fafd6e30ccc1691e7214ef860": "0x0400000000020000000000000000000000000000000014f09f91a8e2808df09f9a8073706163656d616e0000184073706163656d616e3131363a6d61747269782e6f726700000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047148b089e201ac6d25e5e7030e312ba8dd8a9bbffda3d93b34a3ec8d2ff441845be5185e6e0eedcee7d": "0x0000000000000000000000000000000000134e4654f09f9791f09f94a56c616e6466696c104e6967656c20466f726e626572727900001e4e46546c616e6466696c6c61756374696f6e7340676d61696c2e636f6d000011404e465464756d707374657266697265000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047148b299234c2604004face99d3401cb9b45ee1bc0ec52f4cb35914dc5ad27806230534230eedb8413d": "0x040000000002000000000000000000000000000000000542494c4c0000164062696c6c3a776562332e666f756e646174696f6e1562696c6c40776562332e666f756e646174696f6e00000c4042696c6c4c61626f6f6e000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047148b72a01f273fec5b1ae6196e6d0656d7b2986e26c2265f462eeace67593da0fe87d1341b0e4ef001": "0x00000000000000000000000000000000000a41726368697669737400000016726f67616e61766572787540676d61696c2e636f6d00000b404c6f6b695061676573000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047148b99dd128482b33028ef38027a9dca274aa6ffb31e788468c1707dc9e1539164e4be048748244476": "0x00000000000000000000000000000000000b42617272616375646173001b68747470733a2f2f6c696e6b74722e65652f636c617967616e670017636c617967616e677374617240676d61696c2e636f6d00000d405f436c61795f47616e675f000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047148ba9eaa6ab907510383b9fdea1ee994d93bbacd6d67f7cda32fbe6d351d359c257b9e93d92eab75a": "0x0000000000000000000000000000000000114d65616e696e6766756c204d6f74657301010101000001000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047148bd5e851d3f0ece282ab24b11d8ce676a4ddb69f0a2d1a4990c73761bbea86ee509cd5f5af038c35": "0x00000000000000000000000000000000000a484420676172616765011768747470733a2f2f63727970746f2d6172742e65732f010100000e406e66745f6265686f6c646572000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047148bdc67657419bbeb22ce51e9b096db10638d2889c4a847781e0360f6fd3adffa6280107ef7260f62": "0x040000000002000000000000000000000000000000000d506f6c6b61646f742048756200000016706f6c6b61646f7468756240676d61696c2e636f6d00000d40706f6c6b61646f74687562000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047148bfc916011aac51348ffcdc60f24e9b546980dba143340f37be597cd0b6135eba9c87c4cb434a53d": "0x00000000000000000000000000000000000a43796265724e657264074265636b657200000000000b406a765f6265636b6572000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047148c1c29593b2d5db604c73bb4b37fd89e159ea8dda26c4021a4af572826ad6397d8fa9942c18b3568": "0x04010000000200000000000000000000000000000000094741544f544543480d4741544f54454348204c54441468747470733a2f2f6761746f746563682e756b15406761746f746563683a6d61747269782e6f726711696e666f406761746f746563682e756b00000d406761746f746563685f756b000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047148c24c3ef8bc4c3e412c0e71d326f83f4e6089448e147fdab51b0b7398a7d0cc9a88b0571432e7310": "0x0800000000020100000002000000000000000000000000000000000c5a7567204361706974616c001768747470733a2f2f7a75676361706974616c2e636f6d0017636f6e74616374407a75676361706974616c2e636f6d000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047148c3084898ad5f06e529c401186113eb29d37baf9cd8f00c62ab900c8f45587e224c70af5bc231f66": "0x00000000000000000000000000000000000a507572706c4e67687401010110707572706c6e67687440706d2e6d6500000b404e676874507572706c000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047148c36932cefb7a9ecb4caa4a0e94ce7de3a3b240421eae5ac497d3222dced621b09dc5b0790575538": "0x000000000000000000000000000000000013506c6173746963205268696e6f73204e46540000000000000f40706c61737469637268696e6f73000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047148c4a4a005c89c680fa7c443627d84ad0a74c4510d28d286ac0121c70a2a8191961f689957a625250": "0x00000000000000000000000000000000000a524d524b6e696e6a610000000000000b40524d524b6e696e6a61000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047148c818112f3226361ba19adf8ab8528c9f53058b494b6154dde0fadfe2bdeb3a9b9c87761cdcbb441": "0x00000000000000000000000000000000000000000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047148c8a104718f01d73d20463560bc0be7d6e5eb0c6f46ac13bbd2a52be9764eb0ea5664224d188b162": "0x040000000002000000000000000000000000000000000b4e6f436f43727970746f000017406e6f636f63727970746f3a6d61747269782e6f7267156e6f636f63727970746f40676d61696c2e636f6d000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047148cb3a38ac67409ba900d19dc7ddf1723c1b0ee589e54392ae66f4dfdc4e340813d3982ee3c444e4c": "0x00000000000000000000000000000000000b646565706f6c6f6769630b4a616e204b6f6c63616b1768747470733a2f2f646565706f6c6f6769632e636f6d0014696e666f40646565706f6c6f6769632e636f6d00000c40646565706f6c6f676963000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047148cbad522066132e614740e9f8ba7bc917ece78a0cf3ad3a59dc190a467983fc40b6e10d26df2424e": "0x00000000000000000000000000000000000d656e7665726d65697374657200000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047148cf331474cf8ca77789371e25daefddfe31380de2e849beae016eed32ef426bca684a87b2722b226": "0x0000000000000000000000000000000000127361746f7368695f646f7473616d6f746f00000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047148d136d7c7984d254da01077bdc025fd779cc21c9760727ec07e52aa132410b82e5fabacb6f45b055": "0x04000000000200000000000000000000000000000000064f4e44494e000012406f6e64696e3a6d61747269782e6f72670e6f6e64696e406969762e646576000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047148d15d9b9ba448549ceb2a7cee1fe704ef408c1025e5f70a508ce24d0d005b110bb8b92aee6729823": "0x0000000000000000000000000000000000065961796f6900000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047148d17af330f9b2c86badb27b0ea87f8b6de054d7ab764af17cfec0a00fa2d9d55ea6317a6202cad58": "0x000000000000000000000000000000000009626163636869737400000013626163636869737440676d61696c2e636f6d00000a406261636368697374000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047148d181a92494fefeeb2e15eb8b4fd587fb9d94c5345cbdfa949b059dd12653ebea1df1bc8c00a8d56": "0x0000000000000000000000000000000000046875650000000000000c6875653533363337373831000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047148d22092b65a0be40263e0e2220ee17f5e592687553243ef2cd9dc0f870e3bc8c5aa4759350c66f74": "0x000000000000000000000000000000000009536c617661506f650101010100000d40496e73706563746f72506f000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047148d27cb369656b59b3a2d7c5aa6f73b06dfc3f72288b99609976953f11ed014e38b63cc717e5d9e44": "0x000000000000000000000000000000000006736f6c617200000019736f6c617273797374656d6f6f6e40676d61696c2e636f6d00001040536f6c617273797374656d6f6f6e000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047148d4a0f8bd7262bf796b999767cece29bf12001df86d1355bea8fe46996aeb0ca149f309605794029": "0x00000000000000000000000000000000000f42494e414e43455f4b534d5f31370f42494e414e43455f4b534d5f3137000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047148d5f7ebde4f481a866f7b3f3db597d3032c2d767568aa550249c946600a61276910b9c1d21a93371": "0x0404000000020000000000000000000000000000000005534b454e00000018486f6f646965534b4070726f746f6e6d61696c2e636f6d00000d4063727970746f736b656e5f000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047148d8daac9c069e6c7f200d9578df25fafb6690614aa05052abc6ea28c886c52448f28c8fd1c2a2f2d": "0x000000000000000000000000000000000008576f6f6265656b1743726561746f72206f66204b7573616d616e617574731a7777772e696e7374616772616d2e636f6d2f776f6f6265656b001676617379617374617379614079616e6465782e727500000940776f6f6265656b000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047148d8e7baeef66b6391e9b88072c2f8b8c9b5c730d2b0a65589ba2df45ceb9fec58d35814b2ad5a719": "0x0000000000000000000000000000000000184f55544c4554204152542047414c4c45525920494e432e0000001f73616c65732e61727467616c6c6572792e696e6340676d61696c2e636f6d000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047148d8ff74133df57ac367801ab22817ca7c25117923cdd6c62889a01c2bf01683cea29e279d14e3e48": "0x0000000000000000000000000000000000094269484f444c203200000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047148d901b92205a25ebbea06e6ad606b2a80822a72aaae84a9a80bec27f1beef1880ad4970b72227601": "0x0000000000000000000000000000000000157061726974792d7374616b696e672d6d696e657200000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047148db172d8f1d1e04ea246cf4986a146aec95dd8a3670e957aa3f0cbfd70583be5b2e1c0ff7992a36d": "0x00000000000000000000000000000000000f616e616d656c657373666f726365045f5f5f177777772e616e616d656c657373666f7263652e636f6d001c7370656369616c6167656e74736576656e40676d61696c2e636f6d00001040616e616d656c657373666f726365000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047148dbef89e3ac0f0aad86c1cbcda487cd9e31a5e37b2836ebc1c3b3d86b2cd7596da91fae58e876b24": "0x00000000000000000000000000000000000000000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047148ddffc86aaebc2d41e5c61cb6941b247d22fa14392fb8710a23493db5857c2904a76b3bcfda7d217": "0x0400000000020000000000000000000000000000000018576562332065647520616e6420696e766573746d656e740000001261686a7863727a40676d61696c2e636f6d0000094063616f5f6c6162000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047148de2cc2856d7fb2a8ad06fa44a5669702a29b394424560714a1af90ad9efb57f3864b93b1ff7961c": "0x040000000002000000000000000000000000000000000670686f6e670000194070686f6e676c657472756e673a6d61747269782e6f72671974706c657472756e6740676f6f676c656d61696c2e636f6d000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047148df29185dccdeea1e881cd70793b3191b905aab3c659140f21d0febd037e0301235c14ca276d762a": "0x00000000000000000000000000000000000f42696e616e63655f6b736d5f32330f42696e616e63655f6b736d5f3233000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047148dfb7086a8af6a0f46a258564182e321ace7b23e06d109edb5fb9fdd7f25ff6693bc9e0fccac531a": "0x00000000000000000000000000000000000e50756e6b205661756c7420233300000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047148e029dc73c6ca9b6f00272047a1369138c7948e8d193757bd7d6319254926d2b91175398d8250e30": "0x040000000002000000000000000000000000000000000d52544920736f6c7574696f6e000000196a6f6e61736d6f6e64616c31393440676d61696c2e636f6d000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047148e44cd35926bdb0bc6864e8808445baf40b99a5704ecdd47f7b0e609c5c4bcde4658fa8cecacfc3e": "0x000000000000000000000000000000000012446f676569737465722043726f776c65790d536861776e204d757270687900001a726f6d65734063727970746f65636f6e6f6d697a652e636f6d0000114063727970746f65636f6e6f6d697a65000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047148e5dd8f5ec2ae4f178ba8486af484a791ccc52be9aa844efcb97e88161ef3810ceeb4822cbe9297c": "0x00000000000000000000000000000000000a6465636f6d38383831096465636f6d383838000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047148e60dc01fb6f9a204244242bbae9826963603e899b19812a4daae3f5bfc1c4c8fb6aacad2d274300": "0x00000000000000000000000000000000000772726967616e0000000000000b4072726967616e313137000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047148eb1982dcbab9029e66b4a86783cae6a8ebf3824279bab103478b05ce04d2630e61a4dd9301d7b11": "0x00000000000000000000000000000000000000000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047148eb6988ffcbcddc884c62d27805ac9c7a62086e31dfae23703ac9dfb37fbd31bec95aa611c5d2c33": "0x04000000000200000000000000000000000000000000124e696e67f09fa4a6e2808de29982efb88f00000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047148ec37554e12de10ab08b555a5a3b2725e01ba15eb40aa32dc5b781532854b797808ed45e752b047c": "0x040000000002000000000000000000000000000000000742656e64616b0000001862656e64616b7374616b696e6740676d61696c2e636f6d000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047148ec91a2d2c36d0707a8b217ad8d80016336be124846210559ebf720aecd25ea0d0d11c10f1839e71": "0x0400000000020000000000000000000000000000000012706c6179696e67207769746820647573740000124071756970753a6d61747269782e6f726721706c6179696e675f776974685f647573744070726f746f6e6d61696c2e636f6d000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047148ec9e0f3e4ed8b00d6886dc9eaca691d9d893c4eb3132e31db7c0aee951805dd5eb463e783ca7957": "0x00000000000000000000000000000000000c417765736f6d655f446f740c417765736f6d655f446f74000016617765736f6d65646f744079616e6465782e636f6d000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047148ee3802b033a961232477dcb6bcaad7e38477d8e0bbaee67b4534d0bf49a0d69f1f8051ca9c8206a": "0x000000000000000000000000000000000010427269736b426c61636b4d616d6261000e636861696e677572752e6170700000000011406c6f6e67626f61726466616d617261000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047148ee5e7ff29bbc499c4826569e68b7eee1b5b93406e4951fcd7ab6b40be519a7db5c6732f66da1149": "0x00000000000000000000000000000000001d496361727573202d205374616b696e6720466163696c697469657320001f68747470733a2f2f7374616b696e67666163696c69746965732e636f6d2f001b696e666f407374616b696e67666163696c69746965732e636f6d00000c407374616b696e67666163000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047148ef014a3ff4856d97472058104d047d60672ab582ac3a345ec5d5d8f0292b7d237ad8aa4f9f93924": "0x040100000002000000000000000000000000000000000f537562737472614b6e6967687473001e68747470733a2f2f7777772e737562737472616b6e69676874732e696f001e737562737472616b6e69676874734070726f746f6e6d61696c2e636f6d00001140737562737472615f6b6e6967687473000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047148f10571113e0ae6b447326399643ec639a0bfde97d8b37f8dd0ca9fcb3c74a1ce017f0476f3e2770": "0x04000000000200000000000000000000000000000000064b495a4f53000012406b697a6f733a6d61747269782e6f7267156b697a6f734070726f746f6e6d61696c2e636f6d000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047148f3ec1f0eb47047c3aa8cecefcce91950b7cade280f301fca12202043e06b20e1231ebb4fd331304": "0x00000000000000000000000000000000000c6d616e656b69747469657300176d616e656b6974746965732e706172617472692e6265001168656c6c6f40706172617472692e626500000d406d616e656b697474696573000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047148f570a7114f41f2f9238a1cfd09a86d9624c562507c977082ab136ae4cd96747d618fadcdb7ecd2b": "0x0000000000000000000000000000000000054578657a0000000000000b404f6e64726150756c63000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047148f7c8fc33a08b55c5e9e6c9b7fa123c1f3a714edd226b960cd2ea07faa969dac9e3e9e8bc7c6e24f": "0x04000000000100902f50090000000000000000000000000000000000000000000000000000000d456c6f646965207c205733460f456c6f6469652044696e63756666000017656c6f64696540776562332e666f756e646174696f6e000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047148f8156567d999f4b06c4a2d537ca65341ebf4d0573230514a60ad2d9d7a78339aa2b6a5e4c61250f": "0x00000000000000000000000000000000000464696501010101000001000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047148f88e4319e34d2ea16476866c0074663b7d9046023a2b3fbf447c833f4fccfa3dd7a482235f1ec7f": "0x040000000002000000000000000000000000000000000a656e646561766f757200001840656e646561766f75725f313a6d61747269782e6f72671676696c696a61313936383840676d61696c2e636f6d00000e40416c65784b7269766f6e6f73000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047148f8a37e7560fdc95e6fdbbb40014567ab47740ab5e52be2492362e3d0459215d1ce3184a8689b42a": "0x00000000000000000000000000000000000d4772697a7a204b7573616d6100000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047148f943fb275b495a03e3622fb285dddefdf8f9ac2ab59aa34e2abb5a316e9ebdc020317220e75f879": "0x04000000000200000000000000000000000000000000076b734d6f6f6e000013406b736d6f6f6e3a6d61747269782e6f726700000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047148f9b3eae413c2cb20cde84600189647d443f6318f068a9cfdf630b1ce842b1a9dbb74712866d7639": "0x000000000000000000000000000000000006626f6e796112426f7373616e204261677368697965766100001773686f6e79616d63636f793240676d61696c2e636f6d00001040426f7373616e3036373131303739000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047148fb2b977b7be8246964685d439545f2f1805e498916d06ac142ed440f99ddd3543278cacfb1ddb3a": "0x0000000000000000000000000000000000104c6f792042616c646f6e20417274200c4b61726c2042616c646f6e2168747470733a2f2f7777772e6c696e6b6465636b2e6d652f6b61726c62616c64001962616c646f6e6b61726c6b61726c40676d61696c2e636f6d00000d406b61726c5f62616c646f6e000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047148fce8c937cb9835fae24164b69db56408ef6a9e9ba9549be17fb3bd4b88bdff92c06ea9df3776d13": "0x00000000000000000000000000000000000a7369726b6974726565000e7369726b69747265652e6e657400147369726b697472656540676d61696c2e636f6d00000b407369726b6974726565000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047148fda280bf14a4d9a6c87c1c4489f6b4199bacfb7cd427374374a9ddccc4658413564dc6c41a08938": "0x0000000000000000000000000000000000064b534d20320b526f6d616e20526f696b000012722e726f79696b40676d61696c2e636f6d000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047148fdc8a1dba69b4009a659fe431e951e6a30aa39a583f2b7f5b0540df31fc3fe126e7604f49479f69": "0x0000000000000000000000000000000000204d495353494f4e20434f4e54524f4c207c20434f4d4d554e4954594e46203600000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047148fe45272324c1bfc323e890aa0b5c0616ae4ce73ef46986c6e822d9f212ac26528fcb36d70b83e42": "0x040000000002000000000000000000000000000000000753656e73656900000014696e666f4073656e7365696e6f64652e636f6d000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047148ff1a76fe565275c32f682cd110c69b9666ad45dc6735e18e6b790b524fe347df9fc6027ee9da94a": "0x000000000000000000000000000000000019446561642043616e61727920436c7562204675726e61636500000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047148ff90052f96341279c107fbcac10f60dc1910e27210283c39f8d5951816f8d7c8f5f96d0c71dbb29": "0x0000000000000000000000000000000000084a454f2e52494300000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471490073106f69e036ffaba4f34d61e2defae2db1f7c712007824c194ad921959efdb4a65dd174a590c": "0x040000000002000000000000000000000000000000000f50524f4f462e434f4d5055544552134d6f6f7365204c616273204c696d697465641768747470733a2f2f70726f6f662e636f6d7075746572001a76616c696461746f72734070726f6f662e636f6d707574657200000f4070726f6f66636f6d7075746572000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047149008545bc6b9104854dae13b8ee7c7b93cfe5d6e3db2a48ad4fd34ef6191684dbab498b234b9cb10": "0x00000000000000000000000000000000000576616c7900000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047149009e250f366165b143b78432fda580e0996f00fce6f1ea8b2a38e4ddbe229eea3b839921eb4215c": "0x040000000002000000000000000000000000000000001df09f8fa2204d696e6973747279204f6620426c6f636b7320f09f8fa20000001778406d696e69737472796f66626c6f636b732e636f6d000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714900d5f104f49317a8ae668d3b1d7fd73a726263ac4a6454634d65f9c874ad7eede11184c6886bb52": "0x040400000002000000000000000000000000000000000a4c554e415220444f54000000196c756e61722e706f6c6b61646f7440676d61696c2e636f6d000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714900f31199a5d4616161cc08adbd7742ba651fac7c0fe5057fa4ac37b16541bb7a20c903a1841907a": "0x000000000000000000000000000000000009726d616e7a6f6b750c52796f204d616e7a6f6b7500000000000a40726d616e7a6f6b75000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714902842d3c37f4986a0b2fb0ff6a2effb882dc59e18d1717233e1142051304e76219f825b9da4eb6b": "0x040000000002000000000000000000000000000000000950616e6567616c690000154070616e6567616c693a6d61747269782e6f72671870616e6567616c694070726f746f6e6d61696c2e636f6d00000a4050616e6567616c69000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714903daac85f2846d9f0038b583a9edb1847e77fd632f12053eb84e81cd17e9afa3abd4bfc56a30b24": "0x00000000000000000000000000000000000949726f6e466973680000000000000b40506c6f6e6b61446f74000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047149045f9ed16c20b3fee866b5a824a9620446b09bdab8191fe0ab8800e1fbe8185c4ce3488d81d5648": "0x0000000000000000000000000000000000084e696b69746b6100000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714904ced744e494b84188e0101febd96c4801aa0f8df34142d9a5351e5bef51fccba8456b0a29d2030": "0x0000000000000000000000000000000000064e696e6a610000000000000d4062616c616e6365626f726e000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714904d3bc15625b8b05c1e0ddb072da402a8732c1dd926dc9befc7e2c9159507a75563b4ac0a2ef347": "0x00000000000000000000000000000000000000000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471490552d7683a533ef8821dc119eb7790c050e97b61a8b93c5e06d7494057f6c773004af1939837a7f": "0x00000000000000000000000000000000000a546f776e437269657200000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471490559a708d4b8f5b9691490b7b477dd3ee98a24ba795c474ac2655fb51c29c24016aea156460494a": "0x00000000000000000000000000000000001ce382afe382b5e3839e204b7573616d61204e696e6a6120f09f8c9e0d736169626f67756e696e6a612568747470733a2f2f7777772e657473792e636f6d2f73686f702f6e6575726f63010100000e40736169626f67756e696e6a61000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714905772522f1ed5ae1c9f76582c41ce999555425dcb884e8baa51a21eb8ae524457431ac81431061f": "0x00000000000000000000000000000000000468696f00000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047149060a3c80f6810d992b978cbfa629a5b3fecff0e348a6745690470ea9dc27674a56f757a14e59940": "0x0000000000000000000000000000000000064a6f7267650b4a6f7267652053656e61010101000001000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047149061dceaf0e1f167f25386e981a22cc69a7bbddc7671e7e471fd95f49098d0f40ebd5bc79730fb49": "0x000000000000000000000000000000000016546865204b7573616d61204e4654204d757365756d00000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714906d83e2f26e70dd0ed88dff710092f66a4e3da59fa67674985976f493be21879da90be0c1f41476": "0x040000000006000000000000000000000000000000000659616f71690a59616f7169204a69611568747470733a2f2f6a696179616f71692e636f6d184079616f71693a6d61747269782e7061726974792e696f1079616f7169407061726974792e696f00000a406a696179616f7169000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047149073d801dfde2151c0d998fb9f36dc65132dd06a845548d564e1db500fec59a8926a8fc75a8ba446": "0x00000000000000000000000000000000000a416c656b73616e647213416c656b73616e647220416761666f6e6f76000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471490762653147f44fb2479f5e0d2126d87a0ce77cd90278520ed58590d136b78586cbe5c915d5ff16a": "0x000000000000000000000000000000000007436861726c690c436861726c692041726f6e137777772e636861726c6961726f6e2e636f6d00146d61696c40636861726c6961726f6e2e636f6d00000a4063796e6f74797065000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714909443962b28076bc4f174c5cd052a7aa222302c7e1c0af713bb28673a504ed1f6a07f03486fc90d": "0x00000000000000000000000000000000001046726f776e696e675a65757338323601010101000001000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471490969d394746afac8c0cf875f18ab9ca0e60bfc13dba6b4216b74dddf84555ab2f10f0f3b265157c": "0x00000000000000000000000000000000000763726565736501010101000001000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471490a3a06bb6e41d8f1694cecdcc4a83985d1904e6d6709729459eef4a3bd8468f5b11a1dbc352af5d": "0x040100000002000000000000000000000000000000000d444953432d534f46542d30360e4469736320536f6674204c74641a68747470733a2f2f7777772e646973632d736f66742e636f6d154064697363736f66743a6d61747269782e6f72671876616c696461746f7240646973632d736f66742e636f6d00000e4044697363536f667457656233000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471490b1c53cf7dcddbd8a320af9e031a3396f15acdcc65c43008124068226505ee7e12bbb0a12012e60": "0x04000000000300000000000000000000000000000000075061726974791d50617269747920546563686e6f6c6f676965732028554b29204c74640a7061726974792e696f000f696e666f407061726974792e696f000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471490b34a3937b9efce6482a21b7e92055e74bc9b182ded5b0cb86e6f7706090c916f60e8235b8fe51a": "0x00000000000000000000000000000000000b4441524b464f5245535400000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471490b7f1fb67016ea9caaeb20361e77d9114bdd85dc196c33e15da72f4c28699085c388a3ecaa17f1e": "0x04000000000200000000000000000000000000000000034c560000000000000b404b7573616d614e4654000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471490bfa3ccf24689448eac08398a7441d30d6c48e1cce03d40c4ed1d8bf6764945925e5af4c3c4d362": "0x00000000000000000000000000000000000554616b6f0c53686962612054616c65731968747470733a2f2f736869626174616c65732e73706163651b4074616b6f736869626174616c65733a6d61747269782e6f72671d736869626173637265616d73747564696f7340676d61696c2e636f6d00000b4044616e636554616b6f000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471490cb5bb0ae9f291ede1c4c24739f2202961c22424816397b191bd85996985270375c21891d637f5e": "0x0000000000000000000000000000000000124249472d424f472d56414c494441544f52000012406e617465333a6d61747269782e6f726700000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471490f5f7cf3f6d8adb903ebbf02f14c17e429da07dc1a372fdd67074849faf98fe93487ddf92f7b869": "0x00000000000000000000000000000000000943616e6172696e6f00000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471490f89f28c98fdb9f9e14a9dd8d2928325d66d5987142ffd9209ea874b9a0d50a07492bd69e94c612": "0x0000000000000000000000000000000000104a616d657320536b7977616c6b657200000000000008406e6654555552000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714910e21740f651a39fa507c9a5d3879d4a7d6654c6a35fef974094bf5d16203d6312f9ea1358ec660": "0x00000000000000000000000000000000000a446f747765696c65720000001c646f747765696c65726f6666696369616c40676d61696c2e636f6d00000b40646f747765696c6572000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047149124e4dc6df447e792a0166ebf4b3f197986796419c48c9b61d29369acf5dd4a47ea2c7bd0393a61": "0x000000000000000000000000000000000005416c657801010101000001000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714912655d634b54e9a086de7162fbfa0b91a67eee94b697646028edcf484ae78fdc0627e7eef1b2247": "0x00000000000000000000000000000000001353756257616c6c6574204f6666696369616c001a68747470733a2f2f7777772e73756277616c6c65742e61707000146167656e744073756277616c6c65742e61707000000e4073756277616c6c6574617070000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047149155332d1321391214cd612ff7f390b9e90584767a00a4e9b740b61c0f2134698bbac79c6649764d": "0x040000000002000000000000000000000000000000000c6d7968656172746f70656e00001c40616c6578616e64616c6578323030373a6d61747269782e6f72671a616c6578616e64616c65783230303740676d61696c2e636f6d000010404c61626f6461537665746c616e61000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714915734949771ed554038aef7c58b83c4252c3ac69b38bf7d3df85ce136459a69bea073e24900423d": "0x00000000000000000000000000000000000c54696d757220447562696e0c54696d757220447562696e2068747470733a2f2f696e7374616772616d2e636f6d2f74696d75722e647562001574696d75722e647562696e40656d61696c2e637a00000d4074696d75725f647562696e000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714915d6c6518f7b5c4c0bbe78d8d6ec69c7ba07f331f2c491f94b7a53986caee31f97011905d5a9b5c": "0x00000000000000000000000000000000000c43525950544f4c4449455200000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714915f093e86a67b73629b918a21dae886bcc5cc6f7dead2bb9bcf0a25e7e376ba138882a91d473e31": "0x04000000000200000000000000000000000000000000126b7573616d612d70726f64756374696f6e0000001c637269737469616e636861706172726f6140676d61696c2e636f6d000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047149160a699257bae5812e991b50e700d1e52b37300ef0f51538197c0509d9d0b3d77482b4c1a3da566": "0x000000000000000000000000000000000008484a504b444f54104861797468616d204a6162626f7572000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714917bdd412b89d0510cce9e210c473fd1f20178fe889c178956ea1cf325c54b1a439a88bc62fe7851": "0x040200000002000000000000000000000000000000000ee29b93204e4f565920e29b9320054e4f56591668747470733a2f2f7374616b652e6e6f76792e707712406e6f7679343a6d61747269782e6f72670e7374616b65406e6f76792e707700000f406c6f73745f696e636861696e73000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714917ee600d4ff956c28f9a4e7cff6010ad028c4cd82432afde4dd1269efafcd281016daebf7fe0e16": "0x00000000000000000000000000000000000757697a6b696400000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047149180662af89403432204f9f580904c74f61c9606d97ba4b8d3149d5a689173b3056a9bf43d003039": "0x00000000000000000000000000000000000673656d616b0753657267657900001673656d616b31383032383040676d61696c2e636f6d0000114067463138764f5639396d635972516b000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047149185893c3a05ff480488b1a94fa6c2e250d13576c5e3256b263ac9ce966a7ef6e7766921d8d61738": "0x040100000002000000000000000000000000000000000559616b690c53686962612054616c657318687474703a2f2f736869626174616c65732e73706163651b4079616b69736869626174616c65733a6d61747269782e6f726715736869626174616c657340676d61696c2e636f6d00000c40736869626174616c6573000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471491b543380b6013ea301ca9d61b74c9aaa1fdd9e53249ba415ee86fd4d15130e9dc7ee8d713456b33": "0x0000000000000000000000000000000000076b7573616d6100000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471491b5f4bf2b18b9e7c01c495b45751393a71693e7abfae197cbbe0eae7233a463f7be2efd6f13444d": "0x00000000000000000000000000000000000554626f79044f2e4600001a7368696e6570726f6a65637431303040676d61696c2e636f6d000010405348494e4570726f6a6563745f31000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471491b6ef1b478c037f5a64d688b6d7eed3e5d25e0c69421de9a10db233c6635166a7be9b61ebb2a433": "0x000000000000000000000000000000000008526f746865727300000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471491d6804bda44e439d21ffa34abd2709779ccdef7aa0aaa292c32a986ff3aa6faf7c0af56d47cca5c": "0x00000000000000000000000000000000000541646f6e01010101000001000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714921d891bcf4e728ce683743954d0cb555a54ab21cfb8161f74e689a051d1ac1dbbb94df70be3d81e": "0x0400000000020000000000000000000000000000000012504f5745525354414b45204b5553414d4100001740706f7765727374616b653a6d61747269782e6f726719706f77657240706f7765727374616b652e6e6574776f726b000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714925643626036602a9a92ad7c6dcc51fec9f6d98f8316406ca42bd04dbb029d3ce454330a20fac077": "0x040000000002000000000000000000000000000000000b5473756b6920f09f8c9500000019636f6e74616374407473756b697374616b696e672e636f6d000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714925e96c4a6796256c0374918863d100dcc69bcab798ce6d52ad129a8b35e170ba00ba414a7be5e70": "0x00000000000000000000000000000000000b487970657220436c75620b487970657220436c756200001a68797065726c6f636b6564636c756240676d61696c2e636f6d0000104048797065725f436c75625f6e6674000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471492688eaced7f4cc5baa8a189ca8c65b64a3fdb0dbeac6a7ca2c00b27ed799f8e5f61b8af0621a162": "0x00000000000000000000000000000000000101010101000001000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047149275654d23da48139280f3396e4673c4475c8ae2f041cac0fce02e2551e1beb6d80df55667c66275": "0x00000000000000000000000000000000000e4e6f7261436f646520f09f92bb001f68747470733a2f2f6e6f7261636f64652e737562737461636b2e636f6d2f00166e6f72616c69753038333040676d61696c2e636f6d000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714927911426652f14cf4492a28ead0b315fc68069bcc39470c409d12b4e48259384d63da411bad0129": "0x04010000000200000000000000000000000000000000184d61726b204372696e6365204b534d20636f6e74726f6c0c4d61726b204372696e63650000156d61726b6372696e636540676d61696c2e636f6d000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714927d23a251f0902d7c4f2330f182fd91474849a74d6c681264aeeb57213af82a90fca83248b37477": "0x00000000000000000000000000000000000b446f7453616d61487562055a335230000015446f7473616d6168756240676d61696c2e636f6d00000c40446f7453616d61487562000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047149297e19198fb83a580540a824b03b96ba36fd30af41f8de9de93ce30ef8a16299bb9d938e62f3f68": "0x00000000000000000000000000000000000667626163690000124067626163693a6d61747269782e6f72670000000840676261636958000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714929c071a7d0883d10a6fa0a39e064f33dfb2fb47e30e19aaa7bdd13291d582535703ba7e8b273528": "0x00000000000000000000000000000000001247726561742054656163686572204b657a00000000000011406772656174746561636865726b657a000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471492ac2b44e9df4524865ca05d8bee6d8b21d7c48b543c5a154f5cab3079deb6718a775707c86fff5f": "0x000000000000000000000000000000000008726964646c657200000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471492b894b9740836cdce2e98564f421ca69a64608d68480080f5f317f4de4e400af3c065181e0c8a11": "0x00000000000000000000000000000000000d4c6971756964204368616f730d4c6971756964204368616f7300001a6c69717569646368616f732e6b736d40676d61696c2e636f6d00000e406c69717569646368616f7335000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471492bd0d654a0b34ffb640b7373eb438306069706e984d4725d91690d4685648f2caf3d1aef39b4003": "0x00000000000000000000000000000000000a52652e4d61726b656401010101000001000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471492d3b8b7eabbcd46524842180999b774cea511715b38f557018c75b586d0fbebaadb52adf0a44447": "0x04000000000100902f50090000000000000000000000000000000000000000000000000000000a5374616b654261627912536b696e6e7920426f74746c65204c74641668747470733a2f2f7374616b65626162792e636f6d0016636f6e74616374407374616b65626162792e636f6d000000001e68747470733a2f2f646973636f72642e67672f5679514558584564556e00", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471492f879f180f6a02408b712a589f5cb71cd7094809785ab0a924358d3cb52b27efd4933b6efc14963": "0x000000000000000000000000000000000010446f6e446965676f53616e6368657a0000001c676176696e776f6f6469736d796775727540676d61696c2e636f6d00000f4053616e6368657a43727970746f000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471492fd5ac6793d3e958ea2f0d9cd27c799fe691f45c532865beab623b9225e078d980b1b2e86b3026a": "0x0000000000000000000000000000000000194b5553414d412050415241434841494e205354414b494e4700000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047149302748bb1f52508b2ed4e35c8a3e577dbd30e2bdc03b475588c236484315857088e86bc74df1b31": "0x000000000000000000000000000000000003594800000011796172636f6840676d61696c2e636f6d000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047149306f9d2b20faa1224ec6e0f9e1ebb3e0a363ea3ad99d21dcc0f15b2c9587349d2e843d748f71232": "0x0400000000020000000000000000000000000000000007616c657865690000000000001040616c657865695a616d796174696e000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714930a2be4692e62f7e26e878810d319dd39d85e013a0cac3f232e6d9682b1d829bc3f7830ade12855": "0x000000000000000000000000000000000006736172616d0000001479756a756e31303138406e617665722e636f6d00000d406b696d736172616d313131000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714930c02ed2be38f57f8f51f44c3305ee50a92b2e1bac6b7103abbff664718d06dc10f3112c82bf61a": "0x00000000000000000000000000000000000d43726f6d6d2056617264656b0e437972696c204361726c69657200194063726f6d6d5f76617264656b3a6d61747269782e6f726719637972696c6361726c69657240686f746d61696c2e636f6d000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714933b413030a2193b0e4d677832209548c8712ca7ba1e72a885bfea75f7c639552b20b7a395df3f70": "0x0000000000000000000000000000000000010101010100000c40446f7453616d614c6164000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047149345f7e620413feb30b15f14ec3f05e821524d0bce378ef332d19b60476d88870deddc5e9382af16": "0x0000000000000000000000000000000000115065746572207c2047656e736869726f0c457175696c69627269756d1868747470733a2f2f657175696c69627269756d2e696f2f164070657465725f7374723a6d61747269782e6f72671770657465722e7340657175696c69627269756d2e696f00001140457175696c69627269756d44654669000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714934cae89366fc06960aded936fc747de820f80ae1ea2f02671395df2e87f5b8e296545d4b3d0bd29": "0x000000000000000000000000000000000006486f7368690545676f722168747470733a2f2f7777772e61727473746174696f6e2e636f6d2f686f73686900186b68616e656e6b6f2e65676f7240676d61696c2e636f6d00000f4045676f725f4b68616e656e6b6f000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714935e5672d20bc186d483a43afa5895b93249e9cbd00ffbea478ae2fcc21f5aaefb6fd9cfe30f4a4f": "0x0000000000000000000000000000000000064e696b546f104e465420436f6c6c656374696f6e7300001663727970746f64696e657240676d61696c2e636f6d00000a404172744a6f686e6f000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471493641724f6b9e368deffe6c6afb3c290639377d7cfb16bf69dc9039b46014f6eaaa13b55a71aa606": "0x000000000000000000000000000000000004646a6200000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047149366d4cd051fda98c47741beea936cd81fcb6221e2f2f6c9d6b875ed92133706a4b8eb70271fd003": "0x0400000000020000000000000000000000000000000014f09f8d9320506963636f6c6f6e6520f09f8d9300000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714937b9ba6877f7e80f80761baccb8c83580e6a9bcd98c05d11ebd9fd6c666fc09f00b055daa4d6e2d": "0x00000000000000000000000000000000000a4672656e636869654200000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047149390a024fbd35d6154bc9d96ec0ac259bb9cfadc33fe9ed4db3ab50168b329e86d68189e9ab1451d": "0x000000000000000000000000000000000017e29a944772756d7079204a61636b2046696e6ee29a9400000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471493a9c3c86003c444c4f1fdb0c67daf9e2302565a974d166ddc74b65219694369569eedd43e2bf308": "0x00000000000000000000000000000000000000000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471493c499446dff130948b985dae79adcb9becca19ca2eba2aada6416020dc01abd59f8b4419cd8a002": "0x00000000000000000000000000000000000b4d41442043524950544f0000000000000b406d617474756e636869000a6d617474756e63686900", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471493e08f85a76d37a7328b6e90d27539b8224a0ba4139f305a6bb2d97540a722e2ad470ecf43b4a341": "0x0000000000000000000000000000000000084d4c4e204b534d0e4d696c656e204d6172696e6f760000126d696c656e406d6574617079722e636f6d000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471493ee60d0d680c677224705fc7cbd3f254286b3e9fa19a113267a4628d213884d6a83179c41206b08": "0x00000000000000000000000000000000000a507572706c654254570000000000000f405265616c507572706c65425457000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471493fa88b509112c5cc8310cf96893e0013bdf5ad21fbdec7cc9423de8ddc27c30022c47fdf4c3cf11": "0x000000000000000000000000000000000004e5bcba01010101000001000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047149401230589822c5d48efa32a0569824a03e7a969f40d50b2ec796164b4d774d20d0d488513f3eb1b": "0x080000000002040000000100902f50090000000000000000000000000000000000000000000000000000000e33394b7573616d6120f09f998f00001a406175746f636174616c797469633a6d61747269782e6f7267116b656e6c303940676d61696c2e636f6d00000b406b656e736572736f6e000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714940d03ca7ec7ffbbecf9b1d2f50b9518f91e67d42a34bc73512d68f34a8371f5c45ecf9af2d8570a": "0x00000000000000000000000000000000000000000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047149414b9a45988e9b186717d35d7cfe3c6fe1c4996268614f6503e8c2caf64521fd9e14b76c57a9b07": "0x00000000000000000000000000000000001047616c6163746963436f756e63696c001c68747470733a2f2f67616c6163746963636f756e63696c2e696f2f00000000114047616c6163746963436f756e636931000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714943fc2ac54f4c37ccc10dd1946b0fc65c8993ff7f47052713e9aa4b1cb72c913bd397c34adf4f949": "0x0400000000020000000000000000000000000000000009416264756c62656511416264756c62617369742053616469711a68747470733a2f2f74686973636f696e6461696c792e636f6d000000000a40446f63416d6f6b61000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047149446885b0b18680ae8e0ac0aa68a0c138a3aa84813f0accae4ed7d6ae4b4905495026f16eda4e069": "0x04000000000200000000000000000000000000000000097370617a636f696e000000137370617a636f696e40676d61696c2e636f6d000008407370617a7674000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047149464a51c61bcb648ee56126859de69a3539f0e8910ca7e775243f18c6257954a65e020eb229be912": "0x040000000002000000000000000000000000000000000de29d84e29d84e29d84efb88f00001740696365636f6c646e61743a6d61747269782e6f726700000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471494673f91681becc4565d3c8cd1fcc93ed837d3f9830e333659cd0962ae7fadb7c87899d0b1431822": "0x00000000000000000000000000000000000e524d524b204d69677261746f7200000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047149497fcfa74b9bd271c1fcc964adadc336e55f884716aacbe0bbf32540003b0279a158cd2748f3f75": "0x00000000000000000000000000000000001e59757269476969207c20524d524b2e617070204661766f757269746573001668747470733a2f2f7777772e726d726b2e6170702f0018797572692e6769726a616e736b6940726d726b2e61707000000a40797572695f676969000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471494e8a3699d4cfcb72cb3165d3c084782aa0a3fdd77a70596c63814b3fc1ac0999fdb2afb5e1f4f40": "0x00000000000000000000000000000000000652656e4f730101010100000a4052656e4f735f5250000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471494ed5c295f9bfa2588f28e17671ba1808d7b02cd3caaf80113066a467127666f4d80afc50bfbc127": "0x0000000000000000000000000000000000097a6f656d63666f78000012407a6f656d633a6d61747269782e6f72670000000a407a6f656d63666f78000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471494ee9a4fadbb7dadbc5d026a7be48559570fc2a3a72d59b58d5971aec58530ab740c35d9f6a29416": "0x0000000000000000000000000000000000094c617373756b6b61064c617373651174656b6e69696b6b612e63727970746f000000000c404c617373756b6b616161000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471494f3111594a138697873a3c888462af6d6717791ad60019b0b5fdbaaa5aae703c4cf9f95766c5479": "0x00000000000000000000000000000000000941657465726e757300000013616b32373530616b40676d61696c2e636f6d00000a40616b32373530616b000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471494f3132d9220bd5bda6eed44e320bc280e758203c8a184a3fb21e875e860be78e2c479bd7b851e08": "0x0000000000000000000000000000000000044b656d000000156b656d706f6c6b61667240676d61696c2e636f6d00000d406b656d7373737373737373000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471494f5bc61099238f7c904f1e0902db076f8b1b593db28140bf6bace7d8ff5c7bf8968728098f13afc": "0x04050000000200000000000000000000000000000000124c696768744769616e745374616b696e670c4e65696c2048617272697300001c6c696768746769616e747374616b696e6740676d61696c2e636f6d00000f404c696768744769616e74496e63000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047149512e7cebb2ab2b2206dd955d4ade8d59bab18cba031e664ae888491d173084bc9a0efabf0be195e": "0x040000000002000000000000000000000000000000000753616b7572610000174073616b757261746563683a6d61747269782e6f726700000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047149525351d4777dc940efea838f312ff60ff62ce2914adfaaeb41d81dc4b81a8bf0a41be031e79c918": "0x00000000000000000000000000000000000e4a65737369636120416e67656c0021687474703a2f2f7777772e6a657373696361616e67656c617274732e636f6d2f00186a6573736963612e616e67656c40676d61696c2e636f6d00000d4063727970746f6172747379000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047149538c438fbcd89d8988376cfad02f636e059969036a05034046bd3a59b97c57cf23b272c9e8b0d55": "0x00000000000000000000000000000000000a4672616e6e694265650b4672616e6e69204265650000176672616e2e6173656d6f746140676d61696c2e636f6d000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047149540f12061c8ade9c0114150a79f0572d3d86fd1411ac282bd8b62beafdd7b4bc2d5cbacb48f3a55": "0x00000000000000000000000000000000000a42656c6f775a65726f0000001862656c6f772e7a65726f2e747440676d61696c2e636f6d00000f4062656c6f775f7a65726f5f7474000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471495523a80019f8438ccd28a48526105f8ea01f27c133b3971a5d80c26ded2fe4a695b10ab9875136c": "0x00000000000000000000000000000000000642617a7a7500000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471495636345d78c41f24c9006835bd0eb918b1e1a7bad79b1bfc0f70b752acb9dc1aee47819e4df0f06": "0x00000000000000000000000000000000000a736a65766572657374055975726900001670637072696f726174736a40676d61696c2e636f6d00000d405375766f726f7659757275000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471495bb65b41d18b99cacee95ed0e6c831a02112564c89d87a67684229e79a702700f91009c34f6e17a": "0x00000000000000000000000000000000000b6974734e6163686f373900000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471495e5354b81f0f460da9f7fd3d9612a68d2ead69dde53297b172b7db514d0d261e7c5be987df7f32a": "0x040000000002000000000000000000000000000000001453696b207c2063726966666572656e742e646500001540646576305f73696b3a6d61747269782e6f72671a73696d6f6e2e6b726175734063726966666572656e742e646500000a40646576305f73696b000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471495ee9607d490e8687a1cc366cab83c63f1d8a6ad090b038ac6057e235006619bde17ac85597be109": "0x00000000000000000000000000000000000000000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471495f3f5d4f1926f98b2010431ca44985a2cb0950ec7564333c86983dcd44b85c093e16723fbe19031": "0x00000000000000000000000000000000000953616d75726167690874697a69616e6f000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471495f941adaa91654a28322946bfaec48af9564e56ee4134655dc1748ffc206c3694a9c6bddbe8332f": "0x04010000000200000000000000000000000000000000136379626572627261696e2e6e6574776f726b001b68747470733a2f2f6379626572627261696e2e6e6574776f726b001b636f6e74616374406379626572627261696e2e6e6574776f726b00000d406379625f6e6574776f726b000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471495fb7c212eeb16bc3cbd5d669b224d75f6d54031abdac468efddba8ea48d4ec25f39996687e6bb23": "0x00000000000000000000000000000000000e6b7269735f616e66616c6f7661124b72697374696e6120416e66616c6f766100000000000e406b726973616e66616c6f7661000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471495ff23600e669c4a60deb73d358494181a302d0ad149af4aa52df621afe024c6179d7d0b39929e15": "0x00000000000000000000000000000000001346756c6c4e6f6465204d6564697461746f720101010100000f406e6f64656d6564697461746f72000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047149600c2a7db131074ea2f5d8d81a9e713040a65a058dbd3304f787f82be1b7d7fa7e136193ccdcb62": "0x04010000000200000000000000000000000000000000074c4950454e4715e5b2b3e588a9e9b98f204c6970656e67205975650016407975656c6970656e673a6d61747269782e6f7267147975656c6970656e6740676d61696c2e636f6d00000b407975656c6970656e67000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047149629ea052725c3692cea1b9d395f1497930efb3c25135fff46e120b747d490cfd62c66f4573e976d": "0x04000000000200000000000000000000000000000000134554484943414c2056414c494441544f5253000017406576616c7561746f72733a6d61747269782e6f72671d6574686963616c2e76616c696461746f727340676d61696c2e636f6d00000d404556616c696461746f7273000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047149639866340f488369cb0d4ddd32f9332dac7059de238b8e489afb55502d1756d7f50b78b58e20c70": "0x040100000002000000000000000000000000000000000b72656470656e6775696e0000174072656470656e6775696e3a6d61747269782e6f72671a72336470336e6775696e4070726f746f6e6d61696c2e636f6d000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471496466553cdf2029286f520b752675b6242f1b3c6e1dcd704058e3f74f81fba9afe10aa8113dc5068": "0x00000000000000000000000000000000000c4d617374657272756c61780000000000000d406d617374657272756c6178000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471496627741b7418892667eb6da0231e2e63b881d8a8936e6bedadbf4a4f3900e5e657301d410c8bf02": "0x00000000000000000000000000000000000000000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714967dd10b13066df77243fc7f5f476ee7c5fad9de673f1ccfdf59c3e92530c09d6d584ff19452c87c": "0x0000000000000000000000000000000000115361796564406b7573616d613230323100000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714968689303d5e0ea80686d249850c389953211c7ecd77d76f031bc8e9e0289b51f602fc8097122324": "0x0000000000000000000000000000000000086f7461626c656d00000000000009406f7461626c656d000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047149688ac8c5537830f120207cc128159479d48c4bd2213274517c13fda02c1783d2f38232ff1feb11d": "0x00000000000000000000000000000000000e4f6d61725f5365616c7469656c0e4f6d6172205365616c7469656c1c7777772e61727473746174696f6e2e636f6d2f7365616c7469656c00176f6d61727365616c7469656c40676d61696c2e636f6d00000e406f6d61727365616c7469656c000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047149696dce1ccfdcb0910908d002661d99caef8f6cc090f6f3f9853dc554b78dfada32b219398840c0d": "0x04000000000200000000000000000000000000000000147468697369736e6f746d797265616c6e616d6500000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471496a0953ddf0eeb24d71c3176c00b028a841880392ba8cd903836b938a971ad12857ca842ba29973b": "0x04020000000300000000000000000000000000000000114163616c6120466f756e646174696f6e001668747470733a2f2f6163616c612e6e6574776f726b12236163616c613a6d61747269782e6f72671468656c6c6f406163616c612e6e6574776f726b00000e404163616c614e6574776f726b000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471496ad8bee6040ef3c5b473ba833712cddcb59d2569e9f2523d66f2ac183c8470e74077682262eb486": "0x00000000000000000000000000000000001a4e554a4120484f4f44207c20534953204f46204d592042524f00000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471496cb59db66691c528e583eded93da9417b2c0b6dc1446ed4704f3553d065b4d20efed3a1e0c93626": "0x00000000000000000000000000000000000e4b726970746f66696e616e636500000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471496d9cd4e5f65d9cf821ba83ece24cfead00c045d6873d0f80cf12503a812e285afd007a6a9d81328": "0x0000000000000000000000000000000000087365616e5f66620a5365616e204368656e147777772e666f7267696e67626c6f636b2e696f155365616e40666f7267696e67626c6f636b2e696f157365616e40666f7267696e67626c6f636b2e696f00001b68747470733a2f2f747769747465722e636f6d2f565365616e63000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471496f4aad0cdd32c3e8a6d7fd62a2ca5609d25c2574a275de76a6fc5322482aa0b0d29f0a8f8f83b53": "0x040100000002000000000000000000000000000000000d706f6c6b61646f742e70726f001568747470733a2f2f706f6c6b61646f742e70726f001368656c6c6f40706f6c6b61646f742e70726f00000d4070726f706f6c6b61646f74000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471496fde7fff7b4278c8adee5c0c1d45c80592e817fd4914806f2929fbb1c80e8687faa8ad632c32e6a": "0x00000000000000000000000000000000000b5175616b7a204c6f7264000000147175616b7a6c6f726440676d61696c2e636f6d00000b405175616b7a4c6f7264000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714970399168fc6b4bcf20436bc406afae9bb15efd905cb4ab40b338e14a2bfda1c174859cdb06c9b6c": "0x0000000000000000000000000000000000087846756e6e6579000000147866756e6e7930363140676d61696c2e636f6d000009407846756e6e6579000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471497087a3a72f4f8b4c8f553a628a3ef2534f91452ee33fe84549dc8ce3fe330f07828af345f52f849": "0x000000000000000000000000000000000010636f746f706178692d7061796f757400000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714972eb164c7f5e4f208a0291a4b1bafb431607e66865c9fc5538a3eec1e9e859431a2265b701af077": "0x0000000000000000000000000000000000094a61737a4469617a000000146a61737a6469617a7a40676d61696c2e636f6d00000c406a616369656c6469617a000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047149733ee530cd28230b8745db0b5f85fae7e64f061d3d4c058cb4f51af12097a6fe666bd81b8251d7f": "0x0000000000000000000000000000000000204d495353494f4e20434f4e54524f4c207c20434f4d4d554e4954594e46203700000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471497389e32ef925ccd6c0197856b35c7f631f5aa8d9cfd83f7e75202b0d821e67d2f344e4e4b5fc10f": "0x040100000002000000000000000000000000000000000d506f6c6b617373656d626c790d506f6c6b617373656d626c791968747470733a2f2f706f6c6b617373656d626c792e696f2f001668656c6c6f40706f6c6b617373656d626c792e696f00000a40706f6c6b5f676f76000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714974bb4bce2ea42e09224219c0ac40ab90370be268d128fdc9528fa2effc0e28e39ed400a14536e08": "0x00000000000000000000000000000000000953616769747461570545474f52000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714974c91f6b33b06ff9437d00e9bdb34a8bfebb9a526f16a3eec890d0003c6d5f9080a10b04c00b112": "0x000000000000000000000000000000000012506f77657220486f757365204d656469610450484d00001c696e666f40746865706f776572686f7573656d656469612e636f6d000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714974f1452190fc371fada8b71c5d2906a12a63adb35dac00d22349528af0d39e9dcf9e8d43d828878": "0x000000000000000000000000000000000004504a530000000000000d40504a533034313239383932000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047149751a6b5ec392a79700407f5904c7ad8b610fdb40d1a8a1047efa8f00e0f2320791b6d7da8a69103": "0x00000000000000000000000000000000000c61316b616e646175726f7700000017616c2e6b616e646175726f7740676d61696c2e636f6d00000d4061316b616e646175726f77000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471497890c1341c73b0186f0b4a93947c72764f0bf771a5652371344df481a206d2d25e9b5af88a0690f": "0x00000000000000000000000000000000000000000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047149794f920c8bc28ab34e5e97e6921f126dce794b8122543bc3923d7c7abec719405f5822d8818677a": "0x000000000000000000000000000000000009416c6578204d747a0000000000001040416c65784d617274696e657a5f5f000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047149797b884384074cc4c0f34840840d39f88e5d7d2a55caa7416961c17c29ba9552206e5a0bd54093f": "0x00000000000000000000000000000000000a4c75646f63726f737300000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471497b2a64b241954e9a2ee169c829a65fef4ebadc97883a35a3694c2f2995a3cc61abde4fc9412a91e": "0x0000000000000000000000000000000000124272756e6f207468652043757261746f720000000000000a4062697466616c6c73000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471497b7c5b692c6ced4162ad78b4445890bb6f135b583b9775a5979a25d0065a55310943c8d090cb97c": "0x000000000000000000000000000000000007564943544f52000000136d657461766974694070726f746f6e2e6d6500000a40566974697265756d000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471497c4bf937bc625125ade8b34a0f0a1a7975476df53f96cb3b0fc5c4043716af5bc833b4c194bbd79": "0x00000000000000000000000000000000000a616e6e69655f6b736d00000015636f6c616e6e636f6c6140676d61696c2e636f6d00001040616e6e69655f736f726f6b696e61000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471497ed1dcda161ffc758eaac5ecb89b593ea486a2581dbb2df07745b96a7d49125d3bc33c654015243": "0x00000000000000000000000000000000000b4f7a796d616e64696173054f7a616e000000000011404f7a796d616e643737333635373636000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471497f069f11577b05c5414c8bde77dbaa6324c3261025c2d46399d615712a539723ab89fe736577a05": "0x000000000000000000000000000000000004416c690000000000000e40616c696d617277616e693130000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047149814eae07bc4079400da54310700ec4bd026010c3ec89737129446f75a25c0daf55cf6d432f6437d": "0x00000000000000000000000000000000000c4f6e6976657273654e46541b4d2e205665726c6579652026204d2e20426f73736368616572741b687474703a2f2f7777772e6f6e6976657273656e66742e636f6d001c6f6e6976657273652e6b7573616d6140686f746d61696c2e636f6d00000e404f6e6976657273654e465420000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047149837c343b899ac37125ab2fe5c8d89a80539712b54765ee2e8414f15d23e96f9d1413ed04bfa151b": "0x04000000000200000000000000000000000000000000116c696768746e696e672d737472696b6500001440736d6f6b6532363a6d61747269782e6f72671d616c6578616e6465722e73686174756e6f7640676d61696c2e636f6d000011406c6962657274617269616e313937330012616c6578616e64657273686174756e6f7600", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714983aa5b573c0b22174017a0c081a6b17c99ae305b6a0df072a6786bea22d7c9eea7da4cba2938862": "0x00000000000000000000000000000000000b416672696327417274730b4166726963274172747300001461667269636172747340676d61696c2e636f6d00000a404166726f4e667473000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714984b0aa6953965fc57f62eb53f8a94086775a809b67bfab4ec5127e8fc6d0e9b92901d40e4536f8a": "0x00000000000000000000000000000000000a4e696e6a612042697a00000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714987646fbabf7f0564a67865ebf0419d4e5cba04612864fac7999130a5294e4687512bb8c9bf35b35": "0x00000000000000000000000000000000000a4b696e6720506170690000001530786b696e677061706940676d61696c2e636f6d00000c4030784b696e6750617069000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471498844ce2f37772c214f96c193e11618ef9d1991cf06367361e5a5e2d1a91eb44146ea15c240e4819": "0x000000000000000000000000000000000010746573742d706f6c6b61646f744a5300000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471498ccb53a68ae0b0f4caaec0669936d9c7e402ec3c4ccfa546ffd288f015cde72f99b800dae71e932": "0x00000000000000000000000000000000000650617272790000000000000a4050617272794e4654000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471498d79f063b9276569ebeef0150a33357023e678bfff549602e6943b5b85d8bfdb58473992fcfaf63": "0x000000000000000000000000000000000008546869626175740000124074626175743a6d61747269782e6f726700000007407462617574000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047149925e4c33888e571eca22b1d356b4618e38499b2c2616bccb048c2a835af5cb142b77ca799622f59": "0x00000000000000000000000000000000001043727970746f5f70656f706c6555411043727970746f5f70656f706c65554100001567656d696e693834353540676d61696c2e636f6d00000c4067656d696e6938343535000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714995bf0301d5a832de2be45f0061ce0bfd9ef023a354bd1beaa9bad14345aa18c95f9e05043dc1641": "0x040000000002000000000000000000000000000000000d4b495241205374616b696e67000015406b697261636f72653a6d61747269782e6f726716706172746e657273406b697261636f72652e636f6d00000b406b6972615f636f7265000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714996507482af7276afedae0f19e624e485c0a2b8a9aa4b65608c89cc9908f0f90aa5567ea384cfe7e": "0x00000000000000000000000000000000000c536f6c6f7665692e44414f08536f6c6f7665690c536f6c6f7665692e64616f000000000c40536f6c6f76656944414f000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047149975fbaedde7756e12840f0626ac847d41089c4e05cf0719c5698af1e3bb87b66542de70b2de4b2b": "0x0400000000020000000000000000000000000000000005733063350e446176696420426172696e61730014406461766964623a626c6f7175652e7465616d12646176696440626c6f7175652e7465616d00001040696d6461766964626172696e6173000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714998ba9677cf5170c0e987cae440058064c72c16ad03b745e151a1a33f62d51f011f7888efa22605a": "0x00000000000000000000000000000000000470383701010101000001000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714998cd9a07d23d28d50ef3cbba6eefa5127e662a1286c69c3f8cd10aa328d394df9e69919af449b45": "0x000000000000000000000000000000000010496e73696768742046696e616e636508676f7374616b651368747470733a2f2f676f7374616b652e696f0014657269635f64776a4069636c6f75642e636f6d000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714998d2d283f44bf3e5e034f68b3255263d1b64c5d02c720da4748d990576a032dcf42e6e8b02dc658": "0x00000000000000000000000000000000000744617679637a000000000000094044617679637a5f000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471499928322b885a79b32f055569357341d406869cefbe52ef0ea059834a52e4de30b7e9306b364c56f": "0x0000000000000000000000000000000000074f636172696e00000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471499ad9accdb6256f3d8783497b4c06f05dfa6ca91a0502e77ea7ffbc5c33c7142a5d9d1f0322d783b": "0x0400000000020000000000000000000000000000000007535041525441000018407370617274612d636c75623a6d61747269782e6f72671b7370617274612e636c75622e3230303040676d61696c2e636f6d000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471499adee9a95267a606aa596e011820c7af6fcc90e52499158d286106baded690924651f7c9a4b8114": "0x0000000000000000000000000000000000044b48520a4b6e7574205261656e0000117261656e6b6840676d61696c2e636f6d00000a404b6e75745261656e000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab870471499d69c79e3dc754e8e80ceded3cf93fe205a4e71d4bfd6b8419cdf12d85244bd7fe7c82733417b51": "0x00000000000000000000000000000000000a4d696775656c616f6a0d4d696775656c204f7274697a000b406d696775656c616f6a146d696775656c616f6a40676d61696c2e636f6d00000b406d696775656c616f6a000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047149a1921d6885d9479040279d8f4ad6cdcf1792ac373cf6d44ecef27e6ab4a61a9057602b37b6dd028": "0x000000000000000000000000000000000006497a7a795f0101010100000b40497a7a69706f656c5f000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047149a217f9388c8f902d66ac04ad10dbb5ac16a6a477dce727d647cbfd809d18b150cb402ae1569b555": "0x04000000000200000000000000000000000000000000066d63666c790000000000000e406d69676874796d63666c7931000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047149a224cc249859b470efa942be958c4d368e9a0564ce34aa652a9c11727669dfc841dc73e8403497c": "0x00000000000000000000000000000000000949686f7220322e3000000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047149a24c66abe29ea3716d5b643fdfb1b22d5dfd3a50157104df0580c910d2754987afc25fe0aaf5827": "0x040400000002000000000000000000000000000000000b556e69636f6d62617365000000166e616f6d6174657469383140676d61696c2e636f6d000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047149a27fdfcf005531660a973fbc6b1a63e1db41101515df4eecb19bf04ad29e9b5d46b37c919c10975": "0x040100000002000000000000000000000000000000001754686520446f7453616d6120457870657269656e6365002168747470733a2f2f546865446f7453616d61457870657269656e63652e636f6d13403238646179733a6d61747269782e6f72671c767240546865446f7453616d61457870657269656e63652e636f6d00001040546865446f7453616d6145585043000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047149a359c8738cb74379c4731457546007a4ad4e09ba0ff6cc40477c2c2984833245706d8ed2cbeaf61": "0x00000000000000000000000000000000000a6d616b6b616661646102530000196d616b6b61666164614070726f746f6e6d61696c2e636f6d00000b406d616b6b6166616461000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047149a3e5bfc049b0f4a20c4f3295a3fee34bc398fa31f6efea34220772fe18bbe8dae6db750f531e847": "0x040100000002000000000000000000000000000000000c6b747a2e6f6e65204b534d11476975736570706520436f6e736f6c691068747470733a2f2f6b747a2e6f6e6511406b747a653a6d61747269782e6f7267116769757365707065406b747a2e6f6e65000007406b747a5f65000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047149a55a8f4ff0cbfb7d01ba1d7366983e4c464bdf4eb0572ed51599225d503fd0cb750fbdc945c244e": "0x000000000000000000000000000000000007657a7a656b6c08457a656b69656c15696e7374616772616d2e636f6d2f657a7a656b6c0116657a7a656b6c656d61696c40676d61696c2e636f6d00000a40657a7a656b6c636f000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047149a60ad0be33cf6b14e533a2fd6a6ff9987c6dc0659b6b20de1ae31461bea7171518a927287b1fd0f": "0x000000000000000000000000000000000007e9a39ee9b8bd07e9a39ee9b8bd0101156733393433323039333740676d61696c2e636f6d000001000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047149a6f18c4a47ae9cc5837571d1c2bb8e45ce2913ac68ae693a05769b8396a68663457f3e186c4ea20": "0x00000000000000000000000000000000000a524d524b5f4d4152530c4d6172696f2052657965730101166d6172735f39323036406f75746c6f6f6b2e636f6d000001000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047149a80b9fad3bcc75d94b26c1afb14feaf0a625a144350b10268e91f2a4e4c615cdce69fe17096453f": "0x0000000000000000000000000000000000044d415800000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047149ac6c20f1672e23e22680983f848c5191bedb6f13277b5c078f54cce890f70aa0578d20652ada058": "0x0000000000000000000000000000000000085061756c20486f0b416c657373616e64726f00001a63727970746f2e73616e64726f373640676d61696c2e636f6d00000b40416c6543616d6d3736000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047149accca3fde6b92f7ac7f6c84e2930d1ccd60d6a317040f1ffba1c704dbf5a277a324262eb3854c1d": "0x00000000000000000000000000000000000742656e204d6f1442656e6a616d696e204d6f747363686d616e6e1c7777772e62656e6a616d696e2d6d6f747363686d616e6e2e636f6d00106d6f696e67657240676d782e6e657400000c4042656e4d6f696e676572000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047149ad5a4ebb0ba372da6abbcd974cf24668c6e67a248f1f84c54f1737cf8d5547148e0c5835e61ed69": "0x0000000000000000000000000000000000074361707065780743617070657800000000000e4063727970746f636170706578000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047149adc88690451f27780ab25ea34cbc164f9bb13a28523b162cb4ed572b57e7c957f868c3d486f326b": "0x00000000000000000000000000000000000856616c686f6c6f034a41107777772e76616c686f6c6f2e636f6d010f6a614076616c686f6c6f2e636f6d00000d4076616c686f6c6f6465636b000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047149aea00c445f734edbaf3f15b9e83dcfc18b50fe91e601fdf446c008c72c3d17799c21a64877e8d3a": "0x04010000000200000000000000000000000000000000125374656562657220536f6c7574696f6e73165374656562657220536f6c7574696f6e73204c4c432168747470733a2f2f7777772e73746565626572736f6c7574696f6e732e636f6d001b68656c6c6f4073746565626572736f6c7574696f6e732e636f6d0000114053746565626572536f6c7574696f6e000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047149af67195cc171e66489f12b69a3d689791aae4d4f8fe89d35e1acb4bab87327360bfbd13fe8a324d": "0x00000000000000000000000000000000000a562e4c616e204172740d56696b746f726961204c616e2168747470733a2f2f696e7374616772616d2e636f6d2f7669696b615f6c616e5f0014762e6c616e2e6e667440676d61696c2e636f6d0000114056696b746f7269614c616e5f4e4654000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047149af8b5e8cfc8bafef815a7da50a69bdf81fa99c2681c3ac41eac9d1a9ced9467f210b26740af3660": "0x00000000000000000000000000000000000753616e6f756400000017636f6e746163747275626279407961686f6f2e636f6d000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047149afb96de5bd6c558f6b21d624832094b03aa672e016462a020e217cc67b1434785b99114a2b4fa5a": "0x080000000003010000000200000000000000000000000000000000054a61636f1644616e69656c204a61636f627573204772656566661a68747470733a2f2f6769746875622e636f6d2f6a61636f677219406a61636f67723a6d61747269782e7061726974792e696f0f6a61636f407061726974792e696f000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047149b04176b93f2fc32d6b7b9e28c90ba6d9d96a6a65201e7b6d068289cfdccb14a87e3647d1be27f73": "0x040100000002000000000000000000000000000000000b4a616b75624879647261000000116a616b756240687964726164782e696f00000d404772656775734a616b7562000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047149b2b73f74e0bcbe48098003566e8882540368bb1facdab06615168afd78758bb5b2cb3609be94851": "0x04000000000100902f50090000000000000000000000000000000000000000000000000000000a416e64792042656c6c00000015616e64796a7362656c6c40676d61696c2e636f6d000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047149b3023cfe38b696b623d04580e847693a8fca215668f44c36ef4077074c0d96365480597afaa4265": "0x00000000000000000000000000000000000101010101000001000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047149b38ffd646249ff7cc705f0ff73e771cc660a57a9540e469edf5ace2219b1f8452cf66382d915f07": "0x00000000000000000000000000000000000000000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047149b4583306b0319a120e484544431d1f4a52f2e1be4a2493c8e4f5214d4c8c0e45f88c443efbefd7e": "0x040000000002000000000000000000000000000000000e414c45585f41524b4849504f56000016407361736861313938333a6d61747269782e6f72671f616c6578616e6465722e61726b6869706f76383340676d61696c2e636f6d00000d405361736861313830383833000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047149b5c7c3faa653236a262d4db5b43d634096d43710d9eb3976fad629dab987b894e92cf3d5b66e978": "0x04000000000200000000000000000000000000000000094772696d66616365000015406772696d666163653a6d61747269782e6f7267126e6f7461746b6940676d61696c2e636f6d000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047149ba6a520a92802ba82e71c97217b0299f2ffaa8c4d6c1856fee7046a5e904a542d8c17ca8bb95510": "0x00000000000000000000000000000000000542594c49001f68747470733a2f2f6769746875622e636f6d2f637572696f73697479797900163234637572696f7369747940676d61696c2e636f6d000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047149ba746407882e793d49fca4c127d246783d23e388e34c09446b624d2d5e1f7773c9590823d451019": "0x00000000000000000000000000000000000b4441524b464f5245535400000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047149bb030d576315e075272318422a6be3bff308aef9c12a0a9304e65fff73541c82f67f03ec757355f": "0x0000000000000000000000000000000000096d617269746f6f6f064d6172696f0101166d6172696f5f66616c40686f746d61696c2e636f6d00000d406b696e6573696f66756c6c000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047149bb1413da54b080a2691d8004aa9a03212cd950a811d53cb31fc736fe956d2fdc814e44ac0aaec2a": "0x00000000000000000000000000000000000000000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047149bd02aeac53e527cb85b79dfde710c26c2e5b70de5cafb49213d6c867d92d4c5eef5ce9d79c72c4b": "0x000000000000000000000000000000000007506174617465135049455452554343492042454e4a414d494e00001a63727970746f2e70617461746540686f746d61696c2e636f6d000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047149bdad91263f2376dd46eebf8bfc22b8c7a156472e9630e85a3733a5441d305c7a11e85f2533f8d2c": "0x00000000000000000000000000000000000644657765791a427579207374726177206861747320696e2077696e74657221000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047149be10627200d7958fa65ad25c6a51ba28504fe803d9e3d542135924ba9fc0736cd3f1d9b83901778": "0x04040000000200000000000000000000000000000000094a656468614e6574000000176a656468616e65744070726f746f6e6d61696c2e636800000b406a65646861686f6f6b000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047149bfcf61c34036fae141755f3929b5c0b0f20c64648d7f04e6b2e87e513cefdd8a1a882ba47081a37": "0x04000000000100902f50090000000000000000000000000000000000000000000000000000000a7464696d6974726f76001d68747470733a2f2f6769746875622e636f6d2f7464696d6974726f76154074737665746f6d69723a7061726974792e696f00000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047149bffd90013482c8a841d14814b8a9f5b29cf42401b098442706e254e5993c19225b420f31f37164c": "0x00000000000000000000000000000000000e4e6f626f64792050656f706c65000000146e626470656f706c6540676d61696c2e636f6d00000b406e626470656f706c65000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047149c11f75a37508012e84d6f02ea5a833165a345080deaa9777eff59e32c3ea2dda077f0964220ac72": "0x00000000000000000000000000000000000000000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047149c2836ee11edbc0342bbd23dfc82edbf3cc9770f902c0165492b1ddfa03f3bad07a2b8b8c1736a49": "0x00000000000000000000000000000000000a61726368697465637400000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047149c3652738d9db765c02ac0e3b7a5063502ecc00937811834207d4942585ebc50d2380f27dbacc932": "0x040200000003000000000000000000000000000000000d5068616c614e6574776f726b0016687474703a2f2f7068616c612e6e6574776f726b2f12237068616c613a6d61747269782e6f7267156d617276696e407068616c612e6e6574776f726b00000e405068616c614e6574776f726b000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047149c753b3833f46cecb47513040660e2e37de135835e13289e6a632cd6b7156bf16680d55895c08834": "0x00000000000000000000000000000000000a4d6f7573657944656500000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047149c7fedf2907893262a57aadd6bf7482891546cbd398277759854a920bb413299ea04093bd5588d2b": "0x00000000000000000000000000000000000e4f204f204d2049204c20552044086f6f6d696c75642068747470733a2f2f7777772e626568616e63652e6e65742f6f6f6d696c75640000000009406f6f6d696c7564000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047149c880ae2409dd46de8d7a76e2c92c53b569cd53fd0e51f5c97f8bec55686bd56d2bafae3ad7c0753": "0x00000000000000000000000000000000000c446f7473616d616368616e0000000000000d40646f7473616d616368616e000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047149caba676d9ddf7d068ce96d86c921ccd2cf48357aed5b53c12a7db332b3d2c2d49fdcdc4fd92a355": "0x000000000000000000000000000000000006354e504c5900000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047149cbcd9f3144633ac5eb0f44e687b84fa4126f5aebd57e66c8f92a27df1f3f0ec260719841b3ad70f": "0x000000000000000000000000000000000014426c6f636b636861696e2052696f20323032320f426c6f636b636861696e2052696f2168747470733a2f2f7777772e626c6f636b636861696e72696f2e636f6d2e6272001c6672616e636973636f383231363235303140676d61696c2e636f6d000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047149cd04164b151c8211a903015b9ceaaf0f183eb409d3a38c4f0c9a685066ed90b32c834940c689e1c": "0x040000000002000000000000000000000000000000000d43727970746f6772617068790000001963727970746f677261706879766c4070726f746f6e2e6d65000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047149cd0ac122701f28d7ec5e89c029a05224b2759566042a94c54966d125934a8ff8beb8e0b017cbd67": "0x04000000000200000000000000000000000000000000074b594f52595500001540656967656e626f743a6d61747269782e6f72671b6b796f7279752e76616c696461746f7240676d61696c2e636f6d000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047149cdc08512e255b7738f6a9fcc82174482d492015b744f81cefaaa03e88a005508ed10f5936bff335": "0x00000000000000000000000000000000000942696767776f726d0000001862696767776f726d4070726f746f6e6d61696c2e636f6d000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047149cdc46c29a406ad85cc9959fbf01495ec080df904dda709cbef65932c5007dacbac2125eb92cd371": "0x00000000000000000000000000000000000956616c6b797269650000001776616c6b797269652e6e66744070726f746f6e2e6d6500000e4056616c6b797269654e465473000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047149ce78b12d1a5f4bf8ca62534073e8f15e51dc72040064bbd6ed63db5636fa6e57c40c00a9a5a7739": "0x0000000000000000000000000000000000036e6f01010101000001000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047149cffe130a8fe4c1636a0843c25944887176cece9b16aeb480c7afa88f5e8048db2b43a8c63918425": "0x0000000000000000000000000000000000204d495353494f4e20434f4e54524f4c207c20434f4d4d554e4954594e46203200000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047149d0599596e6697cb7a1662770d7b3161c9ad84c07463893ee9da4cd45ba01cccfada15540e411a37": "0x000000000000000000000000000000000008556e6e616d656408556e6e616d65640000184b534d50554e4b534070726f746f6e6d61696c2e636f6d00000b404b534d50554e4b535f000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047149d0cae984350fc7374bc1a01463386774ad67d8a822d4896a7603fc322eb4c6991a0ac38aef50b20": "0x0000000000000000000000000000000000134b6f6e74726f6c206761746f726b6f7270730000000000000a40676b31385f646f67000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047149d0d5a898faa577da8b91ecff4a3016e6fd4172b9119fbba17c3bbf61dbee8269c17583296038553": "0x00000000000000000000000000000000000b4b6f646154657374657200000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047149d1991a04d10dd3ac08fcbab8a091bafb08f6d2264738fd06178368a93f75eb50d45c43c8272db60": "0x00000000000000000000000000000000000a636c61726b3230323600000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047149d20d76620b47fa66610405d8ddaba4dcfca1fe4d14f83496de1055fe97efca594f2813a82900e40": "0x04000000000200000000000000000000000000000000164e6f7a6f6d692053746174696f6e73205374617368000015406e6f7a6f6d6968713a6d61747269782e6f72671373746174696f6e73406e6f7a6f6d692e616900000a406e6f7a6f6d696871000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047149d28492b2214a8bf7c286d9263ab3205e13208aade05ad50ec0d73b338649a630029e7f86e99d145": "0x0000000000000000000000000000000000155361746f7269204372656174697665204c616273075361746f726900001c7361746f726963726561746976656c616240676d61696c2e636f6d00000b406368616f5f73616d61000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047149d3098889f53b6da26b0a4bc93447c5ec3fa281302974ac3669c0f534fa4a3a8f98954e2633c1e6e": "0x00000000000000000000000000000000000e4f7377696e5f4576726c6f6f74000000126f7377696e406576726c6f6f742e636f6d00000e404f7377696e53686966746572000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047149d34cfa440b95864d3754204488186b41e90a93d0607992b9cb992932ff66c2faef8a984dfe4a234": "0x04000000000200000000000000000000000000000000054d696c65000016406d61746865726365673a6d61747269782e6f7267176d6865726365674070726f746f6e6d61696c2e636f6d000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047149d406c203f1082a2c0b248917ec51942009e6cb18f634b944827d04edee517c29deab27d755cd100": "0x0400000000030000000000000000000000000000000018f09f998df09f8fbce2808de29980efb88f204a757474611244722e204a7574746120537465696e65720018406a757474613a6d61747269782e7061726974792e696f106a75747461407061726974792e696f000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047149d41368f1d880a3b3ef88f51188ea054ff03b902d8706c6d9b1ea56c119b34e0b88e915b5d02da5d": "0x040000000002000000000000000000000000000000001a506f6c6b61646f745f506f6c616e645f56616c696461746f72000016407374616b656e6f64653a6d61747269782e6f7267166b6f6e74616b7440706f6c736b61646f742e6f726700001140706f6c6b61646f745f706f6c616e64000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047149d4747c2dff0bc7f50997acc48aaa0cc73c966cb01023e4c220e62285f41e92f293e0dcc3dc81132": "0x00000000000000000000000000000000000950656e41726a756e001b68747470733a2f2f70656e64756c756d636861696e2e6f72672f000000000a4050656e41726a756e000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047149d4b6496be09200b2009101253005ed413215bee9fa78987ba1a5d9edcc9e80b341b621ea976d218": "0x000000000000000000000000000000000006546565627300000000000009407465656273696f000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047149d5e6e9ef7bd98711e7745ab2aae1c51e0588fbc7a5978fb0cad1e2521b9e16831422d3814868f2d": "0x0401000000020000000000000000000000000000000007426572727944000000186b6e6f776c656467656e75676740676d61696c2e636f6d00000c404265727279445f4e4654000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047149db8704940c3089460bd998bd01ce669f92bbaf2ffd60e0e332e8932dd20bdc825a6293032d1cd49": "0x0000000000000000000000000000000000084e79204861726c000000146e6179616861726c3740676d61696c2e636f6d000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047149dbbb4d22419e712fe2ddf82f8499b6f21a96fb3718b3e596c75e11f8c411bb564812ffd5ebd4702": "0x040000000002000000000000000000000000000000000b476f6f64204b61726d61000016407468656d61726375733a6d61747269782e6f7267196d6174746865772e6d617263757340676d61696c2e636f6d00000b405468654d6172637573000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047149dbf1ea1fc3bfd2c58ed982e21ea95d74df1bd6901b6b088babae979b24aa93a205957e1e75ee90c": "0x0000000000000000000000000000000000086f64696769747900000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047149dc1bbaf5f8b85cdd40a52fa2efbe7929910db51addfc222ceaa46fffc82d601f6cfb7289596f609": "0x0000000000000000000000000000000000084c6f6f6f6f6f6e00000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047149dca516239778ea2ee3e62db730d5ded66d818668d4dad82f6e026703e9fcbaa91d06fb8f6678b44": "0x0000000000000000000000000000000000064974616c7900000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047149dcc277753735b96e04ca25cf1cbc516ed1c138492a7f2e606f60c5a9ac96cb405eaa3914fd12973": "0x040000000002000000000000000000000000000000000b626c6f636b736361706500000013626c6f636b7363617065406d7761792e696f00000f40426c6f636b73636170654c6162000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047149dcee803646fe05ab0ef511fbed15d88d75933d12bb50b56d1bbed109380b2fe0c7ec72d44119152": "0x0400000000020000000000000000000000000000000008414c455353494f001d6c696e6b6564696e2e636f6d2f696e2f616c657373696f6f6e6f7269134069726f6e6f613a6d61747269782e6f726718616c657373696f2e6f6e6f726940676d61696c2e636f6d0000084069726f6e6f61000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047149dd0a74dfe9045f7184d701295be7bb38b2c0c58a35bf8edc592671c53d149d206e037dc7c9beb7b": "0x040000000002000000000000000000000000000000000a48617368517561726b00000015636f6e746163744068617368717561726b2e696f00000b4048617368517561726b000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047149de7b0783ac120f57e2653c8926623f3abcb7862638240e78d978128f73749a2b533c89e25d54f03": "0x00000000000000000000000000000000001043727970746f20497368696d7572610c4572696b205461736b696e0000157461736b696e6572696b40676d61696c2e636f6d000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047149def61665adc4306fec2c5ffb46bfe1dbc7935f493a5c9323520878aad74b5a32276a7a268abdb32": "0x04000000000200000000000000000000000000000000076e616667363900000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047149dfcb7c9db5d6bcdce2f88fadaaf6505b613082d0f8ceb04c8c0016c7b6afe57ec0c5226f45e5c45": "0x0000000000000000000000000000000000067374696d73064672616e6b000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047149e091d0dc11bd3ea62bcdbab2bc3f7e3c40b6c4a0f619b63ef65978d6ec0427651e83a59fea6f658": "0x0401000000020000000000000000000000000000000007415a494d555407415a494d55541e687474703a2f2f7777772e617a696d757470726f6a6563742e6e65742f1940636173685f5f617a696d75743a6d61747269782e6f726717696e666f40617a696d757470726f6a6563742e6e6574000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047149e10ac134fee62edcea1f1014266a2b187ff31427aba732be9c6856099354ff536469087226b8453": "0x00000000000000000000000000000000000b50696b6b6f6c6574746501010117746f6d696f6c6179696e6b61407961686f6f2e636f6d000001000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047149e13c3a754009d072cddea2ece3afb01311814e16109d213b56d56de1e4299f697689e5f2a155f5c": "0x00000000000000000000000000000000000f42494e414e43455f4b534d5f31350f42494e414e43455f4b534d5f3135000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047149e21ce449387a9e130d6f231bc79dc0b10d4b09c38f9deada991ddf9234054b5bf8791a576c18a50": "0x00000000000000000000000000000000000d6320f09fa59e206c2065202100000013637874726f6e636f40676d61696c2e636f6d00000c40636f6c65735f5f626167000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047149e5255a8d274d43c14a2c525bcba9a332c97d2d18c549fd3f134bfd9b8cf73837472fc66909e684b": "0x0400000000020000000000000000000000000000000006766974656b000014406d72766974656b3a6d61747269782e6f7267186d7263727970746f766974656b40676d61696c2e636f6d00000d4063727970746f766974656b000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047149e57d4958a2ed9c63484f547d8726bb31f014613b3e2bfd4491f67b8c56a7e585b7505f9498addef": "0x000000000000000000000000000000000010506172697479205365637572697479105061726974792053656375726974790000137365637572697479407061726974792e696f000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047149e5b705cbdcc776ab4410d33f13c053dca87be657a0ae3cc87655baf43f7efdd454ff74e3a9d8a2f": "0x0400000000020000000000000000000000000000000014f09f98bb205374616b65204b617420f09f98bb00001340666d6f6e7a613a6d61747269782e6f726700000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047149e60cb268814889cd4fcdee494cca404d6eaf8c4293efef5159df2957859f2ef2c4b35c231911f7a": "0x0400000000020000000000000000000000000000000015f09f90bc50616e646157617272696f72f09f90bc00001a4070616e64615f77617272696f723a6d61747269782e6f72671970616e64612e77617272696f72444070726f746f6e2e6d65000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047149e738312b74520571ba583787c302d270bf87c9febd2fa4b471cc951c73400270789d5193bede10c": "0x040000000002000000000000000000000000000000001f4368616f7344414f205265666572656e64756d20436f6d6d697373696f6e0000000000000a404368616f7344414f000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047149e94efbcced786be9ad97bf6cfb3fb36b24b221c27ea22cbdbfb4dd4b2c54f80d8235d490be9113b": "0x040000000002000000000000000000000000000000000a416c6578616e64657200001040616c65783a7061726974792e696f1d616c6578616e6465722e746865697373656e407061726974792e696f00000c40616c65787374796c696e000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047149e9aa0898cd6f4e764c3926d1b9f9d44e8a2533c9a4df185d087a06601c49b7cbf12a8448fb45976": "0x000000000000000000000000000000000006737872737200000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047149ea440de636efc37dab0b013939f1b243f4674d76815ce2059fdc16425b04de7b01065e40d1dc46e": "0x0000000000000000000000000000000000126c617572656e7463617374656c6c616e69134c617572656e742043617374656c6c616e692168747470733a2f2f7777772e696e7374616772616d2e636f6d2f6c617572656e00206c617572656e7463617374656c6c616e692e61727440676d61696c2e636f6d000010406c617572656e7443617374656c6c000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047149ea68c0718a528a6f62e96783cff0b94caad6a13634ffd527d6d02d45f2cb810424cc47904ec284b": "0x040100000002000000000000000000000000000000000b6166726f7373743030390a412e2046726f73737400001a6166726f7373743030394070726f746f6e6d61696c2e636f6d00000c406166726f737374303039000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047149ed6094855a6dc83081c465a655cf27eaa73bdf9554abcb46ca2d56fe7fb0a20835c1a5ddec4a325": "0x00000000000000000000000000000000000b4441524b464f5245535400000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047149ef6562b57d1a60490c7f4e84347dc6e4e176f9156b2347378faa9b538a857b404cee3e341706305": "0x040000000002000000000000000000000000000000000f6d6f6f6e6269726469652e636f6d000017406d6f6f6e6269726469653a6d61747269782e6f72671a6d6f6f6e6269726469654070726f746f6e6d61696c2e636f6d00000d404d6f6f6e42697264696533000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047149f053c2746e722456610a5024c2a5db3d02056d4344d120ec7be283100d71a6715f09275167e4f38": "0x040000000002000000000000000000000000000000000e5374616b65776f726c642e696f001668747470733a2f2f7374616b65776f726c642e696f17407374616b65776f726c643a6d61747269782e6f726713696e666f407374616b65776f726c642e696f000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047149f06ff187af4df40163022143f2dff082630195ea8c8518036f5fa8110c90eabd2ef5cb4fc0c4235": "0x00000000000000000000000000000000000000000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047149f1fa798d8345173525f464cc5364f7f7852731d5cd9b78500f1c43cfdb92c9eede3f5a0eaa03f25": "0x0400000000020000000000000000000000000000000006566f76696b000000156b73756d61726b31323340676d61696c2e636f6d000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047149f461d99d2f7b43efaef36db79bfaff596eb52fcd57f5231c07548f88cf3149a6c5e16fc8a02fa56": "0x0000000000000000000000000000000000074e756c6c657809566c6164696d697200001366726f6e7478323540676d61696c2e636f6d00000b4068617269746f6d6173000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047149f4efbdd6555e0b768a449eb95cac957070a045678b83a9eb272296d2d6a73fc8fb32c1d3bf34967": "0x0401000000020000000000000000000000000000000008266e736869726f0000001366656465746f636340676d61696c2e636f6d000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047149f52902e443180208cf503bbe53110bea4f9fc4db5c69cc297d5468dce978b2c16babacff8dd686a": "0x00000000000000000000000000000000000553746176000000194564646965313032344070726f746f6e6d61696c2e636f6d00000a405374617634303936000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047149f5b73b14b74941844028623ab4774d78118028619961cc7ff178f9fac433b80d4f59761c60b6110": "0x00000000000000000000000000000000000000000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047149f7946d98858bbac124a3f9569f9ff89daea4ccf602d528f8da44f34ecf48bc6973eed3b5165ff10": "0x00000000000000000000000000000000000b54726173682e4865726f00000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047149f7c71dd97969da5263df801610ab2b9d7d2f33089b6bc0309ff8b8dd03cd5c7ed6a63d7a3c1f962": "0x00000000000000000000000000000000000000000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047149f8de5a4034454281e984e6d5e51685cee9d5281a4cd1a8ac5cc9885941adce24e5aa7c3c52dc664": "0x0000000000000000000000000000000000064a49534f4f00000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047149fa09da6038a3e69bae09878d7a9b24afaedfc8f7583489d17b8f8f960f2d568e23b235fde2c3526": "0x00000000000000000000000000000000000b69736f7669746578696e0000000000000c4069736f7669746578696e000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047149fab1af956c8e372583b27d0269f0d86d9c19a74eaddbbdd6885d999c9a4d4defc2697e294c1e722": "0x00000000000000000000000000000000000c446f7442756c6c7344616f0c446f7442756c6c7344616f000016646f7462756c6c7364616f40676d61696c2e636f6d00000d40446f7442756c6c7344616f000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047149fb9d67d9f4e2fa2ba72901b5cad51e0d3f0b63845f17d071a84abdcbf78a3ff56c61ffbaf02d56b": "0x0000000000000000000000000000000000086b696c6175656100000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047149fcaf6c7a62c9137a6299b602cc853e89ea284f820806f4451609c9912ae6d975263344d5a840752": "0x00000000000000000000000000000000000000000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047149fcbffeac9a335a1b4959a54c2ae7ea7b9200d5e5c1584654ff2d18e88e50265474b2d3888bc740b": "0x00000000000000000000000000000000000f44656d6f6420506f6c6b61646f7400000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047149fd3584b98fe6bcabc5aae116c7e9946559d10511d4782e36aa971ff50e4b7a3394208a2a68a087c": "0x000000000000000000000000000000000007686966756d6900000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047149fe4058d2daf1d0ac63b1a57aae969fc1d0796ce63d7f2175b568b461ced1ba46679b5e51cd13d30": "0x0000000000000000000000000000000000096368616f73626f6900117777772e6368616f73626f692e636f6d000000000a406368616f73626f69000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047149ff692371ae01a939a033ac371b5adcb02ce6f22dbfc953767c2f4ff6140f2fcb18125eb4cff9820": "0x000000000000000000000000000000000009506572736f6e616c00000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047149ffd1362c0ca2353c85cebb3f21b5e97737a7bbc14d8376a79dbba9c2849a28edae77c776d1e4a08": "0x040000000002000000000000000000000000000000000c7072656d61747572617461000018407072656d617475726174613a6d61747269782e6f7267207072656d617475726174612e76616c696461746f7240676d61696c2e636f6d000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab87047149fff764f278ece0638008b23e7763fadc90d6a0b5d1ebbf8b930e95ab5eaccc3d4cbad41df8f726d": "0x00000000000000000000000000000000000b537562737472614775790000000000000c4073756273747261677579000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714a004ed215b6f26ec367a414bdfb35809b2ab3febb46b75abad9a72cac29918e5501f080841af412d": "0x04040000000200000000000000000000000000000000055472616c00000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714a01290fe5b06995f4c17ad2c0a71fbae7beb3bed91a1e8f90289ffdcd7089c881ff247b3b70fb03f": "0x000000000000000000000000000000000008415254204445580000000000000d406b7573616d615f646f6773000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714a026881ddc77059cfc793f88c007467e78399bf6490ee2c84bf2679eb27ed13a86e0399d291e8525": "0x000000000000000000000000000000000012536e616b6573206f6e206120706c616e65000000116d626279753740676d61696c2e636f6d000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714a028e921c9041581bef3f1aa71b32bba775b3886b900a2e3fb4f4163d58c1bce0aaecfe0b55c1b5f": "0x0400000000020000000000000000000000000000000016f09fa49620526f626f7420486561727420f09f96a400000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714a039f5a44265aa6630e02b0b9846874c53f5fcc3f9260a60f0b27c7239102eb97ab13f5ad29d2273": "0x00000000000000000000000000000000000970696e617475626f00000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714a0476abd38ede3949653bcf18e30531092fdc1c52afe06cf61f56fb1fa5d719078cd6914d395ed0f": "0x04010000000200000000000000000000000000000000114d61737465726e6f64653234f09f94b10d4d61737465726e6f6465323418687474703a2f2f6d61737465726e6f646532342e64652f1540616c65786b6964643a6d61747269782e6f7267176b7573616d61406d61737465726e6f646532342e646500000e406d61737465726e6f64653234000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714a058a0c0476768208476db8162516f3ed29a4227dbc9cff53d4f2c342907a499e9517cc16f94356a": "0x0000000000000000000000000000000000154d6f726f6e6963204d75746174696f6e204b534d00000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714a062138be3539cdbd8876695e0680719107b9ccb595ad5d8bfdc4ccc8e8e4656091fcfe652c0f155": "0x0400000000020000000000000000000000000000000009564c4144494d495200001a406772617465766c6164696d69723a6d61747269782e6f7267196772617465766c6164696d69724072616d626c65722e7275000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714a06e8fd58cbda126387bb92ab860d29d43aaa2f6a9a97d658a52291111654489f8e294301171f908": "0x00000000000000000000000000000000000844722e204d75700000000000001040676f72696c6c6168696768646576000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714a078de63f42f4d3d89abf449cfb7d9b862b775abe556bccbe647820fd4d7a50b63872b657c96506f": "0x0400000000020000000000000000000000000000000010444f5453414d415354414b452e494f00001c40646f7473616d617374616b652e696f3a6d61747269782e6f7267156e6f646540646f7473616d617374616b652e696f00001140646f7473616d617374616b655f696f000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714a091d0f89a15b5c8260bedc3bc39a4394c59b58e3adfc89b23caca4cdf695fb96fff3e0a556f8a00": "0x00000000000000000000000000000000000948616d69645f6d6d0f48616d6964206d6f68616d61646901010100000a4068616d69645f6d6d000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714a09342269424baaa12ec709076fedbe0737ed2b7aa80e029f5de68e2faa5a303fc55cef3b1ca5a4c": "0x00000000000000000000000000000000000a42616a6f717565746101010101000001000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714a09af68755800aad94ef44028b5c2649905e23e0abe33d4542688a2ed40bcc0f169f0d535816f43e": "0x0000000000000000000000000000000000094e656f4e756d6973094e656f4e756d69731668747470733a2f2f6e656f6e756d69732e636f6d2f0015737570706f7274406e656f6e756d69732e636f6d000000000e4e656f4e756d6973233733313600", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714a09f49890c6bdef1acbfbc894060d93d772850a601b3f4b69d02c8026b2e7d99433b4067feabeb29": "0x00000000000000000000000000000000000f4a756c69616e6120436162657a610000001b6a756c69616e61636162657a61407961686f6f2e636f6d2e6272000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714a0a5afe895a38848e60eab4376491bae1381d70519031e7dcba87563353d85d4553ed98102882c26": "0x0000000000000000000000000000000000074d696368656c0000000000000d404d696368656c6c6c6c5f5f000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714a0b881b0063a363a02bf32e061073c44300056b416cd66a4fde1e6c120dbc0089bb65134f5693a3b": "0x040000000002000000000000000000000000000000000a6d7564646c6562656500000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714a0be3d88f3ec6175e4a17c9a02776b617e255d70b32ffa9313bac0f99e7f1f376e449bd51816901c": "0x00000000000000000000000000000000000000000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714a0c7bc8aeaa262f14ac4eaed36e5c54f045b46cb54f533b2d3949c0ca7137e89ef03ee3f56f8155f": "0x040000000002000000000000000000000000000000000c477233336e4861747433520000001b477233336e4861747433524070726f746f6e6d61696c2e636f6d00000d40477233336e486174743352000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714a0c8c65147c2d821f2259af2c52fcc70ca4e85fc39b56d87ffd4411fcebc547e9f92f3314a25c112": "0x00000000000000000000000000000000000d4461766964205472656e647a114461766964204a20576f6f6462757279157777772e7472656e64796368656573652e636f6d00176461766964407472656e64796368656573652e636f6d00000f4064617669646a757374696e3834000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714a107be39dc1d3e29e461904b1a914a11bfcd4ea252c04de536dcc0af7fc36de82431af75f08ef13a": "0x00000000000000000000000000000000000b42697463682054697473001d68747470733a2f2f7777772e6d617968656d6e6f6465732e636f6d2f000000000b406170656f6e61636369000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714a10e77c34a7d9ba5b8a2a7e1c5807c9b5241a00382d483537eeaac2fc756dfde564af6a368fbc275": "0x00000000000000000000000000000000000b4441524b464f5245535400000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714a117fdeb44584c3b762311603c2642b9de046bc7b653733b25cb40e98871ce9835c65a249e735533": "0x00000000000000000000000000000000000f42696e616e63655f6b736d5f33360f62696e616e63655f6b736d5f3336000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714a11a320b9a8feb01f857311106c8d7b0daf6e096db9a0d759b52403e439ab23fd6559780a8b1c803": "0x04000000000200000000000000000000000000000000095374616d70656465000000197374616d7065646563727970746f40676d61696c2e636f6d000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714a125e781d83ce9a1a8fdbb1c5950c16c8e725a857c3834b8647b1751fef78079de2976fe5516176e": "0x000000000000000000000000000000000011416e746f696e652045737469656e6e6511416e746f696e652045737469656e6e650000000000114065737469656e6e65616e746f696e31000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714a157ecf5817eb51ef005d960b7bb25e0979b9533817cff27aca11f7bec09a69235d17622aaa7776b": "0x040100000002000000000000000000000000000000000c6c6c6f7964732e746563681d4c4c6f79647320426c6f636b636861696e20546563686e6f6c6f67791468747470733a2f2f6c6c6f7964732e7465636818406c6c6f7964732e746563683a6d61747269782e6f72671174656368406c6c6f7964732e7465636800000d406c6c6f7964735f74656368000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714a17318e09fa7855318d059728fac3dabd4b7058c455c4cd0c636520da4d9ce4e6cab9932b23a3a3d": "0x04010000000200000000000000000000000000000000076e616d72756e000016406d6931332d3563346e3a6d61747269782e6f7267156e616d72756e2e6b736d40676d61696c2e636f6d000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714a17e7770b29efc26845498df40e85e2ba9d9e213d1f476e7b147aab6a9098f1bb250e00251ef8f5c": "0x0400000000020000000000000000000000000000000015436f6c642053746f72616765204361706974616c0000001d6a6d617a6140636f6c6473746f726167656361706974616c2e636f6d00001040636f6c6473746f72616765636170000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714a18d4df5394e01a8d23bddef5d1f2e9b9d3a49363d6ff94c517aff97ffbe186acb22564a4dccc94b": "0x000000000000000000000000000000000007436f7a6d316300000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714a19b37e844707d72307183930b2264c5165f4a210a99520c5f1672b0413d57769fabc19e6866fb25": "0x000000000000000000000000000000000006537a65676f0d53657267656a2053616b616300001773616b6163737a657267656a40676d61696c2e636f6d00000d4053616b616353657267656a000740737a65676f00", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714a1c8d0175e914150ac13bb5ebe1fd2af47758b14ed5f26987831f053be20293e20064a68393dbc6d": "0x00000000000000000000000000000000000e54696d656c657373204172747a00000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714a1cf23b5be0cbaf3f43436557ab3a98460458c52dc9e8795303af2f3772122c712af60e530592d4a": "0x000000000000000000000000000000000005446963650000000000000e40646963655f696e5f64696365000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714a1e3b34bf1f2c1ce6abdcbbb3d328d87db10f5948e4fab5d12e7470826c4fa9ede73f40bd4ae1721": "0x00000000000000000000000000000000000a4d65746170756e6b7a00127777772e3864646f67636c75622e636f6d0013696e666f403864646f67636c75622e636f6d00000c406d65746170756e6b7a5f000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714a20215acf2cee769a26f9a811e752199217945e52bb96fb08229d7904bc030f6df73b5b4e6bbdb6e": "0x040000000002000000000000000000000000000000000c4a6f686e5f43616e617279000000156a6f686e62726f73734069636c6f75642e636f6d00000c404a6f686e5f42726f7373000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714a209cd26c6c53911aab241100ccfed63c10453f0772355250fca0a4bb826afec2692f11416e0392b": "0x00000000000000000000000000000000000b4272686e4b63627936310000000000000c404272686e4b6362793631000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714a20c478424158a838edfbe8841fb9f9571f356320c1cd5df5b6365e25f83305141940b25a2bddb03": "0x00000000000000000000000000000000000569686f720000001a70616c616d6172656e6b6f69686f7240676d61696c2e636f6d0000114049686f7250616c616d6172656e6b6f000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714a215c23d3f30e28acc4fac060bf7e92c94836df38993b1851e3c2a9728335340fff42ded89ea2326": "0x00000000000000000000000000000000000a53757065727269736b10416e647265612056656e6472616d651768747470733a2f2f6269742e6c792f334644766b6757001f73757065727269736b2e74686573616e64626f7840676d61696c2e636f6d00000e4076656e6472616d655f616e64000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714a22b2644a532020e102cb9e9982a073c22c641fcf04338ccaf8f34047acfd430ee0490488c85201e": "0x0000000000000000000000000000000000175a6569746765697374205461726f74204d696e7465720c5a6569746765697374504d0d7a65697467656973742e706d0115636f6e74616374407a65697467656973742e706d00000d407a6569746765697374706d000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714a232fb94a5267854b2fe1d9da0178b40163865fe41c0a593a6444ea39efea4325cf3a8a2ad2ad279": "0x00000000000000000000000000000000000a4379626572446f6f720101010100001140417274687572573630303532353036000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714a26e21db13bc9cb6d4afb112d3a3a1ab9e8e99dade99ee8afefbb7547f8bb862100557ceb9fb9047": "0x00000000000000000000000000000000000b48756e74657272723739074d757969776100001a6d75796977612e6f6465696e6465406c6976652e636f2e756b00000f404d75796977614f6465696e6465000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714a27174c44291c2200c27409c0741df6780a595424f9e421ffdc6da847a45b0d382d6797e30371213": "0x000000000000000000000000000000000009506f6e64617475730000000f706f6e646174757340706d2e6d6500000a40706f6e6461747573000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714a298d0b8580cdd4b2075be44eab367537b65f751a9198164e4b7c80790015494216465284b9e422d": "0x00000000000000000000000000000000000e496e66696e697479204d696e640e496e66696e697479204d696e641f687474703a2f2f776f6c66616e677279636c75622e74696c64612e77732f001a696e66696e6974796d696e646b736d40676d61696c2e636f6d00001140496e66696e6974794d696e644b534d000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714a2a6a1ee046288c04ef671d2efdd37b165d0cf115e33450b96ed967d730b3c3e6b89e649ffda7352": "0x04000000000200000000000000000000000000000000097461696368756e67000015407461696368756e673a6d61747269782e6f726700000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714a2ae90c382196439e01757b530f7bdc77daf168300e833e402c73828d934814e124e9b14df068a21": "0x00000000000000000000000000000000000f4645454c2054484520465255495410416c656a616e64726f20476c6174741163727970746f706170617961732e696f1040616c656a616e64746f676c61747413616c65676c61747440676d61696c2e636f6d00001040616c656a616e64746f676c617474000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714a2aee766ebb6fb7c4edf81ba4fbeb6ea13cd45ba93cc1d689a6e2e5c6dfc35a458a971823a324218": "0x040000000002000000000000000000000000000000000b506f6c6c7320636f696e000000176c69636572696f73686f727940676d61696c2e636f6d000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714a2b8fab3ba0aef26c86c5ec7bc852b2bf9b5847ca343f9117c1edbd761cc6e40a5233e5764020579": "0x0000000000000000000000000000000000064b6f626179064b6f6261791c68747470733a2f2f6c696e6b74722e65652f6b6f6261792e6172740101000007406b30626179000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714a2ba603094678fe1c650925980e670634900f8e902da89bed9c9702ac51aaf08cb5043eec1f10345": "0x0000000000000000000000000000000000084b756273616d61084b756273616d6100000000000e405365637265745f5f53616d61000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714a2c470192fbbe716643b60a34e88347c82257693d4429296b7822293c9a7bfdb2b08341529513c67": "0x00000000000000000000000000000000000c4a696d6965204475636b7a0000000000000c404a696d69654475636b7a000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714a2e21db14ae164a8ec94a820c5dfc7420392ebb42e844a853016ab1310838a42e7ee315c7e07ed7c": "0x00000000000000000000000000000000001053756e7368696e654175746f732d4300001f4073756e7368696e656175746f736e6f6465733a6d61747269782e6f72671c73756e7368696e656175746f73696e666f40676d61696c2e636f6d0000114053756e7368696e655f4175746f735f000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714a2eb6257919dedbd0297ceb4d82f5843b3339ce0ecdb2a76c041eaf00c60e3b1c069f34111c7c967": "0x00000000000000000000000000000000000b626c61636b6c6f64676500000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714a2fb598c76f739aff4f2348bd92ca853d527b99144ad3f1d62b1ccab25e646b052dd5a3311773f76": "0x00000000000000000000000000000000000659796173680659796173681a7777772e7979617368736f756e6464657369676e65722e636f134059796173683a4b6f6461646f742e6f7267186e65636b63656e736f756e647340676d61696c2e636f6d00000c40427562626c65626f6969000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714a2fef89bd91c048c8b37db52b514d523a0fac84ec631db132c7532f317bbfa5ecd094c891bf65c81": "0x000000000000000000000000000000000009462e492e522e4d2e00000000000008404649524d335f000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714a305800a21679f161a0dc738566c0d456e72772f31b0df32843245857dfc5fed13f2780a3e785771": "0x040000000002000000000000000000000000000000000a7374616b657468617400001640616e647265697369643a6d61747269782e6f7267167374616b6574686174687140676d61696c2e636f6d000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714a30ff791ba0dd28618c7f5a8530d6aafc1b191156294a9e27bb674128607896f3fd5914282fb196d": "0x0000000000000000000000000000000000064b616d696c104b616d696c2053616c616b686965760014406b616d696c73613a6d61747269782e6f7267146b616d696c7361313640676d61696c2e636f6d00000c406b616d696c5f61626979000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714a3122414b52a0a0e18e0e8642a07089983ff62c55ab6f151c2ad58f43a4cb9f995cfaa5769fa9568": "0x040000000002000000000000000000000000000000000a456c7669732050617a00001240656b616d693a6d61747269782e6f72671a656c7669736775737461766f70303340676d61696c2e636f6d000009403078656b616d69000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714a319bb2ed17a3f850374c8228c74fbe266e3f5612322de99d130666ccc639162034c6b0ab135bfe1": "0x00000000000000000000000000000000000c4368656b6f7620524d524b001668747470733a2f2f7777772e726d726b2e6170702f000000000d406368656b6f7638736f7570000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714a31e75d5b109bd2528a94bbd46b41a6c7e7d0c776bbfdb48c6d72886fadf7ac49c62f014959f2852": "0x040000000002000000000000000000000000000000000b636f6c647920f09fa78a00000018636f6c64636861696e40696e746572626c6f632e6f726700000a40676574636f6c6479000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714a32760f6427ce1809aed8974aa64c7f31f4f0f60e863eb811ad1a6c75fd32dda92b19645fe5b0f47": "0x00000000000000000000000000000000000a4469706c617469636f0000000000000b404469706c617469636f000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714a327ed779367e66e9a283ffd707bcb531dc655e2a4d42124a6366355f088936f05d181aa469e2e0c": "0x00000000000000000000000000000000000a50726f6d6f5465616d001e68747470733a2f2f70617261636861696e6d6173636f74732e636f6d2f001c706f6c6b61646f7470726f6d6f7465616d40676d61696c2e636f6d00000d4050726f6d6f5465616d5044000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714a331b5a5d1eacc6ad6474ace9590159e08525e3c7273256016a640e300eaca921ce88713b44c9a5b": "0x0000000000000000000000000000000000044d524b00000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714a35762ac0f6b70b004028af3547c1c24c7b1d6ade70e4b20a94cd829457bc0d126f8d05b8d298775": "0x00000000000000000000000000000000000000000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714a35b58e91836d05e60c6e940d5c74596755e6bb1b31ec98958db10d841dfaf66954b5542c95c462b": "0x0400000000020000000000000000000000000000000008414252415241440000154061627261726164693a6d61747269782e6f72671861627261726164694070726f746f6e6d61696c2e636f6d000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714a36ad1dff06875450ed3eb9c7be61e0f8e13abb04857d82be899c1d7c3203998e02538720052ad34": "0x00000000000000000000000000000000000000000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714a3833fe87343f3df36b5dcb29928d8a462f493e0250e895158fc4fc54eb5d00a2a6701fe36a4283d": "0x04000000000100902f50090000000000000000000000000000000000000000000000000000000b5069636f6e62656c6c6f0e5069636f6e62656c6c6f204f551768747470733a2f2f7069636f6e62656c6c6f2e636f6d0017636f6e74616374407069636f6e62656c6c6f2e636f6d00000c407069636f6e62656c6c6f000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714a38ea7997f350d35d66d89d096c73b1d834e6d3114051cce2f13dc14014a103e9a61a97f4db2a818": "0x00000000000000000000000000000000000b50657065204b756e54610b4b696e67204b756e54610000176b696e676b756e746132343940676d61696c2e636f6d00000c406b696e74796472656164000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714a3a4e6df5615cbd134a3f0845fecdf74f7aeb569953da8cf8f8217a9a167a4e7d6b3438d8bb6d828": "0x040000000002000000000000000000000000000000001c416e756269204469676974616c204d61696e204964656e7469747900001940616e7562696469676974616c3a6d61747269782e6f726716696e666f40616e7562696469676974616c2e636f6d00000e40416e7562694469676974616c000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714a3a7ea9aae156340321d4124142f13d96092f57fb2635388bbd7337f2ef526abda0d3e011c361627": "0x00000000000000000000000000000000000b48656b746f7273616d610f47656f726720547369726f6e697301011967656f72672e747369726f6e697340676d61696c2e636f6d00000f4047656f7267547369726f6e6973000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714a3aa8a884996480b8041562016f6a47fe5d5a4ef7a3e51e71c399b5d7c03850f381b278867e08207": "0x00000000000000000000000000000000000c4d7242617468696e4170650000000000000d404d7242617468696e417065000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714a3cec71a40cb80cfd692990e340f0cd542caf9eced5e6bbdaf269fb9637fdec4cf1c30156f451e24": "0x00000000000000000000000000000000000453616900000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714a3d3732bc41feae490f0a6ad888e6a209c647f9c7834ecef87df797be3acb971708e8b73dc64236a": "0x00000000000000000000000000000000000f486f757365206f66204368616f730000000000001040726f6d65686f7573656368616f73000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714a3d7c54c6084b5aa5ed235ac2a5c0f5ea70c3c75169e1c0439f5e6a56005ae7aeada55080d512944": "0x000000000000000000000000000000000012407068726f647269677565735f31393836135061756c6f20482e20526f647269677565730101117061756c6f5f3139383640706d2e6d65000011407068726f6472696775657331393836000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714a3f10cae030a6d30b0c42cd546571a3529880973bb9be4952a9bd568d57e55fbdefae7614187ce5c": "0x000000000000000000000000000000000006736e69666600000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714a409a5b38e9a0943eceb07c477bd40d22f83b08cce78f2375bc1e4cf188c0de1ffef592570383e59": "0x0400000000020000000000000000000000000000000009496e66726170697800000013696e6672617069784070726f746f6e2e6d65000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714a40bc803acf9306792a118b2db66b83b0687645ec1283b836ed95f3646db15ff4a2fb0f05a4d237a": "0x00000000000000000000000000000000000442434111426c6f636b20437265617465204172741568747470733a2f2f7777772e62636165782e636f10406263613a6d61747269782e6f726713626361727440626c6f636b6172742e76697000000b40426c6f636b61727436000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714a41965f505d4d7b50cdccfda77f98ad5ee49c1056eab38e6dbc2028e5ef46d90618e2ebac4cdf249": "0x00000000000000000000000000000000000741726e61656c0f4d696b65205a676872797665747300001241726e61656c6d40676d61696c2e636f6d00000a4041726e61656c4347000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714a41e44784a9e830d2e47391ba4e18c5aeb3978bc6104d9d4d99453b16cb55150d10e590bdebde066": "0x000000000000000000000000000000000005416e6e6110416e6e612053686368657262796e61000017616e6e613230313476696b7440676d61696c2e636f6d00001040416e6e5f53686368657262796e61000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714a42050992f99e93b160719558ddd4f7497ab5e4be273872a6ae0ef556b87ce5a246a927f417ba278": "0x000000000000000000000000000000000008447572706830390e436f6e6f72204d6168616e657900001563726d6168616e65793940676d61696c2e636f6d0000094044757270683039000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714a42a7f2fc85a4d702255f3051ce179f64c735c4f46438bf790faf9c1e295e068bac569b80ac23961": "0x00000000000000000000000000000000000000000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714a42dd34ade18972444a9743d676ca9759f7897d55fd7fa240058fc1b2e0cdf37d49e588036213a50": "0x0000000000000000000000000000000000074131363030460000000000000840413136303046000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714a443701cf93179113acdfb6cd734dd3e624b6512e0903724c1c90a516c03c81a9af756491ea8e15e": "0x040100000002000000000000000000000000000000000a5374616b65666c6f77002068747470733a2f2f76616c696461746f722e7374616b65666c6f772e696f2f124069373439353a6d61747269782e6f7267127465616d407374616b65666c6f772e696f00000e4073665f76616c696461746f72000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714a45f60fb1fe385b96a39514d62c18e0f36ea214a5d6e772c653af20e647ec87f0f6985fdeba13752": "0x0000000000000000000000000000000000154b6e75636b6c657356616e42656172646875697300000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714a46019660a76ac1f5889dcc187231dbcba0bc0dad136d1ecb09633bc7cd5e27e04daa0277009ff2f": "0x040000000002000000000000000000000000000000000456444100001440766461303339303a6d61747269782e6f7267127664613033393040676d61696c2e636f6d00000b404456656c657368696e000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714a461cd7dfddc684c664b2886e95f12e168b420f06b90c11d8cdfa7ee747bc12e235a6d5efbae6e12": "0x040000000002000000000000000000000000000000000650697032340000134076656c616e613a6d61747269782e6f72671572617a69746f7431323240676d61696c2e636f6d00000b4056656c616e61563036000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714a467ece912d3a063167e362d3f5635ffb7527605a5e9004e8691b954f19a34ab86f4451cb0be6956": "0x04000000000200000000000000000000000000000000095354414b452e5355000016406d722e6f776e6167653a6d61747269782e6f72671d7374616b652e736f766965742e756e696f6e40676d61696c2e636f6d000008406567726d7368000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714a47a994958e0ce59ae58ba526977ac8c888aaec71da2be93459c2c6ee4a33f0881da7bd585b43a66": "0x00000000000000000000000000000000000f546865204b7573616d617269616e002168747470733a2f2f7777772e796f75747562652e636f6d2f6368616e6e656c2f00185468654b7573616d617269616e40676d61696c2e636f6d00000f405468654b7573616d617269616e000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714a48bc4964ca9af844480a961c77e6771723cbb95384839f9a287779affeba7b7651d748927c2901e": "0x00000000000000000000000000000000000c447261676f6e73746f726d00000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714a495a0a3926f96507eb86c4dfcd61617f0896775d0b2094ccb49ada7914e044e532760feef32d85f": "0x00000000000000000000000000000000000970616e6a696e616e00000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714a4990b5c0a8a5952088513ec07599b212d37b1cf18eee0538759ab65ca3735d47d1c5433e3297e02": "0x0000000000000000000000000000000000057261696e00000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714a4b9e382b3c28c9432fe137591e4faf75d462ae5769e8b08a138fcc920ac9387c4a7ab86cb87be23": "0x000000000000000000000000000000000018537562737472614b6e6967687473204d65726368616e74104d65726368616e742057616c6c657400000000001140737562737472615f6b6e6967687473000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714a4ddec1e6dbcf011629c17f4f4a24ec53f85a7beb1c70b13379fb8e4f969560704d2c25133ba8d24": "0x08000000000100902f500900000000000000000000000100000002000000000000000000000000000000000d416c7a796d6f6c6f6769737410416c7a796d6f6c6f67697374204f791968747470733a2f2f7777772e7a796d6f6c6f6769612e66690015636f6e74616374407a796d6f6c6f6769612e6669000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714a4ebe0825e5d7b90e20a9ef731e714cabd44479f1e39f9877a8480eff0ffc05e0d4dd701f7dc8650": "0x040400000002000000000000000000000000000000000a657269637a68616e670000001265726963406c6974656e7472792e636f6d00000e40657269637a68616e67657468000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714a530449273055581500359c0429d00c60d1da56e08054690497c0537931717f462b454362d363e08": "0x00000000000000000000000000000000000b67726f6d62617264757200000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714a53864ffd30a765388d1505492274985d6049cfae833ce8ce11597aca19d0f06a29ddb0a7a5fb97e": "0x00000000000000000000000000000000000756616d7073790000000000000c4076616d70737966656172000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714a54fac6210e70b7fb8d7d63b5e953e9004bc94357dc2f2b11654c220d871bd3c8b05b8047faa2a6d": "0x00000000000000000000000000000000000a53686565702052617000000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714a558ac2b375bd02bacd4501a1fc78e38cfc3b45660c9487ea36fc5a85aa7a7ecd3fc7c31dece0d43": "0x00000000000000000000000000000000000000000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714a57f9bacdb1086c63892e43e9200a587c535ada26933f3f8279e2d75e7e77cb9d3ce33153e5ad973": "0x0000000000000000000000000000000000104b7573616d612041706520436c7562001c6d656469756d2e636f6d2f406170652e636c75622e6b7573616d61001a6170652e636c75622e6b7573616d6140676d61696c2e636f6d00000b404b7573616d61417065000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714a5856810995ea72550ddcd537dceb0e95c72a9e2984c8703f4d9d76e8067305f365905a909ae3a47": "0x04000000000100902f50090000000000000000000000000000000000000000000000000000000547473136000018406c7562616e7979797979793a6d61747269782e6f7267136c7562616e7979797979406d61696c2e7275000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714a58931525b3ed3cb1024d5c7c359048f593fac90652e61b58cf9cfceab4f2828ab77743735bc9611": "0x0000000000000000000000000000000000096772756e746c65640000001a63696e6f63727970746f4070726f746f6e6d61696c2e636f6d00000c4063727970746f63696e6f000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714a59acabf7cc5c2db3a0b67c6e4b35133a18ff9c3b56d6cd28662f9e47f38afbfc508543087966870": "0x040000000002000000000000000000000000000000000c43525950544f4e495441530000001e63727970746f6e697461732e6365727665726140676d61696c2e636f6d00000e4063727970746f6e697461735f000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714a5ad0e5d9fecbb59ecbd732a91bbca19dcbcd8339644f8a6bdb752229a861140998663eafaa8f871": "0x0000000000000000000000000000000000084d6974737572690101010100001040636f70706570616161616161616e000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714a5b9b36d9ffbd7602c527cb7d17e0fe6df0e0da303a71f3eb46ea5bd309858389666ce6dad8efe15": "0x040000000002000000000000000000000000000000001cf09fa6bff09fa4962057686974654e6f646520f09fa496f09fa6bf00000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714a5b9eb0c3f28851660f981f150d72abe1fe2f48f8e825f32baadd440d5114b0242b7d5b85044da07": "0x04000000000200000000000000000000000000000000084e61636869746f000000196e61636869746f2e63727970746f40676d61696c2e636f6d00000c406e61636869746f657468000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714a5c4abc52a115cbd5a3a2cbb4e72978f14e758e1ecf46d1d98cc080f7c7213ef9fb5fffdfeca6c11": "0x000000000000000000000000000000000006416c6f696406416c6f6964000013616c6f696464313340676d61696c2e636f6d000009405f416c6f69645f000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714a5db7a2686e7ec402cbac2d6ac81d2169fa6e455b0497cf0389bd5dd2a11b24a53e6d94053765a77": "0x040000000002000000000000000000000000000000001be29ca8f09f918de29ca8204461793720e29ca8f09f918de29ca800001140646179373a6d61747269782e6f726714616e746f6e406e6f766177616c6c65742e696f000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714a5edded3fab580ac0e330ec8982011f9e4c1b0399335eeaadf410f721def14cd16df28e905af3905": "0x00000000000000000000000000000000000000000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714a60b4b1b2473719caeab30137868944fe970131f3d1882ed41e526020e9429818e90649413f94430": "0x0000000000000000000000000000000000064d617837340000000000000e406d617837345f63727970746f000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714a60dad8905663a8126acb4e6372fd11f9cf419b845964385848977d6e37b6221ea9d69d58d27d623": "0x0401000000020000000000000000000000000000000016444557205374616b696e6720536f6c7574696f6e73001a68747470733a2f2f7777772e6465772d7374616b652e636f6d1440646577706f6f6c3a6d61747269782e6f726716646577706f6f6c406d61696c66656e63652e636f6d000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714a61e7bfd7e80c927d04063c17aa00b3f0a378bf91acaa686257ce04972b6ee190cb6a6f16327d37f": "0x000000000000000000000000000000000008496e7641726368001868747470733a2f2f696e76617263682e6e6574776f726b000000001040496e76417263684e6574776f726b000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714a64992f36040c17f4866f45ae7b07019c03464e3c8c1324e96d3f05a2c5205e889fe597b0af2a70c": "0x040000000002000000000000000000000000000000000b46524553484e4f44454b0000001a66726573686e6f64656b4070726f746f6e6d61696c2e636f6d000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714a64c3dcbca109f3eac1d2d82c4a69b16c3ce9eb5d0b6f34f948a34efe62488879a514bbc837e0e50": "0x0401000000020000000000000000000000000000000010f09fa49620506f6c6b6153746174730b506f6c6b6153746174731668747470733a2f2f706f6c6b6173746174732e696f16406d6172696f70696e6f3a6d61747269782e6f72671a706f6c6b6173746174734070726f746f6e6d61696c2e636f6d00000c40506f6c6b615374617473000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714a6505dd741382407a681b32afa58ec5134541c0f960edfe5d8dd9a94d792d191e238c5a6948c236c": "0x040000000002000000000000000000000000000000000473657800000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714a6654b740dcbab2288acd34d32a3874f7eb5682060fe570c8100554c401bbef2c49dc26ddb1d6d77": "0x00000000000000000000000000000000000933444368656c6f73064368656c6f01010100000a404368656c6f733344000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714a67945dd518154113c6767288e0013ce7231aa2c1d5e76c7275e1ccd380392e8bed9ec6fc5445a6c": "0x0000000000000000000000000000000000086d617474736b69054d617474000000000011404a65727a6577736b69747765657473000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714a695a70bdbfc2aca60f79791d32f2f1d2c352b68b114c682dda46f4ea5f0bcdb891312b6faff670b": "0x00000000000000000000000000000000000454756d0000000000000a4074756d697370726f000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714a6e070a349b0a057e037d692951f268505d48389c9ffc60e38b126f3eb8e9adf17fdf6c8961b9323": "0x0000000000000000000000000000000000084c5549354b534d0000144077696c64646f743a6d61747269782e6f7267000000084031784c554935000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714a6e2ddb0c0dffe479051cb07cf440e1d0d26c6bc80c568a2f4d91367d76fe3bb0bcf215a7753196a": "0x000000000000000000000000000000000008476976657237350000000000000b40676976657231393735000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714a6f2d5d4c23323f8aa91fc0201f26b713a018669bcd269babf25368eee2493323b1ce0190a178a27": "0x0401000000020000000000000000000000000000000007696e736970780d416e6472657720506c617a61001340696e736970783a6d61747269782e6f72671464657640616e64726577706c617a612e64657600000840696e73697078000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714a6fa620b4d132dd76691ffb1fea3613197fdf95dc2d850f7ce48d2bb458810e81b47aed4997ea262": "0x040000000002000000000000000000000000000000000c4869746368686f6f6b6572000018406869746368686f6f6b65723a6d61747269782e6f726710746f6d6d69406e69656d692e6c6f6c00000d406869746368686f6f6b6572000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714a708d9865081ec8abe4bc35b26cdc006c69c1f827d4bfa75e4bfd4ac0094ceaeec8ac70469cac51f": "0x040000000002000000000000000000000000000000000e54656b69742048616e636f636b001368747470733a2f2f68616e636f636b2e6973124074656b69743a6d61747269782e6f72671174656b69744068616e636f636b2e6973000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714a71676abeb9f57f44a2802e70326441f6dafa719f9debd8141431a532066f7233b8d5ebb25428e72": "0x00000000000000000000000000000000000c7370616365736d75746a6500000000000010407370616365736d75746a655f6465000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714a71bb03524b3e99ae4c74212b31e0efc7f5f271a6636fafea840cb1cc318631b64788543ed12d02b": "0x04000000000100902f5009000000000000000000000000000000000000000000000000000000095372536c61796572095372536c617965720000187372736c617965724070726f746f6e6d61696c2e636f6d00000b405372536c617965725f000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714a729fbef766dde7fd6a0b3f61eb031d847fb2d7d262b7d0e409c01042b2872ebd6c673759c93ef7b": "0x00000000000000000000000000000000000941726d696e5261750841726d696e617300001541726d696e617372617540676d61696c2e636f6d00000a406b6c656261733364000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714a72db66667b370238e0fa6d4c1b60eb068b64c965c9c5aba29266a793c130c9b12a1003f01b09d07": "0x000000000000000000000000000000000008536e656d65736807536572676969000012736e656d65736840676d61696c2e636f6d00000940736e656d657368000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714a7543bc341341829e240ebdf6a3eb4882a6ec2284a2b886071cac52c92dde637b7d8e45b1cfc4a59": "0x0000000000000000000000000000000000044c6f7300000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714a7565e1dd549d62a4e7a56a7e64fd0c4c1d42d431e9ba7749f3a6c733fde04072437b2940338707b": "0x00000000000000000000000000000000000d4d41582d52455741524453430000001364757a6972796e6140676d61696c2e636f6d00000f406972796e613235313432303332000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714a763d7749a6cd60306fa1c58ca428edb67bf43766f26256a70bb171428f72e7502f582efa8e4146a": "0x04000000000200000000000000000000000000000000084873696e636875000014406873696e6368753a6d61747269782e6f726700000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714a77985bb6c007252867ed88f416454578da3d92589383af4698e89ac93642e6b0aaa2bd8eeba1f02": "0x00000000000000000000000000000000000849726f6e6d616e0a416c656b736579204b000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714a794662671bf6a9b2c0ace75e5847f22bfcdf0fdb1ee5a9fc15fe32756572d7c685fba050445b143": "0x040400000002000000000000000000000000000000000758696e797565001368747470733a2f2f78696e7975652e64652f1b406361707962617261676f706865723a6d61747269782e6f726719736f66746c69706173636861726140676d61696c2e636f6d000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714a796b643a26045c59c0e1507051438eed8a85c64953a88ac670df8459d30d0686083f56dc1943d53": "0x0000000000000000000000000000000000084e4654636f6e6711496c6f6e612047656c69756e656e6b6f001540696c6f6e617669703a6d61747269782e6f726716706172616469732e64697240676d61696c2e636f6d00000d406479626f7661696c6f6e61000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714a799abc18a65974508cc32a0f27384c6ec57d0318d34e9f90cdc1ed6a2218a630bd57c2465fc661b": "0x0000000000000000000000000000000000064161726e6101010101000001000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714a7a78778d8ac8668c6488a5a0f937b633f9db3046dcb765909e508ac70bad487c614e1002e2d9b2c": "0x00000000000000000000000000000000000c537472656574426561737401010114736861646f76765f636174406d61696c2e727500000c40436174536861646f7676000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714a7af572908447d41c05e32ccc9a75ec27b5be1c3f1d00b038e63a487122cd18aa7253b19ec2e6411": "0x00000000000000000000000000000000000846697265466c790f416e647265792022416e645a6f2200000000000b4046697265466c794747000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714a7d81691bdb191cf96fbd4b6d115fa19831f56d19076161af05e75f5eae031543e0f52eee0fed57b": "0x00000000000000000000000000000000001a43616c616d617269206279204d616e7461204e6574776f726b1143616c616d617269204e6574776f726b1968747470733a2f2f63616c616d6172692e6e6574776f726b00000000114063616c616d6172696e6574776f726b000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714a80bd3d653629195e0bb2043610b76d08387a24e267e36bf9a98d17c1958c93f6e4bf35139475877": "0x0000000000000000000000000000000000074e65336c707300000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714a815c482c3ce0537682c870c88abd2e7ea14e124ee19177b04629a51c7de560038ae850b8707ca4f": "0x0000000000000000000000000000000000054e61636801010101000001000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714a8178389a74a7e720cab3274e2045c86d9dcb81708c13df2a3dd4db5665e9dc64dd9dc148d89955c": "0x0000000000000000000000000000000000054b534b4e154b6f6e7374616e74696e652053687574656e6b6f00001e6b6f6e7374616e74696e2e73687574656e6b6f40676d61696c2e636f6d00000c406b6f7374617362796d64000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714a82e5a53d12a09aab42563a17307b5666d9a19a03d819884c58f14aaa5c7955eabb0373cc51df56b": "0x0000000000000000000000000000000000064e65656c6100000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714a834d4f336c27b55eed1f0f53dd77141b7e14c986f47952c83bceaa85330bbb79bd5049c02c6002d": "0x0000000000000000000000000000000000022e00000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714a8640543b19f19a84ad9207cc7c637de005975cbd7a18c25678fe0539c72da3aee5e481107214e51": "0x00000000000000000000000000000000000954776f506f696e740101010100000c4074776f706f696e743078000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714a86cb47311794162923cc59f21372eacb629a4237273e3c7b70e38b7ee6fe2943243577fb3dd5927": "0x0000000000000000000000000000000000076c6f6c6f6275076c6f6c6f627501010100000c405072656d536f6c4d6161000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714a88614383e45393734feeab011852aa4af8789a515e9fcf699fe44efc4089da2aeb9b3180f55db22": "0x00000000000000000000000000000000000a4261627920426561720101011662616279626561726e667440676d61696c2e636f6d00000e4042616279426561725f4e4654000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714a88877471b8c0203f6944b2b5f590f132203e5dd4f04c56e594f43b5681a48b210899382c3880b4e": "0x04000000000200000000000000000000000000000000114255454e4f2056414c494441544f524f000017406275656e6f76616c69643a6d61747269782e6f72671a686f6c61406275656e6f2d76616c696461746f726f2e636f6d000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714a89d5309de30e31c3a10656b4d5bcb51a5c28fa791cfc445c03dd331b1a4201fbf3e7682fbf7ec63": "0x0000000000000000000000000000000000085265737970746f00000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714a8a003d6a2d0177ca664f354c48dde8ffb75856a2a6d476cf4759eb2cba712f5f34d24da87a33119": "0x00000000000000000000000000000000000b616c6c636f6e6e6563740000000000000f40616c6c636f6e6e6563745f6672000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714a8a3ea9a9a3cbf30d21eb80113b2f57759d263c0eb1f02291dbc81a41d5a98029ad55f941eea3153": "0x040000000002000000000000000000000000000000000d77656233616c6572742e696f001568747470733a2f2f77656233616c6572742e696f164077656233616c6572743a6d61747269782e6f726712696e666f4077656233616c6572742e696f000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714a8c0fe4965a9220bfa0873857fb6d7ea4167b7176e459f3ad4f9a84d9d32c37c97cc07ef71021c3f": "0x04010000000200000000000000000000000000000000094e657762616e6b730f4a616d6573204e657762616e6b730016406a6e657762616e6b733a6d61747269782e6f7267164a616d65732e4e657762616e6b73406d652e636f6d000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714a8f89080f3d629d01e069328eb826785f0f58f3f42d0921da45c2c8f60230bc7a6d9f23e420f6524": "0x00000000000000000000000000000000000c44524147414f4e4f5254450b456c7a6f204e65766573000017656c7a696e6e6576657340686f746d61696c2e636f6d000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714a8f9b83743f647ef6aa99658e2b0755ca9f1ead5bde1ff6249f25d37cf1e7b5214dc31ce2d67e35e": "0x0000000000000000000000000000000000063031656767000000136b73616e6164757540676d61696c2e636f6d00000d4065636e6c6f535675726576000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714a8fb89fb3cff01fbb8a042528b36775f3f2644ef54a2f4cf34ad33ebbe538ef1112af09244428d71": "0x0000000000000000000000000000000000094d6973746572334400000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714a916ff8cbaa3dbb2e048fd6e69598e9af4aa6bdb31c470c5350cb29433bdaadd05fac776f7447e24": "0x040000000002000000000000000000000000000000000a5374616b656c616e64000016407374616b656c616e643a6d61747269782e6f726716616c6f63686b616d696b6140676d61696c2e636f6d000011404576616e4d6f756b68743232303034000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714a922ab100b50050438ee604a9f82f3f702f49b4bc794c684e7097aafc63b4c2ec3f579110fc77102": "0x00000000000000000000000000000000000444525900000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714a93c6e207f351cebc5c184f0565e2192d6aedae584ee736cef875f0e1c558ee3ede26869acd0b4d6": "0x0400000000020000000000000000000000000000000013f09f8c8c204e6f766173616d6120f09f8c8c164e6f766173616d6120546563686e6f6c6f676965731568747470733a2f2f6e6f766173616d612e696f2f1140646179373a6d61747269782e6f726714616e746f6e406e6f766177616c6c65742e696f000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714a9420133b7f85dd418af8d860e3138ecbde8349b7062c6ea5e440850c028e9c1625253890f1e5628": "0x040100000002000000000000000000000000000000000b5a616368204a616d6573000016407a6163686a616d65733a6d61747269782e6f72671d65786368616e6765696e717569727940747574616e6f74612e636f6d000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714a94e1e206d46f06cf451d9aea4d117a8724a9d55c25c968a7a8027a0912bbee2543e3a38eaabe94c": "0x00000000000000000000000000000000000000000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714a9541c4772f19bee9cba8900744a61a81cecd63e84ba19aec07dbfdf0dcf8e649daa9b31545f2e7c": "0x000000000000000000000000000000000012524d524b20506172746e657273686970730009726d726b2e6170700011636f6e7461637440726d726b2e61707000000940526d726b417070000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714a96b781a4270f369de797dd6265e5d3b12a9701b7cf7612c6104610fd35f6c61b5d760a5cebc327d": "0x00000000000000000000000000000000000c4d617a656e2053616c6568154d617a656e2053616c656820416c6a6f68616e690000116d612d7340686f746d61696c2e636f6d000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714a97f5e4fe69abc071c3c0915fe5c823928143e78ebe2046676d0c84a9dc73a51df007e094fb4046b": "0x00000000000000000000000000000000000764657673756200000000000008406a696e786338000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714a9939a663235c70ad2b5076d5c090233682d61cf1b2668d1466255e2030bfce0e38eeea730a1ae75": "0x00000000000000000000000000000000000000000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714a9abc96ba1ca531998d97c7f257bdc631d5a9a10e639a7a3402177a67669f01bfce163abdc14bc11": "0x00000000000000000000000000000000000a7665726f7961746e6f001e7777772e696e7374616772616d2e636f6d2f7665726f7961742e6e6f2f001e7665726f7961742e6e6f6f6f6f6f6f6f6f6f6f40676d61696c2e636f6d00000c407665726f7961745f6e6f000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714a9ac2596fb290717a4f1e970b856afb2bb1ef07cbdc9308267d54033c1d602da5939c46ff3decb10": "0x0000000000000000000000000000000000046e6d6300000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714a9c0101f5bde7e255a47dd2d6aca2d7373c5bf19ef5f771ce1646f0b869d0f34271785de8e44e51f": "0x04000000000200000000000000000000000000000000127374616b652d6d616368696e652e636f6d001a68747470733a2f2f7374616b652d6d616368696e652e636f6d1140616b6d653a6d61747269782e6f72670000000e405374616b654d616368696e65000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714a9d5aef332a19f2e0ceee7d84f1e2c0f6b4d3b29eac3a3c5b2586d3fd13f12e2c90427f5208e610e": "0x040000000002000000000000000000000000000000000a686172766573746572000000176e6f6b6f676972692e73727640676d61696c2e636f6d000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714a9e8d7579b6c63d09c994bd7ab2ac6093f2a3bae11b36c1dadabcfae55c21afc9c823239c151bc59": "0x00000000000000000000000000000000000d50756666657220426c75647a00000016707566666572626c75647a40676d61696c2e636f6d00000d40707566666572626c75647a000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714a9f08d3911f890e17a0625bffca33ce094f74f399580b16674ae3e0cc8ef259cde618e60e927ae53": "0x040000000002000000000000000000000000000000000d4b525950544f53434841494e00001c406b727970746f73636861696e5f79743a6d61747269782e6f72671b6d61726b6574696e67406b727970746f73636861696e2e636f6d00000e404b727970746f73436861696e000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714a9f9ca9189790e6d984a272e9701a4280010de2ca4b6a8036ad527f4f8a4d3f8568dd40ca4bbb929": "0x000000000000000000000000000000000006526164656b0000000000000a405234646f736c3477000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714aa006ae101e5026b0e76e3ac1594a10ba3ac43455a6195b9ade199408127ed344a12e1feb4c1fa1e": "0x040000000002000000000000000000000000000000000879616e6777616f0000144079616e6777616f3a6d61747269782e6f72671179626461626140676d61696c2e636f6d0000094079616e6757616f000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714aa02456a3c239f66f43c777cb76a32b1cabdf02bd5ad1ec330663043d33917da9151323f3a846023": "0x000000000000000000000000000000000008455845515445520000001765786571746572646976696e407961686f6f2e636f6d000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714aa06495c700f98f1f446b0fa660760f015c4fc7cd39c89deb69ed5f7e8b9652f6b14516bb2698517": "0x00000000000000000000000000000000000b4c6f75696520524d524b06627265747400000000000b406c6f756965616c7473000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714aa31b7d6b6c621c5280c01b232926c260a77f08c52e13c6b87e56e6172b6cb767a9274ce15b7f254": "0x000000000000000000000000000000000007616d69726b6500000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714aa5d460a7e61942d6c05e68f748e5a4a68cd353ddf96dcc22395722e9a03cd814a9c5bb964d7aa30": "0x00000000000000000000000000000000000950697869446f74730000001470697869646f74733140676d61696c2e636f6d00000a4050697869446f7473000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714aa66c809e7c7caee244a202cd6b29e2026b65a07c3fb32422138a122e581a627e35791da331bc905": "0x0400000000020000000000000000000000000000000008566172656a6b6100001440766172656a6b613a6d61747269782e6f726718766172656a6b616c657661796140676d61696c2e636f6d000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714aa73eb5624e30cd3ce8d12b99ce263a7d3c6ef0e361551a4fcc80e777b61ef1866ffb47a288dc15d": "0x0000000000000000000000000000000000086375746661636508637574666163651e68747470733a2f2f796f75747562652e636f6d2f632f6375746661636501156375746661636570726f40676d61696c2e636f6d00000b40637574666163655954000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714aa755f1de043396afa3a43c08b6d2eb836c98ffe0e3936f50f54bbd2a31e5a2b4686c6ce187cb479": "0x000000000000000000000000000000000009636f746f7061786900000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714aa76e80be7235fbb9404ddc2d30b821106b545eabb8d22b38ceaf86ed56a37f9f14a37140050bb4d": "0x00000000000000000000000000000000000a4f6c6568204d656c6c0000000000000d406f6c65686d656c6c5f7561000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714aa7bbf43874b9d190c0a3067cabf39e1a8bb185fbd95b274aa838916e6adcb968cbe99fcc0b0c779": "0x0000000000000000000000000000000000044e54200101010100000b404e617373696d543932000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714aa92e5948766b8968e3b5643d507e6af52fe12a5b4d4d095881e687cdba55e9d0e9f81600ab30b18": "0x00000000000000000000000000000000000000000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714aa92eeacb2f4017c0a409ce1eed912358015a8139383b02292284b392bf23ef9eb89c7f31ed7e10b": "0x040000000002000000000000000000000000000000000b47616c6178794e6f64650000164067616c6178796d656e3a6d61747269782e6f72671767616c6178796d656e34363140676d61696c2e636f6d000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714aa96f99f2185e3646069548e7913a106991a40988bd63d25996d6788f9302ef0a86ec40b4e6bd36f": "0x040000000002000000000000000000000000000000000e426c6f636b20427265616b657200000019627265616b626c6f636b706f73744070726f746f6e2e6d65000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714aaa3cef8c09f417f2a807fc9b3748a0d6b964bff11360e00040fb5fc569a9595532f935286a45f47": "0x0401000000020000000000000000000000000000000011e2999e47616d655468656f7279e2999c001668747470733a2f2f67616d657468656f72792e6d65184067616d652e7468656f72793a6d61747269782e6f7267136d61696c4067616d657468656f72792e6d65000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714aaaaeef2f5df648fccf47a2ac8ff8fdf1511044e5040f946f617915ab09a35a4d2b7f16b60bdba1d": "0x04000000000100902f50090000000000000000000000000000000000000000000000000000001a55542046696e74656368204b7573616d61204163636f756e741e556e6976657273697479206f662054657861732061742041757374696e1368747470733a2f2f7574657861732e6564751940757466696e746563686c61623a6d61747269782e6f726712636573617265407574657861732e656475000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714aacd06621bc7fa58402c5a21657ed72700a7b5b18773b060eef6d8fd448a86a01138dfcd9a41677b": "0x0000000000000000000000000000000000085343414d4b494d00000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714aad10b10ac673adf84354a60e57e717efbf60e05a7f8df7982a6054f48fa6c34b2d66a1f2f940f4e": "0x00000000000000000000000000000000000e68756d6d75736f6e7261696c730e42656e20477265656e626572671968747470733a2f2f62656e677265656e626572672e646576001862656e2e677265656e62657267407061726974792e696f00000f4068756d6d75736f6e7261696c73000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714aadb474af3b7652ba4e3fe06c7686f779f50f956b9a36486107808a86666a1105c598abf0cdd9020": "0x00000000000000000000000000000000000b43726f636f7a20426f790000000000000e404b7573616d6143726f636f7a000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714aae05b931631df4deab5016cd6102b4684337646ad1c880eccc696a5279bfd1857a4033f418f014f": "0x000000000000000000000000000000000018546865204372656174697665204d696e6420576f726b730000000000000a4075676c7970616c73000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714aaeed3ff5f7c6546305106e806e5964b54882b0253bbe6bb25fc4437dcb7d162551b2114a86ef81b": "0x0000000000000000000000000000000000105370656369616c204167656e74204b0f4b6576696e204b616d696e736b6901011b7370656369616c6167656e746b34303340676d61696c2e636f6d0000094073616b31333337000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714aaff4d5a3b6c0d71aa7880fe9ca2bbf331fc13e40525dcb0da661f143df506fed76d8ada3db8f551": "0x0400000000020000000000000000000000000000000008536b7974726f6e00001440736b7974726f6e3a6d61747269782e6f726700000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714ab090ef5db55f2a2a6a50a55a5a9ae7f9b80282cd64afb109232a94ff5402785e6174c77f5364740": "0x00000000000000000000000000000000000c427564646861677563686900000016627564646861677563686940676d61696c2e636f6d00000d406275646468616775636869000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714ab15b2cfee5d067cfeff500e183af7ebb6c66d217a35540bc99f91f5c8ca745f189c7a8e02523263": "0x00000000000000000000000000000000000a6176655f766c61647900000015617665766c616479313140676d61696c2e636f6d00000b406176655f766c616479000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714ab1b531c27836eb194fe1c5670fe87032f21aef7ab7089328f0014a104085c9ec123a18fa46bf23a": "0x00000000000000000000000000000000000d4b5553414d412046524f475a000000166b7573616d6166726f677a40676d61696c2e636f6d00000e404b7573616d615f46726f677a000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714ab2f26fdb66b7e0f02603a8ccfffd5b74a929869750a452583b36782928fbb4d21d467d31ca5912d": "0x00000000000000000000000000000000000f706c617374696320736e697463680f706c617374696320736e6974636800000000000f40417274556e6465727261746564000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714ab47f5a74f1518f11e3a86311df89c922a9fa04ce93d9233ae6ca68e9a4e84514c833bc62b98ae57": "0x000000000000000000000000000000000012477261766579617264204275646469657301010101000001000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714ab4cfabd58cd57c4b057b598310f90e7b899cbaea0bc1866fcbf3af525641e40b1b1a983bf840f30": "0x00000000000000000000000000000000000a73796e636c75622d350a53796e636c75622d35000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714ab6c59cef8a0b91fb0bace3fd1908d2fd2894c39d218b13c2095285a9b0f8634e12689ef0963186c": "0x000000000000000000000000000000000008547261644172740b4e465450726f6a656374137777772e6e667470726f6a6563742e74657a17406e667470726f6a6563743a6d61747269782e6f7267136e667470726f6a65637440616f6c2e636f6d00000c404e465450726f6a656374000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714ab727efb89c9f962a44b893b7b290c0e65eef94bde35efc9dda666544da7c59843c64db46850e915": "0x00000000000000000000000000000000000000000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714ab7ded53df100477da35e75473c26344448602f4c2ae540e1a28dbb2772529f06930cf61a3b7ca19": "0x0000000000000000000000000000000000064c55524f420d4c55495320524f424552544f2168747470733a2f2f6f70656e2e73706f746966792e636f6d2f6172746973742f0000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714ab7e3e98c718729f7a895955042cb3fe863f3564e7b30e9130e37b6d905be11c0cf91064de1cd83a": "0x040000000002000000000000000000000000000000000853544b442e696f000015406672617a7a6c65643a6d61747269782e6f726700000011406672617a7a6c65645f64617a7a6c65000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714ab817fd9c538caa7e615d6d583a7c958db2c97347de2c8830e3f6246e9b7adc272f28e373be3366c": "0x00000000000000000000000000000000000a526f6d616e6573636f001568747470733a2f2f726f6d616e6573636f2e6169001368656c6c6f40726f6d616e6573636f2e616900000d40526f6d616e6573636f4149000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714ab8afdd8f0ac6b745e7b0fb60cbb96d9e6325a80e8e14ae76826a53a944f299d3408337436a69631": "0x0000000000000000000000000000000000084861776b69736800000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714abd298c8604cc4203058bc565c6c6fac47bf50cb3f14df3f7e0da993b4e8be978963740ddd96a52f": "0x040100000002000000000000000000000000000000000d444953432d534f46542d30330e4469736320536f6674204c74641a68747470733a2f2f7777772e646973632d736f66742e636f6d154064697363736f66743a6d61747269782e6f72671876616c696461746f7240646973632d736f66742e636f6d00000e4044697363536f667457656233000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714abd8088ba391de8242245c83d3a57fb95b74c05157a15cef637c0c64573b1ae493f8f3c3df13714e": "0x0400000000020000000000000000000000000000000007414547495332000013407369676e79393a6d61747269782e6f7267117369676e7939407961686f6f2e636f6d000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714abe7caa62e5fc36ae6d808f3c2107a51d89762cd838ca246c9b4fe83d15077732694fe9dc9279165": "0x000000000000000000000000000000000012496e73696768742066696e616e63652032001f68747470733a2f2f6d6f6c65737761702e696f2f63726f77646c6f616e730014657269635f64776a4069636c6f75642e636f6d000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714ac3727c0a32917e62c5bca9fd4c92b051e35c47617175d8f28aba000ccf921cb24bdf555662f2d41": "0x04000000000200000000000000000000000000000000056b6f7a750000114067757a6f3a6d61747269782e6f726700000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714ac41f4731ee7b7d67058b4f0cca3807c138068a8c98af65745d8ce4ce287c704a113c80bcc19874b": "0x00000000000000000000000000000000000e54686520496e73706563746f72000f61626f7274696f6e2e726f636b73001561626f72744061626f7274696f6e2e726f636b7300001040646f6162617272656c726f6c6f6c000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714ac5da0493129f685f005964968c50de1ad4514e1453fbed546bcae7508185f8f6f116b98df392c3d": "0x0000000000000000000000000000000000154469676974616c204e6f697365204d757365756d154469676974616c204e6f697365204d757365756d176469676974616c6e6f6973656d757365756d2e636f6d000000000d404e6f6973654d757365756d000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714ac6f1c6373257f1a4284fa7c290fb6052b9437610cfb2e19b3b37081fc72140e444d5b57ca01924d": "0x040000000002000000000000000000000000000000000e576561616b204361706974616c00001a40776561616b2e6361706974616c3a6d61747269782e6f726718776561616b2e6361706974616c40676d61696c2e636f6d00000e40576561616b4361706974616c000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714ac7dc49ac8e1155e3ebc5e567e66f61937449b0c00ca928ae0b2c45e6331e426b756fd5787c73036": "0x00000000000000000000000000000000000e53686964656e2047726f7774680000000000000e4053686964656e47726f777468000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714ac8c20eece56914de20112991cc5c6843ed49189f02b5665847d3e408202737bea3fa2d01a69a10a": "0x00000000000000000000000000000000000c5468756e6465726b6f6e6700000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714ac94e97916c4c22f789becfbaf6d1af5ce67bd164e99eb01d0d677f830d54db4b6aae25543857465": "0x00000000000000000000000000000000000c4b5553414d41204c414e440c4b5553414d41204c414e441868747470733a2f2f6b7573616d616c616e642e636f6d2f001a68656c6c6f6b7573616d616c616e6440676d61696c2e636f6d00000c406b7573616d616c616e64000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714ac97e11542df6e0b98c7819c80977d8895f62907d6f2583177ee7ff77c6c661989b43f834d534d7f": "0x00000000000000000000000000000000000101010101000001000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714ac9c3b250f38c666aa4f9b4fe0e5591c49e938bee099a2462e7d1b274f652ff14376b6ec37c9e335": "0x00000000000000000000000000000000000b4d617273684d6344616e01137777772e6d617273686d6364616e2e636f6d010100000c406d617273686d6364616e000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714acb114a0152b1c7e2e6bfbe96e1c1a46e86a7e085fe5d748c8d0f38dc0d721378d8c9a55fc27c446": "0x0000000000000000000000000000000000074665726162670101010e62757263756740676d782e617400000c406564697a6b726970746f000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714accc7e5f392e9a0c9e758090b4cf20c4ffc9b30b07e41823bf447634b448c7b12bd011631735c814": "0x00000000000000000000000000000000000000000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714acdafe2a83e3f2dd48f9d09659267bbe934aac85662d64591bae57d22266311f7fb8dfd458bd9338": "0x000000000000000000000000000000000007616e6472657910416e647265792042616c6173686f761768747470733a2f2f6e6f766177616c6c65742e696f2f1240626c7368763a6d61747269782e6f726715617762616c6173686f7640676d61696c2e636f6d0000084062616c736876000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714ace3fb0f376c313f2ee247d45c4d034caf805fa22e3bf529b78d04bf33b11ba9a1cf10f7275c4c08": "0x00000000000000000000000000000000000d487970657220536861706573055065706500000f7365736f6d406d61696c2e636f6d00000b406d696e75737269746f000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714acf521c66337a1c992aa2496da20d35abf5407fcbcfa62741358276109b86ef2d0bf3774838b9649": "0x040000000002000000000000000000000000000000000b4d6178496e4d696c616e000000196d6178696e6d696c616e4070726f746f6e6d61696c2e6368000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714ad2218b3decc8eb22eccf3598b22853bd4de4a8340363f1af10f217a578892b569c76e7368253734": "0x00000000000000000000000000000000000b706f6f6861746e63737501010101000011405061756c5061743534323133343530000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714ad2c753ff14dd79164820bb673da18602df1750a214ec8e3ab14815994de12d01bcc46e9a6de476d": "0x00000000000000000000000000000000000e4d6564696f63726574697665730e4d6564696f63726574697665732168747470733a2f2f747769747465722e636f6d2f6d6564696f63726574697665002073696e67756c61726d6564696f637265746976657340676d61696c2e636f6d00000f406d6564696f6372657469766573000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714ad2d645b1ffcbcd23afbbdfaee3e5ed51710c3aa8147b4c28f5260c8bb94e75735e8c4004452d555": "0x00000000000000000000000000000000000c4c617356656761734d616e0e526164656e6b6f204a75726f730000176a75726f73726164656e6b6f40676d61696c2e636f6d00000a405261794a75726f73000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714ad342401c1554edb98299ef0de2ffb12a98370326e70ac683862c78d592970f7294244c1fb370d4e": "0x04000000000200000000000000000000000000000000074e6f6465733100000018616c6578616e64616c6578324072616d626c65722e7275000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714ad35c1615f01572956d629a2c80762d412fad9c15d8cc973b463f600895170d43a10ca504b4f454e": "0x040200000002000000000000000000000000000000000852594142494e41001368747470733a2f2f72796162696e612e696f144072796162696e613a6d61747269782e6f726710696e666f4072796162696e612e696f00000b4072796162696e61696f000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714ad8ddc0ca11a0cfc2cc3c4f5e22e3a59a0ca34de4ed55e532bb842ea36626ccab7a01378dbcffc31": "0x00000000000000000000000000000000000000000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714ad968b9e29de99cf0c705f5ccd12c95bddf10c698f7cbb92d224b099fc759f5f9e1ebf220a685972": "0x00000000000000000000000000000000000753515541445a0000001873717561647a636f727070726f40676d61696c2e636f6d0000094053515541445a5f000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714adaaaeb1d3993c798ac9852f42ff7fde06bd98fb2c2c4b3f18ecc0d7117cefc3acffca60a86a395d": "0x000000000000000000000000000000000006454a56494900000011656a6463303740676d61696c2e636f6d00000940454a4443417274000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714adaacbddd276fad892b68c8f6d36b8ca3bf3f31c200750ef773419b294216127f2aaeed9834e8f12": "0x00000000000000000000000000000000000d414e494d45204c4547414359001e68747470733a2f2f646973636f72642e67672f416743557a44353737760019616e696d656c65676163796e667440676d61696c2e636f6d00000f40616e696d655f6c65676163795f000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714adb4fe3a15170520a6659e4c3f22c2aa97d54a36e31ab57a617af62bd43ec62ed570771492069270": "0x040100000002000000000000000000000000000000000a525454492d353232300f5261756c20526f6d616e75747469001c407261756c2e727474693a6d61747269782e7061726974792e696f177261756c406a7573746f70656e736f757263652e696f00000b406e6163686f72747469000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714adc1094f94b7e6a19e33f55832314d732b6201019a34e6bee2d0050d05e48792f908927004807d4a": "0x040000000002000000000000000000000000000000001052656420446f67205374616b696e6700000019726564646f672e7374616b696e6740676d61696c2e636f6d000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714adcb6799f01113f1147f672b1be04ef277b6175efd27a5691d4589944175985e37fbd4a50fc49e1f": "0x0000000000000000000000000000000000086c7563696f6377000c6c7563696f63772e65746800126c7563696f637740676d61696c2e636f6d000009406c7563696f6377000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714adf6f4946cd7e9bd36d893f519ad2ade0e563049a74f7f4a629c664344e294f12dcf295dcb9f134b": "0x040000000002000000000000000000000000000000000850727a656d656b001968747470733a2f2f6769746875622e636f6d2f727a616470134070727a656d656b3a7061726974792e696f1270727a656d656b407061726974792e696f000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714adffa60d83e2d26fd63749b70cd25854d6accabefa8939f92bd2034e19b32deb67130ab0141c3228": "0x000000000000000000000000000000000003494f00000016494f37384f494070726f746f6e6d61696c2e636f6d00000840494f37384f49000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714ae0f2e475df6cdca56b0bce13b96ed2d2e3d93cb0b96d21117352df2d473fdd111ac7febbd721a3b": "0x000000000000000000000000000000000008416c69736177790841627562616b7200000000000b40616c69736177793031000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714ae19368d93e1a11446ac55edf7126c062f60ddf13c421406126155fe5377abc33bec6e7ec9b98f54": "0x00000000000000000000000000000000000a4c6f7942616c646f6e0c4b61726c2042616c646f6e2168747470733a2f2f7777772e6c696e6b6465636b2e6d652f6b61726c62616c64001962616c646f6e6b61726c6b61726c40676d61696c2e636f6d00000d406b61726c5f62616c646f6e000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714ae19ce23547ca726ec822a69ea8e95513f81967b0c048386598a107c88c49dae54f1d94b0cba802c": "0x00000000000000000000000000000000000e416273747261637420536563740b54796c657220526f776500000f746a726f776531406d652e636f6d00000e40416273747261637453656374000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714ae1a5c36a02b18e9103a9ebd690d8e1dd5e8f3cb43b05586bbfbd8c36ce3e976b6f45da4a60ff01d": "0x00000000000000000000000000000000000f42696e616e63655f6b736d5f32350f42696e616e63655f6b736d5f3235000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714ae2793d04574eccc063443a7dc2c49d6256a61c92bb0515ce6a641bacf9b42c9ec78b913f72c470f": "0x0000000000000000000000000000000000075069706c6f70075069706c6f7001010100000a405069706c6f707070000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714ae29da2b825c96019285049cf1f37e3e312e2367a3768fb066598d309d4a4ccacfb70137714a4404": "0x00000000000000000000000000000000000f42494e414e43455f4b534d5f31380f42494e414e43455f4b534d5f3138000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714ae2ca4581ebd097944e0753f9e387f2ad25607a94c8e17afe7fc505d65bf7de78d4e87d4a8804414": "0x0000000000000000000000000000000000184b7573616d6120447261676f6e7320547265617375727900000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714ae35f46bc40f624a76488519b246e6c8fc7ddc438a876db42446cfbe25ee73a873e696775821615d": "0x00000000000000000000000000000000000f546865756e69746d6f6e7374657200000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714ae37ed4115e2f104feb895bf0e5923afd22e8edecfb4a9ce6263d447ba45375dc4d280ec0d3d1a16": "0x08000000000100902f500900000000000000000000000100000002000000000000000000000000000000000a41554449542e6f6e65001268747470733a2f2f61756469742e6f6e6516406c6974746c656972643a6d61747269782e6f72671068656c6c6f4061756469742e6f6e65000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714ae47ffa8b83cf8eb1cfd7bfee0e9629e1fc2a35a40fedf43436915a1d1a14604d788eb0a5cd12442": "0x00000000000000000000000000000000000c64656c616273747564696f00000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714ae4964a1652132ffe242bf627ae3347d67991e1b2ebff0a013bcf27ddb96c5cc4c09f1720bbf8471": "0x040100000002000000000000000000000000000000000847616e6a616c6601010115617269735f6b6f6e3934407961686f6f2e636f6d0000104047616e6a61496654686547726579000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714ae81b3857066f7b0202a4b121f7c19db32d07246ca42ba38faaf82f5d7fbb929d6c35ace78f4d521": "0x00000000000000000000000000000000000a4f6c6568204d656c6c00000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714ae93bd56eb26fefac88b7d581246140ac334a9701a6b63b609c0e4d1e0a4dc7ed518093e7977c265": "0x00000000000000000000000000000000000000000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714ae9b31f551254fb3ea1751759b8191b2b400bfe38b56f0442edb875c3390c2af3c1edeb2892f300a": "0x04000000000100902f500900000000000000000000000000000000000000000000000000000008436c61697265650000001a6b6c61616161726b61614070726f746f6e6d61696c2e636f6d00000f4044655f6c756e65436c61697265000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714ae9ba12db96645e32c24642cef14e77315bf467c00917c749a19c3e5a6df705548a67aa7ad0ad138": "0x040000000002000000000000000000000000000000000b504f4c4b41574f524c440b504f4c4b41574f524c441c68747470733a2f2f7777772e706f6c6b61776f726c642e6f72672f1740706f6c6b61776f726c643a6d61747269782e6f72671c7869616f6a69652e70616e674066786861736862616e672e636f6d00001040706f6c6b61776f726c645f6f7267000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714aea617318e829b5f12ae4cc150cef3f9e224d7b6cb10383e91a355a9c9052e21c1c638dbebab9921": "0x00000000000000000000000000000000001d57696c6c69616d207c205061726176657273652054616c69736d616e000016407265706c67686f73743a6d61747269782e6f72671577696c6c69616d4074616c69736d616e2e78797a000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714aeb7ceb911a5fe458c2f8f1570391214b89f82df1e2e0c12f9e2e814cc8e38b3d8baf3692724a311": "0x040000000002000000000000000000000000000000000b44656c6567612050726f0000001c7061756c6574746576616e686f6573656e40676d61696c2e636f6d000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714aebcdd1a0eab5430c284a353b40066c06ccde4c573083785d245d5b2838c1ee1281f09c14f0c4b3e": "0x040000000002000000000000000000000000000000000a50757261205669646100001c40707572612e766964612e6e6f6465733a6d61747269782e6f72671a707572612e766964612e6e6f64657340676d61696c2e636f6d00000f4050757261566964614e6f6465730010707572612e766964612e6e6f64657300", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714aebd88238d3a6853e4340b480dc1067cc6eed90dbfbb55eccbf4b290860eac100caac06cf7bfe50f": "0x00000000000000000000000000000000000c536c75675468756767696e01010101000001000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714aebfc4a3abbe2861e2b2f3f1826834a30b035da7502c657d702287f295c944292ceca13436f2525f": "0x00000000000000000000000000000000000b6a6a706f6c6b616465780000001a6a61796173696e6768616c3230323140676d61696c2e636f6d000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714aec040a9a30c2fa408dda0877b73535dd8e892916397ac9ceccb44b8441122bb434b17e2db376d03": "0x040000000002000000000000000000000000000000000c636172626f6e7a65724f33001768747470733a2f2f636172626f6e7a65726f332e696f001c7374616b652e636172626f6e7a65726f3340676d61696c2e636f6d00000d40636172626f6e7a65723033000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714af08e5f294e1dbf3e08ca157a6b33c275a3141a8f1d0d26fdb69cdfabcd9bbbc04121009ab9eac6d": "0x00000000000000000000000000000000000c416e647265772044697a7a00000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714af0f194ca5eedf8696cfb23cc08b9267a778c38e9aba684d2708786813c14ced80a51c32014e8c17": "0x00000000000000000000000000000000001067697073797472616465722e646f740c6769707379747261646572010101000001000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714af17ae08f9526c52d2eeb4ca57167ef272dd79a7e07be6b9e0f825932c46bc21e64c9d4d96c80f47": "0x0000000000000000000000000000000000074b7573616d6100000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714af1c32392abb5cec8884900b83686025314b36118c490de387482dd7aa54c1fe3ae3f3b74cd0f347": "0x00000000000000000000000000000000000000000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714af26cecf04b0d6f91a48da57cd9e71d434c2c4c043d7304ab2d0b4f04db9194f6bcb1a7d5cc7b822": "0x0400000000020000000000000000000000000000000007726f64696f6e00001a40726f64696f6e706170613030373a6d61747269782e6f726718726f64696f6e7061706130303740676d61696c2e636f6d00001040526f64696f6e3034373039393331000f726f64696f6e303037233535353300", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714af2cc3fd6d2f53af265f0277528dda506dfc7451261a78f74b159bf1032d917b8622657d0fcffc4f": "0x00000000000000000000000000000000001d526f6d65726f2074686520446567656e65726174652041727469737401010101000001000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714af36192670e89a839ecb437788f1e911c3a324b0d377b46bc2e56ecd68cdc11f827f3edf81e7a23f": "0x0000000000000000000000000000000000094a616465204b6f6101010101000001000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714af36a552655d8727a03a7d4a2e5b472c56e6282ab563aa3c9dbe1fcd82f2d954ef86d8c67c89575d": "0x0000000000000000000000000000000000106361727465697261206b7573616d6100000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714af64089eb873bdca2ce5f06beaee8b512f2cbb5192296ad4c2ff3359fdc2cea9cd613903a7c8360b": "0x04010000000100fc8d0e800000000000000000000000000000000000000000000000000000000d506f6f646c65546f794e46540d506f6f646c65546f794e46541f68747470733a2f2f6c696e6b74722e65652f506f6f646c65546f794e46540017706f6f646c65746f796e667440676d61696c2e636f6d00000e40506f6f646c65546f794e4654000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714af8778444f4de017a26dac20e5b6200fcbbd2fe377f3db8101a7ac0f97dcd30cf21a9ebef4728d2f": "0x0000000000000000000000000000000000084570697374656d000000196570697374656d6963726973697340676d61696c2e636f6d00000d40496361727573526973656e000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714af92c79ba730b3d974494d37fcd7c5ba35a87b4d9a5c86a890b4b10e0c00e935ef4a8d0853428637": "0x0000000000000000000000000000000000084e464b2044414f001e68747470733a2f2f646973636f72642e67672f355550763242475565530000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714af98277273da6e43692f87b14dc9169f22bbe981d976de2d7fc7495c361dafc154eb21a03c5035a2": "0x040000000002000000000000000000000000000000000d4c494e4b45523639f09f8ead0000001530786c696e6b6572363940676d61696c2e636f6d00000c4030786c696e6b65723639000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714af9993b81e5473d034a31d751a0ec52fbf411513a3cee3c7c6c1a2c2bacc3f809f3ead9eb9bae348": "0x0000000000000000000000000000000000064e696e654600000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714af9ae6e4f434181d9c322cfa42b80ffb1fa0a096ffbbe08ff44423ea7e6626183ba14bfb20c98c53": "0x040100000002000000000000000000000000000000000c456e73526174696f6e6973001c68747470733a2f2f726f626f6e6f6d6963732e6e6574776f726b2f1840656e73726174696f6e69733a6d61747269782e6f7267166c7340726f626f6e6f6d6963732e6e6574776f726b00000d40456e73526174696f6e6973000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714afa63c93073adc978e06bfc989509d6d625c085209adb405867bdbe4f167ded7e61ec126c683165d": "0x040000000002000000000000000000000000000000000653617368610000000d68694073617368612e696e6b000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714afab87883b2986dc6ee5ad3ea0da40510f11f42c3281fd543f5a6bfad54ebef7381a7320bb509a0d": "0x0400000000020000000000000000000000000000000010477572755374616b696e67f09f91b3001868747470733a2f2f677572757374616b696e672e636f6d1840677572757374616b696e673a6d61747269782e6f7267167374616b6540677572757374616b696e672e636f6d00000d40477572755374616b696e67000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714afc3bdc7245962d07c9f7a1b77cd672ba9c9f01a933ce98effbc36bb57503a4f671bc6f01e25f335": "0x00000000000000000000000000000000000862796e61745f5f114e6174616c69612053616c64697661721968747470733a2f2f6c696e6b74722e65652f62796e61745f00000000094062796e61745f5f000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714afdc8afb93fda6f506a3316928fa06115766132478d1e7b9385bea8e0e411a8c6056f12b3d13ce7c": "0x000000000000000000000000000000000014395374616b652028436f6e74726f6c6c65722900000017397374616b652b6b7573616d6140396761672e636f6d000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714afddd653b3cc45ff4036da32f7b6ae9df4e3f7e29f2f0c3e42d893976c993633b952bd8c8754d408": "0x00000000000000000000000000000000000b416c6578204d616e74610000000000000e40737469673330385f74727565000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714afdded1663a63773142eba87db082b693b5f35e88d7a70409b0ddb61d430abf218884d4467af1024": "0x00000000000000000000000000000000000b4441524b464f5245535400000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714aff1fbb6c9b02bcf8213f1a5a5efc5379fc21131f5c9425dfef0f628cc858c2d54b713e96b1f607b": "0x000000000000000000000000000000000007436f6666656500000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714aff2ef9eab1786a6a680f1d3b6abc1351b6b0afd91a54c1d466b7820abeda0bb7e059513a4d80c04": "0x040000000002000000000000000000000000000000000b4e61706143727970746f00000013746f74657374656b40676d61696c2e636f6d00000b40546f74657374656b31000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714b009963bd6cf7f553e3fedc679e48594357377ab604693db948db02922e5f7f1740581d1d6fc3608": "0x0000000000000000000000000000000000154b75626942697420496e64657820536861726573000000000000104074686567616c6c65727931313131000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714b05ea025efa6e1a0aac311fdc8e841ba529158c0da3b3b0e1efabbeb980b2186d7f6194388da6131": "0x00000000000000000000000000000000000668756f626900000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714b0726c73592fd7dcacd0b478fd9586fcfde7d71aaf49bab9777e0e1ccfeef5d5922bfe68fe68c96b": "0x040000000002000000000000000000000000000000001053756c74616e4f665374616b696e67002168747470733a2f2f7777772e73756c74616e6f667374616b696e672e636f6d2f204073756c74616e6f667374616b696e672e636f6d3a6d61747269782e6f72671f73756c74616e6f667374616b696e674070726f746f6e6d61696c2e636f6d0000114053756c74616e4f665374616b696e67000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714b0a155d537be68bc40c46bdf410fc4998d2413619de53b7cf4619abca4e8ad87d8a3adc50ec73f2a": "0x0000000000000000000000000000000000086b75736d616d61001c7777772e696e7374616772616d2e636f6d2f6b75736d697465636100146b75736d697465636140676d61696c2e636f6d00000b406b75736d6974656361000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714b0ac057a255285ea7000a09ee477781f180c3ce5ead45d6ed8d92d24a5abcfec3f24837c38ca1a40": "0x0000000000000000000000000000000000085348525553484100000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714b0c27f90ac9d10a58adc4e19e79b3d2c744f88fa5aca47ef05ccaae141f6435c2d50df824433ae48": "0x04000000000200000000000000000000000000000000144859504552535048455245204449474954414c001d68747470733a2f2f68797065727370686572652e76656e747572657311406876616c3a6d61747269782e6f72672076616c696461746f72734068797065727370686572652e76656e747572657300000e4068797065727370686572655f000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714b0c82179e29e010760c9cc0b9b314c31215486883e1b0ee9faf0a64ec4c9abbde63e53855bdc2219": "0x040000000002000000000000000000000000000000000568696d65000018406c696768746e696e6773623a6d61747269782e6f72670b73624068696d652e616900000e404c696768746e696e675f444e000c4c696768746e696e67534200", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714b0e8c1857841459cc005652d40096e4fe6d2ac773d8834e30e31ec39e455f5116ab76176f2b30166": "0x00000000000000000000000000000000000757616c6b65720c4164616d2057616c6b65720000186164616d77616c6b657238344069636c6f75642e636f6d000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714b0f0b3ac307cd751749ddc93a65dfec3af27cc7478212cb7d4b0c0357fef35a0163966ab5333b757": "0x04020000000200000000000000000000000000000000094b6565704e6f6465094b6565704e6f64650d6b6565706e6f64652e78797a11404472756e3a6d61747269782e6f7267156472756e2e6d6167696340676d61696c2e636f6d00000a404b6565704e6f6465000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714b0fe6b98334d7d6cc4516751df2e5803bac3bf9cf7b6d55cf4acbd76f861ad0a2a2b71b7a5ed8054": "0x04000000000100902f500900000000000000000000000000000000000000000000000000000010626c6f636b6461656d6f6ef09f988800000018737570706f727440626c6f636b6461656d6f6e2e636f6d00000f40426c6f636b6461656d6f6e4851000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714b10065a77e52723a249ac734e3c93c449fb84dc63e3305a8bf8280ecb3fce23f8b59fc4d22695264": "0x0000000000000000000000000000000000074b734d6f6f6e000000146b736d6f6f6e70726f40676d61696c2e636f6d000009404b734d6f6f6e5f000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714b11058f1454ffb44d2d09f95d0f12add7c3917ee547d24ed7e1f11bb5d93a1c59fe79c1305604128": "0x00000000000000000000000000000000000a5472757374426173650a5472757374426173651a68747470733a2f2f7472757374626173652e6e6574776f726b000000000f405472757374426173655f4e6574000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714b11aaa4195d2ac6dce35dca783c5b947a69d789c5d3f10e3e2a5177321d1e6bf88a7e7b46c57d329": "0x00000000000000000000000000000000000f546865204461696c79204d696e7400000000000011405468654461696c794d696e744e4654000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714b16947c55a8fcdca9cee29ac72489e226911a3e13cc12e83655f3b2ba98c72760cd8e066c5f6bb1c": "0x00000000000000000000000000000000000b4d725069c3b1614b534d00000017636c617564696f70696e616340676d61696c2e636f6d00000d404d7250696e6170706c655f000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714b171be44e280759d380e0679794d9d5b8202444c893a17cff2cd2e65e76d095eeefaaa9362a3cf42": "0x0000000000000000000000000000000000057065706f000017407065706f6f7370696e613a6d61747269782e6f72670f7065706f4075707274636c2e696f00000c407065706f6f7370696e61000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714b173257b17c32ecd724b7e940995b11d1e65f91a3ce3362429f941dacb9ad3e278acce9325308213": "0x00000000000000000000000000000000000841727563616e75000000000000094041727563616e75000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714b181c04016578e69dcbc0885fe08b19fc1a3c71b5a62c5710b6da20a20b3730c58a52c51ac567e30": "0x040100000002000000000000000000000000000000000c57616c6c6574792e6f72670c57616c6c6574792e6f72671468747470733a2f2f77616c6c6574792e6f7267174077616c6c6574796f72673a6d61747269782e6f72671268656c6c6f4077616c6c6574792e6f726700000c4057616c6c6574794f7267000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714b19b71d671b6baa2aad8e905d4c09ac501fc3f74833019107288077bdaa77291588b5e021330657c": "0x0400000000020000000000000000000000000000000010534d4152542d4b5553414d4120535400000015736d617274617034303640676d61696c2e636f6d000000001440736d61727461703a6d61747269782e6f726700", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714b19c3eac0c4c1de9dcc1c3cc78ba39c3d7b416dd47da6dd8a5fde83f454a55157caa477b5fb0c734": "0x00000000000000000000000000000000000b44617277696e4475646500000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714b1a4415d3fe3b73f4cd5f7ee69df1d1fb53e664569fef68fcb2d7dfd9113107d6b108e5c27e2a725": "0x00000000000000000000000000000000000f506f2d4b7520547265617375727900000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714b1b49b2e110517e354722d3648065cb3c0ee5de9ef5d7161e707e317fc897b2b109b062520f0ed23": "0x00000000000000000000000000000000000a4952594e4120322e3000000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714b1ef8d6360daf3d016f1f5077a316bcc580964e83ce2af8c24574233aa13883fd4c9e37425fe5671": "0x000000000000000000000000000000000010524d524b2041756374696f6e656572001168747470733a2f2f726d726b2e6170700011636f6e7461637440726d726b2e61707000000940526d726b417070000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714b1f5b788e8cb3020222f4af632639b2a6c24dfc4532b82a49c4d1010cb324bc98c8223ee2003cb6c": "0x00000000000000000000000000000000000e3120666f7220746865204b75730000000000000f405468654b7573616d617269616e000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714b1f8cc3f226516048828d861f59282edb359070315c4b6e20be9ddd0ef58de47512c3d98b628c72b": "0x00000000000000000000000000000000000d4c6974746c654f6e6770696e0000000000000b40636f72746578726164000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714b21612d15cfbf7080ec594c4b9d16ea738e3c034498ea20655423f3861fd2df568ae379751cca262": "0x040000000002000000000000000000000000000000000d636c6f75647374616b696e67000013406d6f6761616c3a6d61747269782e6f726713686940636c6f75647374616b696e672e696f00000f40636c6f75645f7374616b696e67000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714b2315ce9bb1e5e9af89ed17c957b4a6de1ee5f3a36f7eeff3b5e53aba13792e64e471ee8775b6b31": "0x000000000000000000000000000000000004496b7501010101000001000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714b243ac33f5105fa6c01379a41a162af5a91e480a73369c4dd773a1ad16759a44cd3bb6935cd67e3e": "0x040100000002000000000000000000000000000000000b4b7573616d61204d4841000000196d686163727970746f4070726f746f6e6d61696c2e636f6d000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714b246a1c9081ca716a86d962e9922cd2213f9ea746767e3513957f86a335d940c8529d8357c106413": "0x040100000002000000000000000000000000000000000c5a4b5620436f756e63696c001868747470733a2f2f7a6b76616c696461746f722e636f6d001577696c6c407a6b76616c696461746f722e636f6d000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714b25006accff8cd9d064ee3e94e269dfcf8d09d4e0980bb3123ca16dc734304128e328bb5a40f575f": "0x0000000000000000000000000000000000074d6179776169000000156d61797761692e6b736d40676d61696c2e636f6d00000c406d61797761695f6b736d000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714b257cc47df162822949b344d8706a170108f20aa5457fb62d19ac4d1edd7bb450b07f6790d16283d": "0x000000000000000000000000000000000007446573796e63074d616e75656c00000000000c405f4d616e75656c5f4c5f000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714b260711c449324e13e1a3571a435d9e2de0a5336428458e38e0e0c84179450ebe4466b5db8efea76": "0x040000000002000000000000000000000000000000001949204c6f76652043726970746f202d204375726163696f6e0000001e616c62657274706f6c6b61646f74737061696e40676d61696c2e636f6d00000f40495f4c6f76655f43726970746f000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714b2850a82780da820548a3bc51f5f2ff006d0dd63d17248752bd6b46800314a689f69ef9f3570937d": "0x04040000000100902f50090000000000000000000000000000000000000000000000000000000a4d6967617373657473174d6173736920496e766573746d656e742047726f75700016406d69676173736574733a6d61747269782e6f726713616c6578406d69676173736574732e636f6d00000c40416c65785f4d61737369000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714b2a0c16700350d52421185b141843818f93549a95880537b331573bad5cddc5b42856740ef3d2546": "0x0000000000000000000000000000000000085a7a2e2e5a454e00000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714b2a2c140593529fde6d8480e3a48bbdf79da217e7e017b06513f25276f3474773d5cac5ccd7eb96a": "0x0000000000000000000000000000000000104c6f76656c792043617472696e6173000000196c6f76656c7963617472696e617340676d61696c2e636f6d0000104043617472696e61734c6f76656c79000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714b2aa0fcea34ca1baca3fe10047d713cd9fab0a5e42e48ca47378781652f40f19edc6cd1fbe815e60": "0x000000000000000000000000000000000012636170656c696e686f732d7061796f757400000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714b2ac9fe1e9a7f5470ec778d2cc791b2d30c6d1986418f864b5c5f9032b52c59083e48f77d8618001": "0x00000000000000000000000000000000000879646473626c6c0879646473626c6c1468747470733a2f2f79646473626c6c2e6f7267001f79646473626c6c5f7374616b696e674070726f746f6e6d61696c2e636f6d00000e4079646473626c6c5f4e504f53000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714b2ccbd867d990e4d2c17be94b5327001650a4bb5cea4a3673c99c9c55b1ca911ab72703b50d8a742": "0x000000000000000000000000000000000012446f744b7520506170657257616c6c657400000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714b2e76be759cb39c0f6a250b388d7fb1233e530d1d2a904ecc28ddd85d0c642e2012f9163cd496c65": "0x0000000000000000000000000000000000084167656e74313301010101000001000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714b2e868baf7804149e881c372e5f6f2b82da4e8a08dfb2a2b463a02ee2228f4c3abb5515ca6a7ff1c": "0x00000000000000000000000000000000000b5468652042726f6b657201010101000001000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714b2f651117e3fd34c84bda1949a2b78bfc3b12dcc8f2c8e8822912efe0c693a23effaf7f3b54e9a5c": "0x040000000002000000000000000000000000000000000b4279746520766973746100000019636172646f6e616a6f636162656440676d61696c2e636f6d000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714b2f76aa3ff10a37e84fc49ce30071ea611731838cc7736113c1ec68fbc47119be8a0805066df9b2b": "0x04010000000200000000000000000000000000000000134475646f3530207c20506172615370656c6c0d447573616e204d6f726861631d68747470733a2f2f6769746875622e636f6d2f706172617370656c6c00166475646f2e6d6f7268616340676d61696c2e636f6d000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714b3074442a3a8a9ae98e9edd65f5caf8136db93b2f8213f4f91637ee4facff286fd491f904d691f75": "0x04040000000100902f5009000000000000000000000000000000000000000000000000000000086d657472696b610d4d657472696b6120496e632e1768747470733a2f2f7777772e6d657472696b612e636f0010696e666f406d657472696b612e636f000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714b30a0d7012b77142a86620314a174486a9938856e3b939de3bcd73458780f542388be0cd66379e28": "0x04010000000200000000000000000000000000000000124b52414e412e5620f09f9a8020f09f8c9900001b406b72616e615f76656e74757265733a6d61747269782e6f726717737570706f7274406b72616e612e76656e7475726573000010406b72616e615f76656e7475726573000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714b341499a31d863421ebbb4642a0056d17938932a9c46aec001297bc51e0b4a9dc2a1eb730a9fe521": "0x00000000000000000000000000000000000101010117353275316a79737437327969406f706179712e636f6d000001000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714b342eacf1a7bb7924440fa58f447b221d6353497312ea0c1596f7d688b84fd0f55e68ed89c3f1827": "0x00000000000000000000000000000000000101010101000001000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714b34bc4a4815f0a13cde66d4751e5ba025658b0f605dddb25a3ed08c9dd54e597304ba7a139706e00": "0x04000000000100902f50090000000000000000000000000000000000000000000000000000000c5375625374616b65e29ca8094b796c65204c65650015406b796c65796f6f6e3a6d61747269782e6f7267116c6b796f6f6e40676d61696c2e636f6d000000000e4b796c65596f6f6e233339313200", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714b34d53e3735a0db2c0c2bbf240b3e8306ffe68dde3373cd1446bf162f8a09e2f259391f2764d0d39": "0x000000000000000000000000000000000015444543454e5452414c495a454420656e7469747900000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714b357e4ead78873ac2aa53f55efa82a9820f3c2569d4e52dc467475a1a11cfc9861ce5440316edb7a": "0x040000000002000000000000000000000000000000001056656761735f6c6966655f6d61696e001668747470733a2f2f76656761736c6966652e696f2f1440636372697330323a6d61747269782e6f72671876656761736c6966656d61696e40676d61696c2e636f6d0000094063637269736c76000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714b3581561695f63fabce0e8afbf04533cc92ee13d29374cd930e1b65505e2b5d9d3ea672bb4512c1d": "0x00000000000000000000000000000000000a486920496d20426f62104a656c6c65206465205a77617274650000146a64657a776172746540676d61696c2e636f6d00000c404869496d426f6244434c000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714b35c78d2f5f8365e32df05004fe9cc14f3b60a5afc3533aaa519399dc75d5b65d338f3f497ffe156": "0x08000000000100902f50090000000000000000000000040000000100902f50090000000000000000000000000000000000000000000000000000000653796e746800000015796173696e2e73696c4079616e6465782e636f6d00000b4062757977696e726172000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714b35dce1f552fdc17f6e6c46211d81310a08c8b683a6cca98743ad98bd21447687b9f55aebaa9881c": "0x00000000000000000000000000000000000e53706972616c20536f757263650000001a73706972616c736f7572636531303840676d61696c2e636f6d00000e4053706972616c536f75726365000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714b3873b7b002e1c99ee60b67ca3f293af1531a28c25fba9f970bcf4bdcf77181a4a707454d252ee47": "0x0000000000000000000000000000000000076d6c6962747900137777772e6d61726b6f7a7562616b2e636f6d0012746f5f7a7540686f746d61696c2e636f6d00001c68747470733a2f2f747769747465722e636f6d2f406d6c69627479000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714b38b581ee35eb27176d688692159d622d85ab2deed48eafc143c9678d34bc8e6b080f7676187f105": "0x0000000000000000000000000000000000084e594d45545641000015406e796d657476613a2e6d61747269782e6f726700000009406e796d65747661000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714b3a116ce56e09a4ad6166cf88da98fb2caa21af4f23c89b489c65faf585fb0015f74bbaafca8ff01": "0x00000000000000000000000000000000000b7374616b65617765656200000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714b3bbe235e317bb0ec8205518d8e268b0ff306b684cda2b22bb68c4ecbeea54f377fb9d1481699b3e": "0x00000000000000000000000000000000000666722e6f6d001a7777772e696e7374616772616d2e636f6d2f6e6f6e656d7963000f6d79636f6c40696e626f782e6c7600000f404d79636f6c4e65706574726f76000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714b3f32eef5a4f87c32658b40ec2b02f94d22dc082219558da0be0a3a902a9e33445a81fe75fd41e43": "0x00000000000000000000000000000000001647656d2048756e746572207c20524d524b204f2e47074b696572616e00000000000d40646567656e646f74636f6d000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714b3f50e5d25996acc8c6c261024db524af0eb5c2f6a913875a2b1be99ae03f2e7ae461f1a62201648": "0x040100000002000000000000000000000000000000001053706865726520f09f87a6f09f87ba11454f53706865726520507479204c74641868747470733a2f2f7777772e656f7370686572652e696f1540726f7373636f39393a6d61747269782e6f726711726f737340656f7370686572652e696f00000d40656f7370686572655f696f000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714b40191c2f127f31a083c4c20b076d878baa0815fcfeb5f93a60d9ca7861413d6295ceced417ab876": "0x00000000000000000000000000000000000d4e69676854686f75676874730000001c6e6967687474686f75676874732e6e667440676d61696c2e636f6d000010404e6967687474686f75676874734e000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714b40757a983c744376e2a534e0403f363633ed63219a73fb31ba077f03fcc1a4818ade82dd77f9077": "0x00000000000000000000000000000000000d6e696b6b695f73756e73657400000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714b40975722af3500702088d2b822148eedc93dc55bd7b4e890a44b783233aa936e9ff714df1fb2351": "0x000000000000000000000000000000000007576574657a32001568747470733a2f2f7777772e776574657a2e696f0000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714b4113e7993545da1482bd6f002eaa6a7affb7e570fbff9878771a213873c31dc6f5c20d15c10ce64": "0x00000000000000000000000000000000000c5577652043657272726f6e0016687474703a2f2f757765636572726f6e2e636f6d2f0014757765636572726f6e40676d61696c2e636f6d000007407577656365000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714b415242948e48c4af65b2541075f4ab6dd22df200f9a5d19a3c65ee8e16f10a04d390a33f9550c7e": "0x00000000000000000000000000000000000742726f736b6901010101000001000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714b42bd9796193505f78f29bdb93bce99ebfaf2d05f45e3b0cc5e20cc3655b00c7a87efd0714b6b221": "0x00000000000000000000000000000000000a677265657a626c6f67000d677265657a626c6f672e7275001361646d696e40677265657a626c6f672e727500000b40677265657a626c6f67000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714b444a082a34087094c1dbf673aeb1c17f8f51c2fdbeef84d02a33a8ed3f558ccd48b744a3a7dad7c": "0x00000000000000000000000000000000000000000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714b448e5a7e01085b6d6f077ab8fa173ff524e3b4a8f7c4216cdc06bc76c3b620547a929b5ec6ea834": "0x00000000000000000000000000000000000c477265676720466972737400000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714b455b694dad128e9722c9b4173ba6950b862740bf60abb3b081012e3a5bed9e7ec139666f0690f1c": "0x00000000000000000000000000000000000f4d65746176657273654368696c64000000196d65746176657273656368696c6440676d61696c2e636f6d000010404d65746176657273654368696c64000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714b46f79823607ed8672ded8001e89fb9e5f2e7a9eb1913ab57211a7efc262a58b68c0af4db193f05c": "0x000000000000000000000000000000000012696c696120524d524b2047616c6c6572790000000e696c696140726d726b2e61707000000b40696c69615f6f6e6963000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714b4736827e2622569824651190f1d20237fea2d5953bb53ec59df25d581e54f291d6978c9a8017741": "0x040000000002000000000000000000000000000000000d536d6172742043686f69636500000019736d61727476616c696461746f724070726f746f6e2e6d65000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714b4763e158852db7edea87703a49b3e2cd535dbb0187c3dc240dc585cedc7215d31b6f5b5e6be1309": "0x00000000000000000000000000000000000000000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714b47781cbd1ef364b044921f1a8a44f37ee55978961047fbeecc19c2529c73d367847ef04dbdfb852": "0x000000000000000000000000000000000007427562626c330000000000000a40536562636c653339000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714b48b1b8f79a7433f88b9f3a722747e8f637b2583963ea7f1215adc8c75c3957554fdf92fcbfa5034": "0x040000000002000000000000000000000000000000000858616c616d75730000144078616c616d75733a6d61747269782e6f7267136b7573616d614078616c616d75732e78797a000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714b4d902a5e3ceaacbe2c0be196404087dd756eb35190f731531a6e66ab6a157d9e8755a0b1ce8157b": "0x04000000000200000000000000000000000000000000093832344d616d62610000001b3832346d616d62616e657665726f757440676d61696c2e636f6d000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714b4dfa73f600178ff3a9e64ec8308c39b8ec28ac2e7bb6e6eba1ca2fb8a87dc446e0fa3b232f84648": "0x00000000000000000000000000000000000000000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714b4e729082bc0effa0c691601793de060491dab143dfae19f5f6413d4ce4c363637e5ceacb2836a4e": "0x04000000000200000000000000000000000000000000064c65656d6f000000166c65656d6f407468656368616f7364616f2e636f6d000009404c65656d6f5844000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714b4f035960b0d010c102ecd1c98119bb49b5fdcdde4160e597892cb30aa1aa3a40dafe3717e59a74a": "0x040500000002000000000000000000000000000000000e4e494b48494c2052414e4a414e0e4e494b48494c2052414e4a414e0000156e696b6c61626838313140676d61696c2e636f6d0000086e696b6c616268000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714b4f0c4c16f8fc06e34d5e51cae79df0f3ee7229078ab968d7f9948de296c0fa8b5d92d574f269506": "0x00000000000000000000000000000000000a41746c616e7469636100000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714b52e4d96f225ba523ed709144add542687b9827a767b3291f991d568f2cb27662f0ffd5f55c74945": "0x00000000000000000000000000000000001243616c69737468656e696373627261696e0753696d6f6e651d687474703a2f2f7777772e76756c63616e6f6669746e6573732e6974001b696e666f4063616c69737468656e696373627261696e2e636f6d000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714b5421b6506f7f790ac59122f8bc8c527a8efde87156403558ea66ca0ef049cf3fa4f671f98517d61": "0x00000000000000000000000000000000000b4441524b464f5245535400000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714b552fbf6f1a1b77a86c3585c906e4928f030b4735d375cee0410db104908788133281b53533b5633": "0x00000000000000000000000000000000000853616e6368657a0000001473616e63687365706840676d61696c2e636f6d00000b4073616e63687a657068000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714b56cbcafeb6c89004cd9ac314578bf2f172acdadfb93f39a59794ac258b7de50c38814f4187a5d35": "0x00000000000000000000000000000000000d6265726e61746665727265730e4265726e617420466572726573010101000001000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714b574900a55849d7c2c30c7923251b4c2b6ac0a13589e931912e35672c525d05a9ccb48bc19a7db4c": "0x00000000000000000000000000000000000a43727970746f5349440000001563727970746f6f73696440676d61696c2e636f6d000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714b584e1a4194b9d21fea234d679d4dc45e5e2373fec6e40659bf0e6918ff73502cea99ee7e7e9f750": "0x0400000000020000000000000000000000000000000010726f616473776974686f7574656e640000001774617469616e612e6d6b686e40676d61696c2e636f6d0000000015726f616473776974686f7574656e64233331303000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714b5857832389789b78af348b187a2e94f7dfcacc1de5c71b55f6ab8a50e75f0ac1a15baeebfd92e03": "0x0400000000020000000000000000000000000000000010472720457870656374204368616f7300000015672e756e69743234383140676d61696c2e636f6d00000b4067756e697433313234000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714b59303ef0c9246ef0e58776f7b5ac468803ca692cda97289cbc6412e2c8dd832f30d74bd480f7529": "0x00000000000000000000000000000000000e736c696d74726164792e4e46540e736c696d74726164792e4e4654000018736c696d74726164792e4e46544070726f746f6e2e6d6500000e40736c696d74726164794e4654000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714b5bfb9c15abda4d344fd0dd3c86f7bac5e3c502d08bd06add439cd568af4ae1399ad617764c84349": "0x00000000000000000000000000000000001a446f7473616d61204368726973746d6173204368617269747900000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714b5c8f247935e6ce99e0bb283b2d2522a090d71d9c8fb484c7966d3e28b21bc513419ef7f70d6a563": "0x040000000002000000000000000000000000000000000a4a41434b464c415348000016406a61636b666c3473683a6d61747269782e6f72671a6a61636b666c617368374070726f746f6e6d61696c2e636f6d00000d404a61636b666c6173685f56000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714b5cbc9967f19afa3e295650fdd71d7046633b1fafd0881a3207719c573f17725fccddf854a8b5628": "0x040000000002000000000000000000000000000000000744617276696e0000184064617276696e30303532343a6d61747269782e6f72671664617276696e323238313640676d61696c2e636f6d0000104064616e7961706f7a6e79616b6f76000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714b5d2b4bc4d7b8aae7673bd5e6320b489eeefbfb7fc372b5aafc3955acdab0592bd1a5dd63b581376": "0x00000000000000000000000000000000000641544c303700000016646f6c61706f746f6b616e40676d61696c2e636f6d00000d40646f6c61706f746f6b616e000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714b5dece0984444d31a0c077265fa8ebb05329c968fe13efc415460cc5c379fb392a652ac07c9c2f7d": "0x04000000000200000000000000000000000000000000125a6574657469632056616c696461746f7200001d407a65746574696376616c696461746f723a6d61747269782e6f72671e6f70657261746f72407a65746574696376616c696461746f722e636f6d000010405a6574696356616c696461746f72000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714b60b504a11ae006d8a26b6e4d6934f03e3f094197206bf224c8e863582b77c794141eef1719b2f60": "0x0000000000000000000000000000000000084d6f6f6e4d616e0101010100000b406d6f6f6e6d616e3831000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714b61c69cf9ed79934d275000318be3386cdc343eb0d5dec56f65b8954a6946576b773e6eebc27e169": "0x000000000000000000000000000000000016425241204355454e5441204445205052554542415300000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714b62acaa32f7e218efcc5b90bc1891b7d905423f7a00ffb4e8f3d59aa97491b5a1d45b82548639936": "0x040000000002000000000000000000000000000000000a547574694672757469000000156b7573616d614074656c7574696f6e732e636f6d000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714b62b777d8f1d409cc2533fecb62aa788edf60c15825bc7ecdb4516096007dd24b8a858d5c4434920": "0x0000000000000000000000000000000000054641444500000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714b63533e1e147f27d823265fcc4b6ca5e77e4fdeb4c6ff019564e3afa70a44edc1cbeb13a175dc365": "0x0000000000000000000000000000000000125374616d7020466f7220556b7261696e65125374616d7020466f7220556b7261696e65000000000011405374616d70466f72556b7261696e65000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714b643ba1f89b73794ea3fb9aa4efc85db2a51959b1654caeb11576dededff098bf4692440e75cbf2b": "0x00000000000000000000000000000000000d43726970746f6d6973686b611cd09cd0b8d185d0b0d0b8d0bb20d0a0d0b0d0bad0bed0b2d0b8d18700001763726970746f6d6973686b614079616e6465782e727500000e4063726970746f6d6973686b61000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714b672def05cb0d96f4e35d916c13e4bc55676d21e94120d4e27e10e1c9aa9e0fae59434ea8856817f": "0x00000000000000000000000000000000000847696c73616d610101010100000e406b736d767374686577726c64000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714b67386b3a2bca62fa6805c6dc7757cea227e11839257d4e24ad39520621e99e6016ee0e1907c3315": "0x08000000000100902f50090000000000000000000000010000000200000000000000000000000000000000034d430c4d61726b204372696e63650000156d61726b6372696e636540676d61696c2e636f6d000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714b67f107771c3b26f78daf5556df89f21e14e2e07a132f523aba6a03c21792d14f7d41a5192c53453": "0x000000000000000000000000000000000019437265657079467269656e646c79436f6c6c656374697665001c68747470733a2f2f637265657079667269656e646c792e636f6d2f001f637265657079667269656e646c79636f6c6c65637469766540676d61696c000010404372656570794f726967696e616c000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714b69333f8c0d86b1248c2f61e58783887d3652c07bc6bcddffa6373246c2f2b5270e7d5d3b57af315": "0x04000000000100902f5009000000000000000000000000000000000000000000000000000000105a6569746765697374204d696e65720d5a65697467656973742e706d1668747470733a2f2f7a65697467656973742e706d2f00106869407a65697467656973742e706d00000d405a6569746765697374504d000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714b69339fdfcab0d9f1cbf2d072567bdfeb00359e9d318e7b425a65449eb94b1a8f5ca0c28a9513878": "0x00000000000000000000000000000000000659616d6e650000000000000c406572615f6974616c6961000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714b69e21ddf4af61a05a89c086659b0ae940285ac34a75b3d1e846350f647cd7ac1236377fcd9d4405": "0x00000000000000000000000000000000000c496f616e5f54656d6e7565054976616e00001875736d766964656f363432324069636c6f75642e636f6d000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714b69ffb015d88545c0470d52d80c8f777e2a326e028444cedc0f910af3db5e49ca84751736d086f4a": "0x0000000000000000000000000000000000094c656e6f63686b6100000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714b6a30b89e64a46012419b405a61cdeb929bcc1883a7368b2fba867bd78ff4886800ab56b273ccb3f": "0x00000000000000000000000000000000000452757300000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714b6c8b7052e61ea994437c8a23f1c5d221ddaaee441be0a9f38c638300e2805018abb4e72f7de753e": "0x00000000000000000000000000000000000b5073796368697465637401186c696e6b74722e65652f50737963686974656374417274010100000d40707379636869746563745f000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714b6cfd687de7a23b4d60cf655685824e9966b0a10c01dc8b17b37e24944fdd760e4dd73ff1dd4ac14": "0x040000000002000000000000000000000000000000000e416c74204f72646572204361700000001d616c742e6f726465722e6361704070726f746f6e6d61696c2e636f6d000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714b6d97ff4578c0fe536fdcc8b78421a34a864a6a100bd9426c9f154381739a74f617b7f5988dced32": "0x0000000000000000000000000000000000114b6f6461446f745f7374657761726473001468747470733a2f2f6b6f6461646f742e78797a0000000009404b6f6461446f74000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714b6ecd013f449a75f58f2f7dd26682082ccd78611deeeffb89b38bfe97fe95be7e2047cd8e346ad1d": "0x0401000000020000000000000000000000000000000005474465650c47656f726765732044696200174067656f726765736469623a6d61747269782e6f72671667656f726765732e64696240676d61696c2e636f6d00000d4067656f726765735f646962000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714b6f81cd81eee83ee72559667d3ccc1f96dded8d17e6299c5ff111ae37d9aba73bc7e6cbb53e6dc0d": "0x0000000000000000000000000000000000105468652048756d616e2042697264730000000000000f4054686548756d616e4269726473000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714b70e7e870eb10773f4e890b0badca21d04941659525012545053c6fda2c75381553fb91394b8d92a": "0x000000000000000000000000000000000013466169746820416e6420496e647573747279011d68747470733a2f2f6661697468616e64696e6475737472792e636f6d01206661697468616e64696e6475737472794070726f746f6e6d61696c2e636f6d0000104066616974685f696e647573747279000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714b718fb63dc5e0eca26b4ebe12602aeb02aa9d74a361a687fda2155814b680edeeb26f5159cdce741": "0x00000000000000000000000000000000000d4a415649544f4152524f42410000000000000e406a617669746f6172726f6261000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714b71a89138784643960235425858d04422d3183b91e97c522d39b532a547065d395532b60542b752f": "0x04000000000200000000000000000000000000000000096b6f6b6f72696e390000001b6e696b6974612e642e736f626f6c657640676d61696c2e636f6d00000a404c61676172743073000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714b727995258469c869c9db3e7b4aa077d5df26c65a2f98f8fedc50f8cc445cd7cfc26a96ce57b9654": "0x0000000000000000000000000000000000047373730473737300000c737373407373732e636f6d000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714b7461dfb8eafd0dfeafe7afd0a43dbdf3ed4d2691aa15907978fe457ad52bc326be51cfa098dd865": "0x040100000002000000000000000000000000000000000e6d617274696e2e6a656e73656e164d617274696e204cc3b873657468204a656e73656e0020406d617274696e6c6f65736574686a656e73656e3a6d61747269782e6f72671e6d617274696e6c6f65736574686a656e73656e40676d61696c2e636f6d000010406d617274696e5f5f6a656e73656e000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714b7636fb25a038da49c78b621dbae80aa6797a28f752059eef1abd763dabda3595560a0348ff82e39": "0x080000000002020000000100000000000000000000000000000000000000000000000000000000000000000b5354414b452e5a4f4e4500000010696e666f407374616b652e7a6f6e65000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714b76acca59a92ef07ce072084c159fb3547381b718ac1660d14030e7bcbe9db68eef0f7c0e340f33b": "0x00000000000000000000000000000000000b4441524b464f5245535400000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714b7792dfd8eea068b88b9e241d5bc525d51b2784a4545429311f373202a8fca5706ed6c49141b350a": "0x0000000000000000000000000000000000067265616c4d0000001369636f646f6a616b40676d61696c2e636f6d00000a404b614a6f446f4369000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714b787cc241627881d7edf6c4de505630a4dc222c9de78e78becb4bc08a72277ee786da979ed4d8075": "0x000000000000000000000000000000000006746569646500000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714b789289293d8c850dcf93493400b853ddb07cd0ddf190ac86817206c9ad23dfcd64a480384c8bc0d": "0x0000000000000000000000000000000000074d61726c657900000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714b78cbac72154fae87aa524afbdeb18aa240f0b09780fd634f24ef48d87e5f328cd7471766bfd4c7a": "0x00000000000000000000000000000000000979657668656e69790959657668656e697900001879657668656e6979333939393340676d61696c2e636f6d00000b406672756b7474616a6d000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714b797ee954f7fdc00a0aa404a3a1178f1337564cf2a5a70db2819f832ba23c92346d6b74271928126": "0x04000000000100902f50090000000000000000000000000000000000000000000000000000000e5068616c61204e6574776f726b0e5068616c61204e6574776f726b1668747470733a2f2f7068616c612e6e6574776f726b0014776f726c64407068616c612e6e6574776f726b00000e405068616c614e6574776f726b000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714b7ad4b1d953b9c6d84fc160fbb01b3a8dfee1ec843cf2e3c60cf7062de3c0a7614eb8d79c58dc46b": "0x0000000000000000000000000000000000056d696e6800000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714b7b8b1b5a75ce20d524cf67b5db0c0e6a04d9509f1e6c980623094ad9e870adbd0a7a1b85a11e345": "0x00000000000000000000000000000000000c546f7276616c6420536f6e08546f7276616c6401010100000d40546f7276616c645f536f6e000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714b7bec5191a59492f82230d13be153b9db2876a9b26c9e35486c41aa8c987eb16bcc8909a481b4257": "0x0000000000000000000000000000000000057534696101010101000001000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714b7e08c50407adb61c00f8f18bd12975ae69a9b145cde3835109e4dfe2a18d7da51e98e54b62d703b": "0x0000000000000000000000000000000000084372696d58656e000000136372696d78656e3240676d61696c2e636f6d00000d404372696d58656e5a65726f000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714b7e95879065eb42bfcef3034912f1b6b1bbff67d362083286698d80defff9ab1ea0279da0fd2d83d": "0x00000000000000000000000000000000000b5468652043697263757300000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714b7f3be7246e94277d6ff0e9daf6baadc9aedaafad3db973385df8124cb0e35cf2d183c1539ed4109": "0x0000000000000000000000000000000000114d6175726963696f5f446f7453616d6100000000000011404d6175726963696f446f7453616d61000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714b7ffd9218f5ca5750e0797db0e2ae604c97ba48e3f3490ed781718d28e6c6162fcef61dca4d51404": "0x00000000000000000000000000000000000000000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714b80c4ca47b74cc28b425b49b63e7422dc709b51218af8f981f7d4dbc7745fb2e3b91a64ff3d80570": "0x000000000000000000000000000000000009466f73666f726f73001b696e7374616772616d2e636f6d2f666f73666f726f732e6e6674001e616e647279757368612e66726f6c6f762e393340676d61696c2e636f6d00000d40466f73666f726f734e6674000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714b8114461fdcaf8d8046b4467eec7e673d63c621a3e9cac72b515014c74f9046de1caf79ff798f23b": "0x00000000000000000000000000000000000c496e64696365735f4e465400000016696e64696365735f6e66744070726f746f6e2e6d6500000d40496e64696365735f4e6674000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714b8131ca67ebf42dda6addc873dab36ed63418ecfcaf4e40f6ab30badeae2cae08c5b307d3527eb4d": "0x0000000000000000000000000000000000134b7573616d61204672616e2079204661637500000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714b81a60ef7174fcff4adaa68a6139ecce46e6f5fa0608f3c60d34787bd25d7a57f1a49e42c935c315": "0x080000000002040000000100902f50090000000000000000000000000000000000000000000000000000000c416c65785f4d6178616f6e000016407361736861313938333a6d61747269782e6f72671f616c6578616e6465722e61726b6869706f76383340676d61696c2e636f6d00000d405361736861313830383833000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714b81b10d0eaa7b26976729e17ad31469debcb60f3ce3622f79143e442e77b58d6e2195d9ea998680d": "0x040200000002000000000000000000000000000000000b4d61746857616c6c65740b4d61746857616c6c65741b68747470733a2f2f7777772e6d61746877616c6c65742e6f7267001568656c6c6f406d61746877616c6c65742e6f726700000c404d61746857616c6c6574000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714b825d933ae3512dfb6dd45ba18e564b4aa812a9974ce45e71d51355d2d93335d22f6804d782cf43b": "0x00000000000000000000000000000000001d597572694e6f6e6475616c207c20524d524b20636f6c6c6563746f720009726d726b2e61707000167975726970657475736b6f40676d61696c2e636f6d00000d405975726970657475736b6f000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714b82ca38b993a4d8b5a7aaed28c23b0b10d2fc6a0a914c93ce965749d67d7f657facb010255e4852e": "0x040000000002000000000000000000000000000000000a5374617475746f7279000000196d697368616b656c6d616e37373740676d61696c2e636f6d000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714b8a088107fc00e82440ca03d91b4a7a9ac7f74d416e1ed29899ae32c2ac81fd5380f8a07e3713812": "0x0000000000000000000000000000000000084e6168204e6168000000116e61686e616840676d61696c2e636f6d000008404e61684e6168000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714b8a497e0503c1d16bc063e9ffcd1f15193240f7ce33e9ae2faf17345ea06cc4781208e4a4585cd46": "0x00000000000000000000000000000000000e756e636c6520676f72696c6c6105616c657800000000000a4070616f6b34616c6c000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714b8b5006d5797640e6e753aa0bf6a3699bf1820cd8cb87cd1fd7c88d0c3e9c194a5055bbf6d338047": "0x00000000000000000000000000000000000d53656372657420416c69656e0000001473637274616c69656e40676d61696c2e636f6d00000b4073637274616c69656e000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714b8dd952c3de3ccebca83919d5d59734897305b32ff1eeb190fa168b7a8f10d613a5fa9067c708f7f": "0x00000000000000000000000000000000000744616d69656e00000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714b8dec3cd52567f7d50deac6bb330e0370fb0f6e25693717ed7c05ae1d43c22b93e9ec5814e318d25": "0x00000000000000000000000000000000000564616e6b00000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714b8e12a80176f0c830aff6865635ae11013a83835c019d44ec3f865145943f487ae82a8e7bed3a66b": "0x04020000000200000000000000000000000000000000114272756e6f207c20524d524b2e6170700e4272756e6f20c5a06b766f72631d6170702e737562736f6369616c2e6e6574776f726b2f406272756e6f154062697466616c6c733a6d61747269782e6f7267136272756e6f4062697466616c6c732e636f6d00000a4062697466616c6c73000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714b8ed6b693822d4a77825b33ec8baf2d437c19856a6ce74f09bbf49c284602a18ecc0683874dd596e": "0x0400000000020000000000000000000000000000000012736e66206b736d2076616c696461746f7210496e666f73656320436f6e73756c741c68747470733a2f2f696e666f7365632d636f6e73756c742e636f6d001d69687562616e6f7640696e666f7365632d636f6e73756c742e636f6d00000a40736e696666736b69000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714b902e56a5ec842fbc8018be75da4c5757d622874c1dd478950b27baff9b50ca4c0e7670c237f626d": "0x040500000002000000000000000000000000000000000a77336e3a657269636b0c457269636b2052616d6f7300001577336e657269636b40686f746d61696c2e636f6d00000a4077336e657269636b000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714b9206afde78e38223a154cb2e55ed80b9b671b240ccf20a8e2a47a7097a61f156eaebdc98fe4780a": "0x040000000002000000000000000000000000000000000a4d616964616e5f5541000016406d616964616e2e65763a6d61747269782e6f7267176d616964616e2e657668656e40676d61696c2e636f6d00000c4059657668656e69694d31000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714b9467b909c56e93efc49c631023463a74ee7b3a3294cfc62479ed9879d7b96cbac4b31cc480bfd68": "0x0400000000020000000000000000000000000000000008494e5349474854000016407368696e79666f696c3a6d61747269782e6f726700000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714b9541ad999d600439c2010321b6f64024b485ffcb9c2c6218bc6baae3b30ee2edce121033c4e443a": "0x0000000000000000000000000000000000074a617a7a75730d416e6472c3a920446962c3a9127777772e6b616d65616c6162732e636f6d0014616e647265406b616d65616c6162732e636f6d00000c40616e6472655f64696265000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714b96d7c19d50508c4cea875e1a4dc1d17e8f7a389467ce388a27f4e6bf47d48bee57490922ea64764": "0x00000000000000000000000000000000000e5361736169204b756461736169000000000000114053617361695f5f5f4b756461736169000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714b96fec1148c50fd53277094fa10fb120ac35dc09a0b57ad3509699366dd95c36c79390832dd1d978": "0x0000000000000000000000000000000000094e61726973657469000000196368616e752e6e6172697365746940676d61696c2e636f6d00000f404368616e753436313836313331000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714b9792ddb83a0fbf980a42994e6266629750cb091d1cd6abd99b9f8371d7ac1c9572fbff31a9fd108": "0x00000000000000000000000000000000000866756e6779737300167777772e6c696e6b74722e65652f66756e6779737300000000094066756e67797373000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714b982d49de1e3d631c6423f3a139fc55c4cea94f27c7472a1ff86c9d7a160b750425d1182bfd83858": "0x00000000000000000000000000000000000c546f6e694d6f6e74616e6f00000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714b982dbb2e3c6ee865ac0bc1423595a61eac2804e8007dd17c6106c9f3153210ea9a7646d486da513": "0x00000000000000000000000000000000000b43727970746f476f6c6600000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714b9840b5e244be97a3c2ebd0507647e389d89069d87d98594c0390f15b774ad70d69a506cc0721262": "0x00000000000000000000000000000000000b43727970746f2e4c69750ae58898e4b89ce6988a1a68747470733a2f2f7777772e696d616e676f646f632e636f6d011364686c69752e616940676d61696c2e636f6d000001000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714b989abb8037b868632cd5ca83f4f70c0570b608c91253f4ec8bb7aef34d6ea23813268a08be1f50b": "0x00000000000000000000000000000000000544415a5a00000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714b9ba5adedd76a0a63443089409ef5b3fe6fe1e79bca1ed3f035b35af2353cf6f9036b598c852cd74": "0x00000000000000000000000000000000000f706f6c6b61206d6574616d61736b0000001161656b6d656e40676d61696c2e636f6d000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714b9be7b84d6056f5f427dbf56380f49793c83aa5a8e7a4f577be76293593a99b3b3c21e47d3821e36": "0x00000000000000000000000000000000000000000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714b9d502fce7c93459067e77e8ffec0eb4beddd71651aae4ca9f05dfe519e5a83745103c15abe7556c": "0x0000000000000000000000000000000000076b656e6c73740000001531336b656e7473756e6740676d61696c2e636f6d00000b4030785f6b656e6c7374000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714b9ef95a6cf7ae500d20b07471e8891d2417c00839dab57c278bd59e855b8c0ce5e7d75bd48dcb303": "0x04000000000100902f500900000000000000000000000000000000000000000000000000000006786e30306200001a40683474743072692d68347878303a6d61747269782e6f72670d6b7535346d3440706d2e6d65000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714b9f6138c9463794508379206f81bebd18953ff826599e0b8c0bceedfc72a996c52e343647f0d625a": "0x040200000002000000000000000000000000000000000d47656e657369732d4e6f64650000134076306964756d3a6d61747269782e6f72671e6b7573616d612e67656e657369732e6e6f646540676d61696c2e636f6d000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714b9f65131235fe195ce5c65fecd7bb733ee636a381fa9dd916f8cca91e2e403c8aea2f7ed32b31d68": "0x00000000000000000000000000000000000c424c41434b4d4952524f5200000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714b9fa90bddc30fe5cbe29ae471fd4b81a6efb3dc6bc7fe4b65b52d646e24373b4237613322099e63e": "0x0000000000000000000000000000000000065374616e6f00000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714ba17b7a7c96751bad490a44a398ef9ddb3d9fc9159ee9211cad8b42ed24378fc8ec6a2051559ba4d": "0x0000000000000000000000000000000000096e616d656c65737300000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714ba2e001c3fdf3cc590980036ef824bdf5e58efd3a0bcfd3b9ce9a6d08584a5aa4631f0fecdec287e": "0x00000000000000000000000000000000000c466f726573742047756d7000000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714ba3272263a601b26705bed5a79303588fb60600fff425e0d0c1129332c341a9f28af16f70a0d0072": "0x00000000000000000000000000000000000c43657361722059616775650c43657361722059616775651668747470733a2f2f636573617279616775652e65730016656c667265736f6e65726f40676d61696c2e636f6d00000f4063657361727961677565617274000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714ba34277ae1163be29c81bfa3aff6c4db81aa876fd24384ff7147fe58fdecae448ac4c2591235042c": "0x00000000000000000000000000000000000c494e54454752414c5f31380f494c5941204b555a4e4554534f561e7777772e696e7374616772616d2e636f6d2f696e74656772616c5f31380012646a6e6176767940676d61696c2e636f6d00001040496e74656772616c50737963686f000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714ba39954813b8c8e0c835ecd271a6b07d93931cdc3ed8f1501cb15130db011c1e1e19bd229bd0827d": "0x04000000000200000000000000000000000000000000136c616e6465726f73207c205374616b655570001668747470733a2f2f7374616b6575702e746563682f15406c616e6465726f733a6d61747269782e6f7267156c616e6465726f73756140676d61696c2e636f6d00000d406c616e6465726f7375615f000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714ba4212be20da972e4601d5e1601ee14b4ab46a8db6841f6165e7af0a05f91dcf5625c56b88294e51": "0x00000000000000000000000000000000000753617676615412536176766174697920496c79756b68696e0000187a656c6761646973657865313340676d61696c2e636f6d00000a40695f536176766154000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714ba4a9572710e11eae4b3182c87d1d282b76398757c96af32377066b3941fa21a038885dbffeb027e": "0x000000000000000000000000000000000013524d524b2050756e6b732053657276696365001768747470733a2f2f63616e6172796e6573742e696f2f001652656d61726b50756e6b7340676d61696c2e636f6d00000d4052656d61726b50756e6b73000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714ba57612f37ff87d8c0f6272125c7aa7259ab82cafc9e7f170102cc50818299a90a5807debfdb0957": "0x0400000000020000000000000000000000000000000009676c6562616e797900001840676c6562616e79797979793a6d61747269782e6f726716676c656270656e6b696e3840676d61696c2e636f6d000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714ba594f7276ff200c4e531ab22f712634089201978511b49aa987322314dcd8f16fa241f0055e3737": "0x04000000000200000000000000000000000000000000094172696e676f74790000001674307468656d6f306f6e6e40676d61696c2e636f6d000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714ba5e9cf778fa9a309ee26710c447115a1467aa6cddcb5b11a450522fe50f8c328ad7018ca3ca5109": "0x040000000002000000000000000000000000000000000a57494e2d5354414b450000001677696e3737377374616b6540676d61696c2e636f6d000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714ba67fb7fc8a0aa49a6915d6fb30cd30367f23194c68842a6018f565c773ea0c544eb2a62597b1b34": "0x040300000002000000000000000000000000000000000b4c696562692054656368184c6965626920546563686e6f6c6f67696573204c74642e1268747470733a2f2f6c696562692e636f6d001068656c6c6f406c696562692e636f6d000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714ba6839973e6e9ad1e2a0a933d2b1e2dfd0c06baf42557bf4aa2ad84866859e6c869733d6baadf152": "0x040400000002000000000000000000000000000000000c637279707445676f642d31000000147761796e6f3733333740676d61696c2e636f6d000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714ba91bba06b9f9bc520214ae0372ce9446bff0c4b6c1d56b8d5f8bedd43e563d12dd888e910a67069": "0x000000000000000000000000000000000011f09d9488f09d94a9f09d94a6f09d94a405456c696110656c69612d6f7273696e692e636f6d0018656c69612e6f7273696e6940686f746d61696c2e636f6d00000a40656c69675f5f5f5f000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714ba9c47cbe1e3127fc6f159cc01916d03e79dd23ddb4f32bc3505f47f99548b36c8dd85cb3d703f17": "0x00000000000000000000000000000000000773686f6e79611253686f687261742042616773686979657600001673686f6e79616d63636f7940676d61696c2e636f6d0000104073686f6e79613036343734373836000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714baa78287fb8b42a5f89cdade39dc2b7f42cd668be4a3aabfa432524f9732ec2b38362ad8b6b6d17e": "0x00000000000000000000000000000000000f5468655265616c4973696c64757200000000000010405468655265616c4973696c647572000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714bacc123aba961dfdac7c228c0c2f9f8bd69a79694a21c0aaa11fa0bdffb8a24f8a2b2c7c71dd4464": "0x000000000000000000000000000000000008616c657867676800000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714bad35515a8d5aa0ce26cc8ecc7230bf0579be3d530cfcd6cfe8e18f560a20bb651dcd4bc5877c442": "0x00000000000000000000000000000000000f42494e414e43455f4b534d5f353100000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714bad85d54508d6840b433c85404bf9625fccfe9f33ea14dc941c5f2d33a2ee131b462526ed834365a": "0x00000000000000000000000000000000000c546174617461205465616d0c546174617461205465616d000013736179656e34696b40676d61696c2e636f6d000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714badc22310930427ba763de880dfe6c4bbdad18fab60e27002f648c221df5248b7d44a575b4bc7342": "0x04000000000200000000000000000000000000000000054d6f626200001240316d6f62623a6d61747269782e6f726700000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714badd0717f1d37bea9a351f499b0c0ad66910f50ad9b28097a671da936b170ac23440194c803b8c2f": "0x0000000000000000000000000000000000000000000000000d40766974796163727970746f000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714baf2344ffd48e8ba62b57bdeb1e972c6f82ddeac93c75c9068b57649792c34110443f6a5cab2757b": "0x000000000000000000000000000000000006646c73393306446f742d58000016646c7340646973706f7274656c65636f6d2e6e657400000840646c736d7173000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714baf41e8958962423603c30a2fec5564ad9ab97b2545ea990e3c1e6ad80537b9f49ee5ea077c37a29": "0x00000000000000000000000000000000000f63616c69636f666c616d696e676f00000000000011406d65746170686f7269636472796674000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714bb0178d1513af2c9c8aa860ecfe404cee1ae6ae1e175966ffc5d0ed9518febe66c949472d9ccea52": "0x00000000000000000000000000000000000954616c69736d616e0954616c69736d616e000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714bb146d7c8d93ce7a7874637d61f8a35d5cc1f042c93a1eac375025b66d469df55822b40d374a146e": "0x00000000000000000000000000000000000f4c697a692050616c6b696e697a6900000000000010406c697a695f70616c6b696e697a69000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714bb1a60ea00d6b485d26dde9e6d3cce0d69ae970d6d9ea7c3a5e39c197fc4360a063f68da22df3c30": "0x000000000000000000000000000000000008566f6c6174696c054e69636f000015766f6c6174696c64756240676d61696c2e636f6d00000d40766f6c6174696c64756273000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714bb23b116b16ec5027ef5168fd3e20f6dd7063f3d7654fa986e326da23f6132acadddcd47c2fb7634": "0x00000000000000000000000000000000000b617065586368696d707a001c68747470733a2f2f7777772e617065786368696d707a2e636f6d2f0015746f75636840617065786368696d707a2e636f6d00000c40617065586368696d707a000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714bb316e0c469f968b5064b971aae8c27d90e75935176851e03c3b30d7737a81b4ebaafae61e86e008": "0x0000000000000000000000000000000000064a756c69650d4a756c6965616e6e65204e672168747470733a2f2f696e73746167722e616d2f6a756c6965616e6e653139393400186a756c6965616e6e653032323040676d61696c2e636f6d00000d404e674a756c6965616e6e65000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714bb3c046d0a6fb474e0084f5bd539e9f109706deacc25d346a52b1c61870f5f47d80b65defb7c9174": "0x00000000000000000000000000000000000f62696e616e63655f6b736d5f33370f62696e616e63655f6b736d5f3337000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714bb439f2ecc149015560189524f9e8a5a319945ba02d9696b8e17068709af4f3a3b37961b21b73a25": "0x00000000000000000000000000000000000f4c7575752040204576726c6f6f74064c75636173107777772e6576726c6f6f742e636f6d00116c757575406576726c6f6f742e636f6d000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714bb5235e6238a13f3f496e79339df9183c3498406c6a885d6b381e33eeca4fb217751cf02fcfe1d72": "0x00000000000000000000000000000000000f4a5755204368616f7320323032310a4a757374696e20577513687474703a2f2f4368616f73436f6e2e696f00166a757374696e406465666973756d6d69742e636f6d00000b406368616f735f636f6e000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714bb5ac47891b1706c02182bd1df5c617cd764a92111372e138c8f2de893e2870e1ba6798b69629e65": "0x00000000000000000000000000000000000654616e6b610f54657469616e61204b6c796d616e00001874657469616e616b6c796d616e40676d61696c2e636f6d00000b407468655f74616e6b61000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714bb6fb2c1a1cf337b7ed3dd1132e1f216cb30c2440b46423faf32c6effd0a2d9a9f24e52f57af6677": "0x040000000002000000000000000000000000000000000b4c415552454e5454524b000000186c617572656e742e747572656b40676d61696c2e636f6d00000c406c617572656e7474726b000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714bb90b6ee5cde60ba10a769ca3066979c556735c449cffae412f7ba4bb7f8eb1377e0b3f11a8f144b": "0x000000000000000000000000000000000004416c7400000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714bb98a2562e4cc62d54c768b91070d322e396886d9ba5fbb6d75ba6d04b244ba8efc1c318b3591b52": "0x00000000000000000000000000000000000e62616e6461692d7061796f757400000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714bbb543598a54ca6b9c974e668dd5d28bd12df4e36aabde599fa1623ee8b97811dbfde761fe762857": "0x0000000000000000000000000000000000085361757261626800000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714bbc7bd73b2748c6f96672955216c27e79001bf18f21b977f2765ef1d0f2aa2f037725ba051311537": "0x00000000000000000000000000000000000d535550455220504958454c530000000000000e405355504552504958454c5378000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714bbcb83d90d25faefbadef2fe7ed3061a98b743c923501b7e196735e1a8bd1f066b1c3c960511445a": "0x000000000000000000000000000000000016f09fa4b5f09f8fbbe2808de29982efb88ff09f90900000000000000d406d725f5f77686f676f6174000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714bbd9f3a4a489a29e46b99e4f0ae2bfa4a719980c7833c4fc1a6f78fd8b4ea4aef68a036e6ba4b845": "0x000000000000000000000000000000000007656d65656e610000000000000940656d65656e6134000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714bbdd44aa00ffeb9790174218ad9d5531fc97c3b347e073d347d157cc40a470ad89b75604b0d9dc33": "0x0401000000020000000000000000000000000000000012546f6d61737a2050616e7461205268656910546f6d61737a205761737a637a796b1568747470733a2f2f7761737a637a796b2e636f6d1b40746f6d61737a7761737a637a796b3a6d61747269782e6f726714746f6d61737a407761737a637a796b2e636f6d00001040746f6d61737a7761737a637a796b000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714bbe6cdadc6b5f81166abfdc8c3f01b4913bb09c1690b3ad15179ad20fb3e1f46d90e0104ea90951b": "0x040100000002000000000000000000000000000000000b4e69636b20536d6974680f4e6963686f6c617320536d6974681768747470733a2f2f6e69636b736d6974682e78797a2f00196e69636b2e63616d2e736d69746840676d61696c2e636f6d00000e406e69636b63616d736d697468000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714bbf2c08ccad2373618270c23416bc290f3e029234130076858ec2b13753249521efc90f74ae62656": "0x040100000002000000000000000000000000000000000a53696c7665726561751053796c7661696e20436f726d69657200164073696c7665726561753a6d61747269782e6f72671c73796c7661696e636f726d6965724063726970746578742e636f6d00000b4073696c766572656175000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714bbfce08e9e5bda94e2cd3cc85125534b5ea71b50545fea6da949704fc53b8ad0fa6a6e53c1e8b60d": "0x000000000000000000000000000000000007544f544f544f000000107a6a6b32343030403136332e636f6d00000c407a686f756a69616b7569000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714bc013d27fd77c44a621062161709870a2adfa220222901a2eacfeecc3a4d57ec0ceb0892770f4d31": "0x040000000002000000000000000000000000000000000a4d6568616e696b6f7200000016706f6d69646f6572696b7440676d61696c2e636f6d000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714bc11b42293c053bb8aaaccc15d1e83263b6f51805be7a175838e9039d93a4c510954d03b8928fc51": "0x000000000000000000000000000000000004616e740847756f204b616900000e6875616e666f4071712e636f6d000008406875616e666f000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714bc2d8754336d8fa7da2b89ee8960496527b6374ec753a1f5fda3e39e9e9b03d9badfb4bccf6e8f56": "0x00000000000000000000000000000000000742696f4172740101011362696f617274383940676d61696c2e636f6d00000e4042696f4172744c6561677565000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714bc39f04eeba5e074def7e734f3e6f486dab2052f0ec6f574424cfbabc1d9f8c707c831398bad520a": "0x000000000000000000000000000000000008416e74616c657300000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714bc547c1424fb130ccc26f3f343300ea20b4ce386372382e3d33e9ece9a27e0a01fa995338c0f651d": "0x0000000000000000000000000000000000055155455300000000000011406369676172696c6c6f6f7074696d6f000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714bc668f7dfbaa59cb02d7a8a8876312537dcdef0ccc8d7aa11011b1e95d82e0d4be84f40b5e97537b": "0x00000000000000000000000000000000000864796e616d694b0101010100000c4064796e616d696b756e6f000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714bc6b5bdca0cef0328e80f01c037bbec2db122fbd54406add4e7876dad507df9686a4602bf41cf664": "0x040000000002000000000000000000000000000000000c59657668656e5f56616c3200001a4079657668656e626173617261623a6d61747269782e6f72671a657667656e69792e6261736172616240676d61696c2e636f6d000011406768366d786a78384f437754776373000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714bc737a0b2b1b692a444c69e29645f58dc986ea6c666c7d6fa7183d0e517d9bf72bdc4f642d38c163": "0x00000000000000000000000000000000000d426561726f667468656e657400000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714bc7dd41f6fa996306a36dac17180d46bcf920c75b4e77f8000639ff41f6e55f2232a7650002c2934": "0x00000000000000000000000000000000000d576f6e6465722057696c647300187777772e6a6572656d7962616b6572617274732e636f6d0020776f6e64657277696c6473406a6572656d7962616b6572617274732e636f6d00000a404a6572627a576565000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714bc95df3416acfce29ec982d60f3779d8f0043933ee6d1b2a4346df17d07e44a22a2cd91a31076352": "0x04000000000200000000000000000000000000000000076f726469616e001a68747470733a2f2f6769746875622e636f6d2f6f726469616e0000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714bc9c5c7658dc2a36b45071647184e1df1afe1d9165a5762fb9b986c4041f744c95c15fbd55359951": "0x0000000000000000000000000000000000104d72204b7573616d612f5041424c4f0e537562737472616e617574732011737562737472616e617574732e636f6d00146a756e65736e74776b40676d61696c2e636f6d00000a406d726b7573616d61000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714bc9fa9104384658136e4b176f4f8c8e93d1f038c4ad53d6ce6308764888af81d0b2acc9903f59a3d": "0x000000000000000000000000000000000010756e6a6f626265645f63616e61727901010101000001000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714bca25b49658f3abbc422e2ea493a1dcbb08fe47a38b7a06ff11372588ff78f041e2dec92932a274e": "0x00000000000000000000000000000000000a4a6f73616e6b4e4654001e68747470733a2f2f747769747465722e636f6d2f5468654a6f73616e6b00196a6f73616e6b4e46544070726f746f6e6d61696c2e636f6d00000b405468654a6f73616e6b000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714bca4e93e46a1ee7a83c75b56557a84fe8261cadc0c308577b0709cdc54311afc5ec8d348b939f589": "0x000000000000000000000000000000000010416c69616e7a612048697370616e6100000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714bcc32e782ecc9fabd8cd80b17fc41772945cde33054bcf50ba34a036208b9799414c92a187742226": "0x00000000000000000000000000000000000e436f736d6963204a65737465720e54696d20566572686f6576656e177777772e636f736d69636a657374657233332e636f6d0016696e666f4074696d2d766572686f6576656e2e626500001040636f736d69636a65737465723333000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714bcd1f1445ae81362c8dee77020353131d4765e808b2c6cc7b6210eb6fcd3124ae83425c4fc054b69": "0x0000000000000000000000000000000000074d696368616c00000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714bcde3d13baf8df94629a1162629bfa1c1b9291bdb4cd489a90b996ae15af912e8eaa384967b23668": "0x00000000000000000000000000000000000b446f75626c652044656500000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714bce3132e4ef55facd425daddf60b2545e07c695d32d6bea2b9343f1528052b4edd1a777e93058565": "0x040000000002000000000000000000000000000000000b416c7363616c61626c6500000017616c6973616261626c6572744070726f746f6e2e6d65000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714bceadde40165af33fe5a9cca6c5a8bd14c35c961d2a673268d204c2c36d15ab86335ea7954a8e963": "0x00000000000000000000000000000000000e50756e6b205661756c7420233600000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714bcf5cae0679b87b9aa192026f9edadc2b37b96a189bb52a799bc6b81c38af03294269f4f1f40371a": "0x00000000000000000000000000000000000000000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714bcfdd67ea673f1f2641768da63aab1ad01b2ffed1a44b41c4475f3efdcb74d1e45cf3c490db0c11b": "0x040500000002000000000000000000000000000000000b7863526f6d312e646f74077863526f6d310000167863526f6d314070726f746f6e6d61696c2e636f6d00000a40726f6d315f646f74000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714bd003bec2e6f36549a303844f021a011c22d653fb6259b4b8fab1d68b0c0874b185583da201bdf28": "0x000000000000000000000000000000000008507368656b656b08507368656b656b00000000000940507368656b656b000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714bd07137d6081d8b92430a1698a57e4e339ecb9de55ad5673044714661b246edb2c1ea5a2646d9c73": "0x00000000000000000000000000000000000a4d61696b306c5f303000000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714bd136d88ba01ae124af9159027de5ea1662da355ea7cbe3fe413d6531e07aa239d1ba6d9a1c09b12": "0x000000000000000000000000000000000008526f62737465720000000000000a403030375f526f626a000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714bd1575bcc84ab1311010f8f677bbac23220af0b0ac65736ebc00b02e974963a5d006d266bdaf955e": "0x0000000000000000000000000000000000074e756e7a696f00000017616e6e756e7a6961746f636f40676d61696c2e636f6d000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714bd17f907497d7c56a0cb11fa6afcf3be8012015df4a96a7b2020cd7271718a05f8a51027af726971": "0x000000000000000000000000000000000009427275736f66657209427275736f6665721d68747470733a2f2f747769747465722e636f6d2f627275736f66657200216272756e6f736f61726573666572726569726139323940676d61696c2e636f6d00000a40627275736f666572000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714bd2ecf6ad5d9dd9aee019d37459e8eed15e0f5009e508c41af67a4e7be45b790cd9e62d9033dfd5c": "0x00000000000000000000000000000000000000000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714bd3136476e89f2d1688a4b3d49b7fa3e1587f8a8e3b445c7c3e830d524a6dc0bfd89a0f8627a6f08": "0x00000000000000000000000000000000000b616e746f6e6169796c790101010100000c40616e746f6e6961796c79000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714bd39bcb26e4bbeaf9e5d65b57e68b695519207678cf4e14f3311e3b37918551b2859fa20acf5d538": "0x00000000000000000000000000000000000f4a6173654d61746963546f73686900000000000010406175737369657061727479626f79000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714bd3a85fb653543aea882853228a1b570c5461bca6cd0457e2c8fa58c6aa52aa78f29bd5ecaf3513c": "0x000000000000000000000000000000000004544a420654796c65720101166a62743432324070726f746f6e6d61696c2e636f6d00000b40746a616d6573313435000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714bd3e1f96cf2e126e7054e5eabbdb6217217110e775a6f6f0b90c7ae2ca9effeaa9364eebd4eb206e": "0x040000000002000000000000000000000000000000000b48657865722d6e6f6465000018407370656c6c6361737465723a6d61747269782e6f72671f7370656c6c6361737465722e6e6f64654070726f746f6e6d61696c2e6368000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714bd728b26f60d3178f0fe1b04915cf406ce80faca3c18fda01d62d2ce52181870c984fb91c3a7df17": "0x040000000002000000000000000000000000000000000b5361746f79616d612031001b68747470733a2f2f7777772e7361746f79616d612e746563682f00197361746f79616d612e7374616b6540676d61696c2e636f6d000010407361746f79616d615f7374616b65000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714bd73eac9321df2b4bcb330a49b5766dcd63fff92cf95243ec2a29c4131f19155724095e5cfd5197a": "0x08000000000100902f50090000000000000000000000040000000100902f50090000000000000000000000000000000000000000000000000000000d47726567207c2041737461720f477265676f7279204c756e6561752068747470733a2f2f706f6c6b6176657273652e636f6d2f40677265676f72790013677265674061737461722e6e6574776f726b00000f404c756e656175477265676f7279000a68656c6f233331393400", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714bd7cb7fed15797d09eaf21efa0b5543ff7a8f857e47440732a45b5e8a5089741c02b56df13410944": "0x000000000000000000000000000000000018524d524b20537570706f7274207c2056656c696e6f766101010113636872697374696e6140726d726b2e617070000001000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714bd922ee4590a662b5220aaa3db247e52267f6c127eb427c31e5a6a73cdcfda6b2c716f945527780b": "0x00000000000000000000000000000000002150656e64756c756d204b7573616d6120436f72706f726174652057616c6c65741950656e64756c756d20446576656c6f706d656e74204c74641b68747470733a2f2f70656e64756c756d636861696e2e6f72672f001c636f6d6d756e6974794070656e64756c756d636861696e2e6f72670000104070656e64756c756d5f636861696e000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714bdaa6fd826d3e849dac5c7f54060315d58706b0956b5ba06ee5418f9c6ef558a7d95446c29d0e73c": "0x00000000000000000000000000000000000b617065586368696d707a001d68747470733a2f2f6c696e6b74722e65652f617065586368696d707a0015746f75636840617065786368696d707a2e636f6d00000c40617065586368696d707a000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714bdb707c454d386493ed4491f24c65d4af76d353ac2932457ddaf3d27df87ffa4445ea40f979b9c60": "0x00000000000000000000000000000000000000000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714bdb8c60de2e112d532d982ef0b332719d3a292188fef7138daa785a5c1a3d3d55eff4cdc71eb5069": "0x04000000000200000000000000000000000000000000094c6f6e674e6f64650000001c6c6f6e676e6f646576616c696461746f7240676d61696c2e636f6d00000b406c6f6e675f6e6f6465000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714bdd0aa5b808b0d34b437f703710d52aed228ae7f941f8e08b32edde56e683dcc94664c3dc8622e02": "0x0000000000000000000000000000000000114d65726b6c65426f74204d696e746572124d324d2045636f6e6f6d792c20496e632e1768747470733a2f2f6d65726b6c65626f742e636f6d2f000000000b404d65726b6c65423074000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714bdd53ac7ebda26846230b351838edf68965d65538b501241b45871b5e0c20414e8fbae73dfda2a34": "0x04000000000100902f500900000000000000000000000000000000000000000000000000000009436f696e57696b690000154077696c6c6e6176693a6d61747269782e6f7267113139393230343639324071712e636f6d00000f40636f696e77696b697065646961000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714bded1c61bcf50ff15615825944703a7f9494aa2901e4bad051e2f06763f755a3b010c887be77fd73": "0x00000000000000000000000000000000000b4178616e746173616d6100000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714bdff2bb6b49fe71dc0125eaddaf1645d52cad388414ee3d814aab298a97d670d1d5172d4f5b8db0c": "0x00000000000000000000000000000000000000000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714be092d7e5aeb9a7802948b18cd5001e68a33499343bd8ed974fc8398bbfdc3dfafbc7c478544f67d": "0x0401000000020000000000000000000000000000000006696c67696f001468747470733a2f2f706f6f6c67696f2e636f6d1240696c67696f3a6d61747269782e6f726712696c67696f40706f6f6c67696f2e636f6d000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714be3183951dd1f1d5e626934768e68509f3b657372165e6f98fdefe615cc8e669d5bbe033a6478556": "0x040000000002000000000000000000000000000000000bf09f9491204b65697468000018406b656974683a6d61747269782e7061726974792e696f106b65697468407061726974792e696f000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714be3990dcba28e51a80dea82a6a4704d208bd43d1ea1d5a0bd97a9d20c5237beb348be8c82f37d93c": "0x0000000000000000000000000000000000104d617274696e20f09f8cbbf09f8c9e00000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714be3a70de3dc8981a02098b5f718885f0d6f0f18359a7d16b44c9229857934efe66daf4d9f0eb7a43": "0x04000000000200000000000000000000000000000000084e6f646561737900001540637261626265616e3a6d61747269782e6f72671577656e7a686968616f406269746f7069612e636e000009404e6f6465617379000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714be41c254bc739ae910473e87fb3a40efd144767bd4a2b66c551947290d28eb81798dfcaa2981c134": "0x00000000000000000000000000000000000d4d657461204c696d697465640c4375616e205361757465720000156375616e73617574657240676d61696c2e636f6d000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714be67a4a924a2f024ae7c2e1a07ea367f42d8a50cc1b05e67313b2d0961a176bc914ce5418093a816": "0x00000000000000000000000000000000000000000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714be6eb4fcd98b5e48225f2459239641fc50300041f8980fa044cb07705db61fefb340804172b1c25d": "0x040000000002000000000000000000000000000000000f43726f75746f6e4469676974616c00001540746f7861333333333a6d61747269782e6f72671763726f75746f6e6469676974616c40616f6c2e636f6d000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714be87f9c4b210b250122ff96f07bd9c9b3961c4387d71362315d05addda58f1dcce642888a643f930": "0x00000000000000000000000000000000000853435954414c4500000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714be986efd0a14e39c8ecdc51d7c98b64a51f2c4c19e2be313af46a41bbb620432be7f2f78a27f7c1a": "0x00000000000000000000000000000000000a4f6d6567614d696b650a4d69636861656c20420000196f6d6567616d696b6540747269736b656c696f6e2e6f6e6500000d406f6d6567616d696b653834000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714bea99ac32a4539bc724d262fd25c8cc975189c3ae4f0dee1ba2e17080cda69183412d0928b49db0f": "0x040100000002000000000000000000000000000000000b7375626c61622e6465760b7375626c61622e6465761368747470733a2f2f7375626c61622e64657600126f616b6c6579407375626c61622e64657600000b407375626c6162646576000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714beb64061aa9b85f752cf40bb293c3639c52e8d1102816a0eeb15adbdcb34985f4f555d83d6fd9f35": "0x00000000000000000000000000000000001f53414d4241207c20526f79616c20536f6369657479206f66204368616f730d576f6c6667616e672053616d147777772e776f6c6667616e6773616d2e636f6d00146e667440776f6c6667616e6773616d2e636f6d00000f40776f6c6667616e675f5f73616d000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714bee578c453b0ec8a10dcba5c743f0ac5f458c84cae222de427205dbdb1ea5c38070be7a728d44109": "0x00000000000000000000000000000000000c5468652043757261746f7201010101000001000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714bef054a6e8d99eba983c5a0d1f1e697c1a0f9798bc25543603751b41102d41c3b0e23cbc6e3fdc0b": "0x0401000000020000000000000000000000000000000008566978656c6c6f0c566978656c6c6f204c4c431468747470733a2f2f766978656c6c6f2e636f6d1440766978656c6c6f3a6d61747269782e6f72671268656c6c6f40766978656c6c6f2e636f6d00000b403078566978656c6c6f000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714bef3200eba174d218000262b138778788d2c01044e23dbb7b4159a60cc72b36455320866545ea72d": "0x00000000000000000000000000000000000d44616e656c694172746973741044616e616520476f6e7ac3a16c657a00001664616e65676f6e7a612e6340676d61696c2e636f6d00000e4044616e656c69417274697374000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714befec0bbe28bc4156cf103d56cc23ec72abe93fa1bb8b2ce999da4c64cf87a6382fc6f743a176d71": "0x04000000000200000000000000000000000000000000055a756b61000015407a756b615f3131363a6d61747269782e6f7267127377343832363440676d61696c2e636f6d000007406f6b37693300097a756b615f31313600", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714bf0b85bf56b1122f2644199cf370ae595ee0fcfe125cf1f57ccad32c435b62ba43ea09b7652aaa78": "0x00000000000000000000000000000000000f4b7573616d61204b696e67646f6d001f68747470733a2f2f7777772e6b7573616d616b696e67646f6d2e636f6d2f000000000d404b7573616d616b696e6773000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714bf13eac6858519dcdccfd108cf2a01b8e6cf878849eabe75728f267ea10fd8f18b6fe92220c8991d": "0x00000000000000000000000000000000000e4c696c6c7920506f727363686500000000000011404c696c6c79506f7273636865417274000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714bf17a0437a59fce41c45953edf44501060286e3eb61e389d86d13e7c2a6e4acd6bd1df389d34f358": "0x00000000000000000000000000000000000000000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714bf2341873b4d4cf676587217399584996f3d1f2135f8c76cd128e795fc5e04018e3f15be7aded120": "0x00000000000000000000000000000000000000000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714bf284bae8cc1a1845687439c0a1ffe34131bc8f47408fd64663de30e4eb54aa128e578db2745c749": "0x00000000000000000000000000000000000962656e6c75656c6f0a42656e204c75656c6f000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714bf4f9995d06677041cf0dca0b7aa11a240e5706fcb3475f60a375814d69755c9362f65caeb55a867": "0x00000000000000000000000000000000000277000000000000034077000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714bf5e40a7dfc4431c8a99501bbf355e2b2f19a22c79915c2deefe1a3e19c957a9db910b7d3f6ff24e": "0x000000000000000000000000000000000008456c65786965720000000000000940656c6578696572000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714bf6bd75b748928f06effd095a398639dc8af6f449a6362b40ee962e69700369eb9e530629bfa386a": "0x00000000000000000000000000000000000f4b7573616d61205a6f6d62696573000000186b7573616d617a6f6d6269657340676d61696c2e636f6d00000f404b7573616d615a6f6d62696573000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714bf74188b125a3306308b59a947eeb792acf6de27fa47a92ad37d53a15a7b97cd25f11c25455ba253": "0x00000000000000000000000000000000000e4c6f63616c436f696e53776170001a68747470733a2f2f6c6f63616c636f696e737761702e636f6d00177465616d406c6f63616c636f696e737761702e636f6d000010404c6f63616c436f696e537761705f000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714bf85c9682d95267f0459226895922ebcf36a4fd2441690ddeca7404cd4ee5403ebea4c9ef367fe4b": "0x0400000000020000000000000000000000000000000008437269735061700000000000000b40437269735f50617038000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714bf8e0379b44b6804dcf2917d37c64e3d60416e47b5185b4d6c3965ca531ecbe29e1d2cf759f5f871": "0x040000000002000000000000000000000000000000000f554e4956455253414c444f5430300000001d696e666f40756e6976657273616c646f742e666f756e646174696f6e000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714bf9ec12dc8498206bc43e27bc2e8f85dd0bd886f3512866f82132844654c78465fd3b23dc7988e0d": "0x04000000000200000000000000000000000000000000074b7269737479000000156d6172786f786f6c327540676d61696c2e636f6d000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714bfa9ffb31899babc08fabdcfdd509f6f46ae0d3d94774a5555f448378075d9d6e2818dabcfcfce4a": "0x00000000000000000000000000000000000744726f6f736b00000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714bfaa3c41adc4090b76b408e1da2f3e3aa9933dfc856970e1910172ca002f7c692aef2cd814a4d16b": "0x00000000000000000000000000000000000e49736874617220537072696e670000000000000e40497368746172537072696e67000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714bfae967d3e6d06430263fbfa5728d893da31a94b7b23aea0fc23e87b2e24e12e08e372bfde42fb2a": "0x000000000000000000000000000000000007426c61696e6500000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714bfb6186ececfda792ef97696585f2074e73c1a7e50fd86be024eba3cf4472ab02e9e5e60658a9f0f": "0x0000000000000000000000000000000000096c6d61747a38323300000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714bfd1adb8160d3d9cec8c97edfab0a07c37625d53be2075b8ea64a00ca71d80cffe94edb44d215e00": "0x040000000002000000000000000000000000000000000c6e6f6b6f67697269737276000018406e6f6b6f676972697372763a6d61747269782e6f7267176e6f6b6f676972692e73727640676d61696c2e636f6d00000d406e6f6b6f67697269737276000c6e6f6b6f6769726973727600", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714bfd37fecc62ed30d50d3a21916778f488ad7fc8be11e29ced183651fa35e9a5a4148077e3dffb146": "0x0401000000020000000000000000000000000000000004535044001b68747470733a2f2f726f626f6e6f6d6963732e6e6574776f726b15407370645f616972613a6d61747269782e6f72671773706440726f626f6e6f6d6963732e6e6574776f726b00000d407370643537303638333935000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714bfd63dc631849c7f40a40af94843458d2a32dffda8c113143c4c263b689fb22feb2817d44b557447": "0x00000000000000000000000000000000000c476176696e20426972636800001340676176696e6e3a6d61747269782e6f72670000000d4045746865725f476176696e000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714bfe419a5c9e5d3ad6c4e8b48b79ec203ce159cd966e441d6e96f1250639d1ce8e2cca50574a1cf20": "0x040000000002000000000000000000000000000000000b4a756d696e73746f636b000000156a756d696e73746f636b40676d61696c2e636f6d000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714bff2bb4618f007527cee2043a1c5ab3ca7b376a1038e0200b82436d83c6f12cee8a2838f3374511a": "0x00000000000000000000000000000000000d616e64726573616e656d69630e416e6472c3a973205065c3b161117777772e32316d62756c6c732e636f6d0017612e6c656f6e6172646f706d40676d61696c2e636f6d00000e40616e64726573616e656d6963000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714bffb48c65264e596623a83df18a4035e3f753cf28bd99cfee9d86937a0249e64c0edfaaf774aad70": "0x00000000000000000000000000000000000a30784b727970746f6f00000000000011404b727970746f4d616e69614b343030000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714c0076111676aa5c932585bcfe3a06cc536501471159584b934d07923e03f69ec4e7101f6d21b9a42": "0x0000000000000000000000000000000000084b7573616d626100000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714c017c9db88e20ba7d6ea290b1d0c9db6b60e1ccf45cd46ccdfca05d0eefb211f8737138d5f23e81a": "0x00000000000000000000000000000000000000000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714c01ea55f307c73957ef55983821ee123bb7141da96e85024e537b7c3d4dabee51f6bcc458f2ce77f": "0x000000000000000000000000000000000003474d06502e204d2e000018616d706d5f43727970746f734069636c6f75642e636f6d00000e40616d706d5f43727970746f73000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714c04a9c7d0caebe131693a51ef6a5e8d8d7f8254be6e1da86af31c6fadc8cb63c489d3676012a6d46": "0x000000000000000000000000000000000006445245414d0e447261676f6e20456d7069726500000000001040447265616d447261676f6e456d70000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714c04ca87c3c9a9c0e54f7907932d3b6acc91644057bf2732683d772a7b69f8df49f91cadf50e0ca41": "0x00000000000000000000000000000000000e506f6c6b61646f7420426f73730000000000000e40506f6c6b61646f74426f7373000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714c07690bc374b92f796acfe70c04eae75f56d603fa55ea58adc1a5be6f7780f6bb8b55ca788ad670f": "0x00000000000000000000000000000000000c5375706572636f6c6f6e790c5375706572636f6c6f6e791868747470733a2f2f7375706572636f6c6f6e792e6e65740000000011407375706572636f6c6f6e795f6e6574000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714c07b13ed9c7bd5784a9bcc5ed3d67b713c73686690eeaa8d56d0e933b1767d04e6a78c5bcfb0b953": "0x00000000000000000000000000000000000656616c6c791256616c7961204e617274736973736f76611d68747470733a2f2f6c696e6b74722e65652f56616c79614e61727473001556616c796131353331324079616e6465782e727500000c4056616c79614e61727473000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714c0a3a98b551ee046f623943323c10fca98730a4dcae0b6f710f51a9b574a415f4c84617389345024": "0x00000000000000000000000000000000000a5768697465776f6c660e4a6f686e2042616c6c6d656e7400001b7768697465776f6c6637354070726f746f6e6d61696c2e636f6d00000d407768697465776f6c663735000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714c0b698fe85dc7f07f46a2cda2040566d6299f92cdb1132a231dc2632ff84b711e3db8634c344f93e": "0x040000000002000000000000000000000000000000000d47696f726765416264616c610000001767696f726765616264616c6140676d61696c2e636f6d00000e40416264616c6147696f726765000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714c0c86ee622ccbd7b50cf2ac5c2184c5b56bcc4020ff5858a46411c63eafde5c0073033aa9183b008": "0x0000000000000000000000000000000000094d6172666f72696f000000136d6172666f72696f4070726f746f6e2e6d6500000c4030784d6172666f72696f000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714c0c97d65a24f61b1143b4dafb938b67c2305804cedd61580d28079cc89366c4d02754275188e8207": "0x000000000000000000000000000000000013506f6c6b61646f7420636f6d6d756e74697901010101000001000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714c0dd630e2b48c6f1883235753d2d2fbdcde84d5bedf9d4e3049d3aa38eae44b6baf7f90dfbc27c77": "0x00000000000000000000000000000000000d616c656b736969627261766f001d7777772e696e7374616772616d2e636f6d2f627261766f2e70786c730014627261766f70786c7340676d61696c2e636f6d00000e40616c656b736969627261766f000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714c0e60e80c24de0077c140ace22ed9c9542e5bb2a752621225ce07325c26d02a494883e860329921f": "0x000000000000000000000000000000000008446f7473616d610f5269636172646f2043616d706f7300001b3137446f7473616d6137314070726f746f6e6d61696c2e636f6d000011405269636172646f3138393538393533000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714c0e968a177335220aa220871834d1f214169691dfd97c70823d90d192b246378dc01a59daafffe0d": "0x00000000000000000000000000000000000c487970657273706865726500000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714c0f5d760b3d480556c406cd98bab3d290bba03d428b468a9b6b5a4a53101cd11594fad41a27b2754": "0x00000000000000000000000000000000000e69636c6f6e794163636f756e7400000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714c0f7c7b14b34538fba5cba767a8f31682b274dbb330de35c26ad281d7ceab309649a99d7ea0f8b05": "0x000000000000000000000000000000000005416c616e05416c616e000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714c0f837b7cd7e3836b02b8226fe805f72e05b5c6b634b076a01c30d1cce7f1ab7127e63d6e3eaa06d": "0x0000000000000000000000000000000000054c757575054c7575751d68747470733a2f2f6c696e6b74722e65652f6a7573745f6c75757575001a4a7573745f4c757575754070726f746f6e6d61696c2e636f6d00000c404a7573745f4c75757575000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714c103bcc5de571eaad01b3c1368fe9f57cf7dcd732ce35249557f2ce8876a9d083f0921529afbe52b": "0x00000000000000000000000000000000000844696d6172696b01010101000001000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714c1177e10764520f0286ed5b9c507942cbe163cd75a2cd6de711b44216438b6618c2b1a5af864a31e": "0x00000000000000000000000000000000000e62696e616e63655f6b736d5f360e62696e616e63655f6b736d5f36000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714c1182c59277d714b4697f390f0f6624792b81cc517134435760de5303fed079a7f3ada19c3622900": "0x0000000000000000000000000000000000084a6167754e465400000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714c11b1c3f82b75014e4d733aa6e16d24e220efa69687f6ff198317062ab5ee12a059d47b732c27624": "0x040100000002000000000000000000000000000000000a507572655374616b650e507572655374616b65204c74641b68747470733a2f2f7777772e707572657374616b652e636f6d2f0013696e666f40707572657374616b652e636f6d00000d40707572657374616b65636f000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714c153bf084b7770907a60b5bda7a39f689d7e836cd6496066d3959e65ac56da32ced67bab4454d678": "0x0000000000000000000000000000000000044c656f114c656f6e6172646f2052617a6f7669630000156c656f6e6172646f40706f6c696d65632e6f726700000a406c72617a6f766963000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714c1766eb50d30248b986cd47abb7ad417f9b127dc8c38b34fba72a604cd2643f74b0ecead90af9a57": "0x00000000000000000000000000000000001357696c6c69616d204c696d204b7573616d6100000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714c18ee488c392d992f888820459c387645732dc07dce5bb6884a13caf0c41dc1ee81734a74f19e07f": "0x040400000002000000000000000000000000000000000850415452414354001368747470733a2f2f706174726163742e696f16407975656c6970656e673a6d61747269782e6f72670e686940706174726163742e696f00000d40506174726163744c616273000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714c1a57f5abdde93362461cf63ec5df1c71102f6122af9fca5fab21a9c7bedb84f21f2a07504d98213": "0x040000000002000000000000000000000000000000001e48756220556b7261696e6520506f6c6b61646f7420f09f9299f09f929b00002140706f6c6b61646f745f6875625f756b7261696e653a6d61747269782e6f72671d706f6c6b61646f74687562756b7261696e6540676d61696c2e636f6d00001140444f545f4875625f556b7261696e65001c68747470733a2f2f646973636f72642e67672f353743444568363600", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714c1ce12824a5cf3c7b2bbd89d32024cfa3f782fd05b0e325cb9d364d419d85768bbce95395f124e18": "0x000000000000000000000000000000000006432d31303014436974697a656e204f6e652048756e6472656400001e636974697a656e2e6f6e652e68756e6472656440676d61696c2e636f6d000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714c1d7648a3e3194dab2bdb0d774986625498e0b5fce860c7d58103bdb6b7b348054d525fddc3f3e7f": "0x00000000000000000000000000000000000a506f6c6b61506f6f6c00000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714c1d9151efd144bc7c6e2ca836b28b68978aa39dc41d5b7ef3a7b8630a3e432d8ca99f24fd86cbd05": "0x040100000002000000000000000000000000000000000a64616d736b796674770000001c63727970746f64616d736b794070726f746f6e6d61696c2e636f6d00000b4064616d736b79303031000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714c1e288e289580287886286c58d67217bdd854832d5e9f1b218dec6a0ff7e0b7573147ca94a233a0a": "0x040100000002000000000000000000000000000000000c4269742e436f756e747279001468747470733a2f2f6269742e636f756e747279000f6869406269742e636f756e74727900000f40426974446f74436f756e747279000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714c1fb74b2482e1fa3be485a0806e6773e0f8df67b7a7849f2171fd0e42db790dfd9d9e923e79e6d30": "0x000000000000000000000000000000000015747269636b79206e6674206172742074657374730000000000000d40547269636b795f4e465473000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714c240fbc12423680f764c70f6ae87fd18e901fbe3da02098ba42459d29bf26602ec68c229292f301f": "0x040100000002000000000000000000000000000000000b5374616b656454656368001968747470733a2f2f7777772e7374616b65642e746563682f001b7374616b65642e746563684070726f746f6e6d61696c2e636f6d00000c405374616b656454656368000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714c247e5052d61631f088a514be77fc6e8c07ca16c66eff21fabda2362183d9342b017b7f4e3abfa1b": "0x0400000000020000000000000000000000000000000008696c347231343100001440696c34723134313a6d61747269782e6f726712696c347231343140676d61696c2e636f6d00000940696c3472313431000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714c24a329489b706b1e402e6024bfb3168e669c83931a367668e2cb6721ae85d549caeefd9cc74523d": "0x0000000000000000000000000000000000084769674d696e64001468747470733a2f2f6769676d696e642e61707014406d6d61686572653a6d61747269782e6f72670000000a406769675f6d696e64000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714c24ad04d4c11675896324cde80264d4b481bbfff59c179288380084d346630e3d69ae79a584ba27a": "0x0000000000000000000000000000000000067375736c6f000000195365726869792e7375736c6f40686f746d61696c2e636f6d00000d4053657267696a5375736c6f000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714c24ccc1f4f0c01535860ef101dbbcbd69d9c3c0d43cdd6ac285ea2d81e5de77ea31c9b5f46345507": "0x00000000000000000000000000000000000d5468652053756220436c75620d5468652053756220436c756200001967616261676f6f6c676c6f62616c40676d61696c2e636f6d00000f40546865537562436c75624e4654000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714c2531fceab22368da26c51051a9031ebcc5ae2a4eb9a72e444a5bff59b995ce4612ed8cabe8a2a70": "0x0000000000000000000000000000000000144272616c65204b7573616d612057616c6c6574064272616c651368747470733a2f2f6272616c652e78797a2f0012737570706f7274406272616c652e78797a00000b406272616c655f78797a000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714c26b60c340f2850fe003e4deb7ba19046cc38a5b19fce737a9b85dbcffd02c7a9b5ac939c649bc3c": "0x040400000002000000000000000000000000000000000e4368656e5a6f6e6778696f6e67000013407a786368656e3a6d61747269782e6f726711637a78637a6640676d61696c2e636f6d00000f404368656e5a6f6e6778696f6e67000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714c2d515788ab8e1a0e27efcd0fd4d153900de5a5eef0ff376e377856eda61b99e351d8b0feab02271": "0x00000000000000000000000000000000000850617a204c61620101011474686570617a6c616240676d61696c2e636f6d000001000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714c2d9f475a129afb3de35d75951081e7ba5a6bd03a14547079abd9ba3e02b86be08857cb2300fe370": "0x000000000000000000000000000000000008526f6d312e696f00000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714c2fca83922e702d9fad031becd3e949c4168031dbf67cfd0425c23cc9e97602945557cfe94f9686c": "0x00000000000000000000000000000000000000000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714c30921ca6904d9b0481d2289e340dbe924b2d24032e0382fa4385ee579617d900962044ef8f76d78": "0x000000000000000000000000000000000005574f4e4700000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714c3125cbfe931ee052c08cfa5b2dbfcf6850a3b836596d82a9ed7d2d743b42aa5c69798b502b29b57": "0x04000000000200000000000000000000000000000000104e6175676874794e6f6465732e696f000016407472697072616d626f3a6d61747269782e6f726718737570706f7274406e6175676874796e6f6465732e696f00000e404e6175676874794e6f646573000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714c3177ffd686ff73b887aa7b29cd25037b5adbc515ffe27ac96d457cd8af6bb2dcd486fd29e89c955": "0x00000000000000000000000000000000001454686520476f647a696c6c61204c656164657201010101000001000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714c3187f2193d5784124833c81b9862a86b8f6d9b7099661ec45acf14f1831acf5184dc477d5f1445b": "0x000000000000000000000000000000000007707369633474000012407073696334743a646174612e6861757300000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714c3288af44cc8896786018db371564be5c7f5c49e28d43d00c70d34cbf53f71705f1f670a3dedac5e": "0x0000000000000000000000000000000000184f6e2d72616d7020426f756e74792043757261746f727300000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714c32db95f6c40dffcec4b556151cf2da16df2febda18f31e50231881bc5d55a845958bfe87c59e12e": "0x00000000000000000000000000000000000000000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714c3307fa4d9163f3c203066b0a657bdbdbe9974c20a2644881f384f9b206c7c394054c0d411d7bc6e": "0x00000000000000000000000000000000001c526f746b69204b7573616d6120626f756e7479206163636f756e7415526f746b6920536f6c7574696f6e7320476d62481268747470733a2f2f726f746b692e636f6d000f696e666f40726f746b692e636f6d00000a40726f746b69617070000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714c33e475fb0c3b46a9af751af01e61162cc3339e23de3d5387e209eb8ceddc992e4ceff620ccb837c": "0x0000000000000000000000000000000000064261726f6e0000000000000c4047656f7267334c6f7964000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714c3427b260581a0d4dcd6bde04b554d3bc0cd72a5cf503ec854b4a44a4e5a9f8057dc2d0cbcaf5b41": "0x040000000002000000000000000000000000000000000977646d61737465720000154077646d61737465723a6d61747269782e6f7267136d6f6c7465732e6740676d61696c2e636f6d00000d404d414b53494d3738383736000b6d616b73696d3133343900", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714c347cff095b54034e6261adac5418d9d46cb1d02d640d2afb74d5d27945a2c28e176049a6d757d5b": "0x00000000000000000000000000000000000000000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714c353eaa2aa4b36d7c48799cc5e6109c73e8502411177081cd1c77881a6ec2f61bd0d11df09c40804": "0x00000000000000000000000000000000000e62696e616e63655f6b736d5f330e62696e616e63655f6b736d5f33000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714c35fa9be4d106de5521cb7c68dd8c9563fa2cdb0311f820f8aafae31da6007aa89730cde9f46db3a": "0x00000000000000000000000000000000000773746572796f0012687474703a2f2f73746572796f2e78797a000000000a4073746572796f3335000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714c3724f9765a6e28605dec8ffa7205cedfddf7d4a5d76b469d764a9833a3929b33c39a8479c3762ef": "0x080000000002050000000100000000000000000000000000000000000000000000000000000000000000000d44494e4f56414c20f09fa6960000144064696e6f76616c3a6d61747269782e6f72671261646d696e4064696e6f76616c2e746f70000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714c38be37ff19e3a8a7617b9c6475f887ba801cee49b322a4d888224c8d0791bb0d5c999b6605e251a": "0x00000000000000000000000000000000000a73796e636c75622d310a53796e636c75622d31000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714c3903a41eb7b0ea04a1e5db2241a15c418162119c39fe2e9570abaa5b36c7225e4a5b306cc39c047": "0x000000000000000000000000000000000006576f6c664b000000000000114063727970746f6d796c6f75776f6c66000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714c3946172675052829aaca335cc3dce64d9ed58100cafbefb2bb2973985671676c7d645936a5d172b": "0x00000000000000000000000000000000000e54484520434f4c4c4543544f5201010101000001000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714c39daa94631294ae14ce4e09b999c54351c75b74d0bafdd17d86d98b6aab5176b9068e1be13e096f": "0x0401000000020000000000000000000000000000000014f09f909120686f646c2e6661726d20f09f9091001268747470733a2f2f686f646c2e6661726d1640686f646c5f6661726d3a6d61747269782e6f72671068656c6c6f40686f646c2e6661726d00000b40686f646c5f6661726d000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714c3a4d5d0c403e3b4387cbbabecc63d610ae7d4e8089aa6b341a52764f822342e887ba35160a26a61": "0x0000000000000000000000000000000000074b68656f70730000000000000e404b68656f707343727970746f000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714c3a7aee697f8537eced0a17e590489a73c7187393c0004adf62f7bb12bc01c2eab624a81f7b11225": "0x00000000000000000000000000000000000000000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714c3aa48e3a86671870cd7f4ead4230679019f6a6728e1b01daa539969c1ff6e5d7659ee88e6e7792e": "0x00000000000000000000000000000000000c44696e6f20582044696e6f0b506c616e6574204e656f1768747470733a2f2f706c616e65746e656f2e636f6d2f001b6361707461696e2e6e656f6e40706c616e65746e656f2e636f6d00000f40706c616e65746e656f5f636f6d000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714c3b1ad8cdba491b4b2379dab464407695ce9efad8a5b30814255ec0a7b680ed5e90b008d5991a730": "0x000000000000000000000000000000000007566963746f720a566963746f727272520000000000094056696352646576000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714c3dee0cf198fa26528148ad524276363bd3c138bcbf71d62971c8e7a4e67e4833dad82d554d1372a": "0x00000000000000000000000000000000000a446176652053616d6115536c6565704c65737320436f6c6c65637469766500000000000d4064617665646f7473616d61000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714c3f203317925ee60342908079a81bffbcebf5120459750595a066d3d1a00547f26a5b8602ae1ec51": "0x00000000000000000000000000000000000c686172756e6f686561727400000016797575626172696465737540676d61696c2e636f6d00000d40686172756e6f6865617274000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714c3f2c1579fa4e27478baec43fd49badfce811cbba08b3f0ccf758b5e22f0c4d745452f5dad6eee07": "0x04000000000200000000000000000000000000000000154150455254555245204d494e494e4720f09f8e82001b68747470733a2f2f61706572747572656d696e696e672e636f6d194061706572747572652d6578653a6d61747269782e6f72671d76616c696461746f724061706572747572656d696e696e672e636f6d0000104041706572747572654d696e696e67000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714c3fdb0ea29d362e6b83d19e4a3ad242102f94a4452381300ace74c5d50fbdd9675a869401d3bff64": "0x040000000002000000000000000000000000000000000645726e69680000001a65726e6968656e656c626f7371756540676d61696c2e636f6d0000094045726e6968626f000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714c418004698b256eae08a0336e48b06e7993c654fe5a4eb0926b945368ab819ca106038ff7d951601": "0x0000000000000000000000000000000000064b656e6a69001768747470733a2f2f6e656f6e6372697369732e696f2f000000000d404372697369734b656e6a69000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714c41c1de12f5ccec960c320ebf47a6248effe7b1e0d9fa1a05472d9c9face28267a2d6f3897d8460c": "0x00000000000000000000000000000000000a4a6572656d313933310000000000000f406a6572656d7931397061726973000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714c4203048b255be4d94d18f58da33ad88b8f369b0550f4f119c29487db123a8fd7808192c7515d51d": "0x0000000000000000000000000000000000054d696b65010101136d657461646f6f7240676d61696c2e636f6d000001000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714c43479830549f3b92b1898eea254aee5a9b583a87935d2fdc343cf246324922e7c843d13d4858f02": "0x040100000002000000000000000000000000000000001443727970746f50726f63657373696e672e696f001c68747470733a2f2f63727970746f70726f63657373696e672e696f0019696e666f4063727970746f70726f63657373696e672e696f000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714c4352fa303548bd816e0943d412bdac132040c9c6c72b1e67f2669b9b9ed534c919ad61536fd6631": "0x000000000000000000000000000000000009456c6f6e4d75736b00000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714c4369a5a713b27e3fc7fa982540bee375242fda3776a68bc6b8f1a017d10060303b2a1492d508d04": "0x00000000000000000000000000000000000f656e436f72652e655865f09f91be00000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714c437a1a197732969421c28afeed76e4961a3def6e7a9df8c5bdbd2917e7dc07e16df23f858f06f63": "0x00000000000000000000000000000000000c4379636c6f686578616e6501010101000001000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714c43ae492abb7aee99234e13aa20406b05abfa896fd51dedf36648b5a73a45bb0518593a779c0503d": "0x00000000000000000000000000000000000941627320417274730000000000000c40416273417274734e4654000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714c440bd35b1a2b564545efafec313a5bbbcbf30f172e615132bae08debd8141b0255523338127f52a": "0x00000000000000000000000000000000000d756e7a656e2d7061796f757400000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714c460ca530497a319165990d6152cdfdcb7ec7b5c44e5651d5061f0cc95cb30da6d5537cd8aa06321": "0x00000000000000000000000000000000000e43727970746f4c6f63616c6c790e43727970746f4c6f63616c6c791a68747470733a2f2f63727970746f6c6f63616c6c792e636f6d001861646d696e4063727970746f6c6f63616c6c792e636f6d00000f4063727970746f6c6f63616c6c79000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714c46ba4a0042e414d9ee1fa0d8d4e022ed5680b5925d19718a7ecc9f8f2ff77de54f0822978d27755": "0x040000000002000000000000000000000000000000000c476f6c64656e2047617465000016407365726269616e37343a6d61747269782e6f72671662637374616b696e67406f75746c6f6f6b2e636f6d000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714c4706b7c96f81ec6cc89eac7f80e6c83bf44918ca04feb8a8a2583b4cba629d7388fd98f2ae14164": "0x00000000000000000000000000000000000b426972622054617065730000001442697262546170657340676d61696c2e636f6d00000b40426972625461706573000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714c48230cebc1a6bcabcd06bcfa928213a6402fca4096b81a51bbfce4105322ab80881148437d6e44c": "0x04010000000600000000000000000000000000000000084b6c69646f7a6f136a6f686e6e6174616e2067726973616c65730000116a67726973616c6573406d652e636f6d00000e406b6c69646f7a6f5f6e667473000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714c4b6532d1c37b711aa18b3cf52cb27fd19d5b80fe7982ff955e0d5124dae26ac360056f401dad846": "0x0400000000020000000000000000000000000000000005454e4259001d68747470733a2f2f656e62792d636f6c6c6563746976652e6f72672f1140656e62793a6d61747269782e6f7267196d61696c40656e62792d636f6c6c6563746976652e6f7267000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714c4c023a99cd1728bba1b4c6166343cc8598bdebc0ed4baabf5aa3e212e19fbe876e9b2bf8ea8015b": "0x0000000000000000000000000000000000074754524d524b000000000000094047545f524d524b000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714c4c10952fe64fecb528169b51314b1ec0f014bcd4453d83fa21320e5b19a3b2e02657d0c21f8882a": "0x00000000000000000000000000000000000e50756e6b205661756c7420233200000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714c4cc158572b1a1217c49d0e3c5129947f9a8ff4e10fad98714c31499918013e8594bf3928fc5da3d": "0x00000000000000000000000000000000000c4b6c6175735765696e363901010101000001000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714c4deb83fd3636acd789a634476bba8c44dda974b349800e3618b64732c488f98e75cd6941605ae1f": "0x00000000000000000000000000000000000101010101000001000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714c4f3bb9a6a26a4b7249aca910e224a87c14afb90980ef0db0a6b12c9d6b48c1acae111a1dda36617": "0x040000000002000000000000000000000000000000001050617261636861696e732e696e666f0000000000000c4070617261636861696e73000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714c516a00589c5f1062af1849b7c7bedbe910d02ee342f6318414d33f17a50f00c029ec0eb359c6174": "0x040000000002000000000000000000000000000000000744616d696d690000134064616d696d693a6d61747269782e6f726700000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714c51a01ea9809075a3a42cbc61ac54236d45147631d7fb2b7b32003bc2d53e6e9534ca518084fd814": "0x0000000000000000000000000000000000114b6f7374796120436f6d7a756d6f6e6500000000000008406b6f6261346b000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714c531d8ad189c5d4d660e9b4063cfa8684f52190e679f8cbdcbeea8886bdca31d38c6da70c07bdf4a": "0x04000000000200000000000000000000000000000000096c61676172746f73000000176c61676172746f73313938374079616e6465782e7275000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714c544e460580be7c67c05666c7b84f6e937f6972ec3117110bb0750d2994bf1f680b133d990b98e1b": "0x000000000000000000000000000000000007796f7534323507796f753432351868747470733a2f2f6e6f74652e636f6d2f796f75343235000000000b40796f75343235796f75000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714c54cd15798f98d6ffa84a4002c8ade8078eeb6ee7d4516e548c6eefbbed2d87acaf329d77f29a378": "0x0401000000020000000000000000000000000000000009576f77204c61627a1c576f7720496e7465726e6574204c61627a205076742e204c74642e1968747470733a2f2f7777772e776f776c61627a2e636f6d2f1540616d69742e776f773a6d61747269782e6f726717616d69742e73696e676840776f776c61627a2e636f6d00000940576f774c61627a000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714c55831fe1424bc8f4a2a8a33eb13857917959b364672391a64e41f03129c74dc5bd7856fc0fcf964": "0x00000000000000000000000000000000000a416c706861204775790101010100001140616c7068616775795f63727970746f000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714c560adb2f53e7fdbba0518b2408a0883ce26ff4ea90f8639ac05332bf82260fc45033d7b5baa0a20": "0x04000000000200000000000000000000000000000000097279616e686967730000000000000a407279616e68696773000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714c56c778db308e44b8e32641448f9a5ec78ad04a33b7874a2942ca7ad4c7e8ee2e45409cee1883e06": "0x0400000000020000000000000000000000000000000009436f6465676c6f770000001f74727564696562616b616e6175736b617332313040676d61696c2e636f6d000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714c574259a47c36e9cc6730bbb5f77a45b3095c85b50d6d536d358147478f05ed0337d07f43a4de17a": "0x0000000000000000000000000000000000065369676d610000000000000f4043727970746f5369676d417274000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714c5873c02a0650aff3cd8c53d034ca3f0878d3b02c6d2f42084d49c024f08ac1637b7446c6d48b952": "0x0000000000000000000000000000000000134c756e6f20616b612074776f636c69636b730000000000000f40706c68615f73655f686c617369000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714c59c65c996cb7128c8d887817cd801c256ae0adad712737a18a89e23eb061b7002839d16530fa0d8": "0x000000000000000000000000000000000009696e66726164616f00000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714c59e3ec2cf0fb44e4e0bc107a3826d65cc8a42f501c9b0bfa88ccaf00041fd568566b99adeb3c154": "0x00000000000000000000000000000000000b4f484c414c412d4e5943104f6d6172204865726ec3a16e64657a1668747470733a2f2f6f686c616c616e79632e636f6d0101000001000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714c5a064463897ec28ba98d1704adcb69b1d50aebfab39709c03713555e3d49e75690492b0a02f547c": "0x00000000000000000000000000000000000b4441524b464f5245535400000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714c5b4b74e80892500b46d25d53359fe3d532417e8eae2cba1ed38c7c3fc775a4bd30df90f820d900f": "0x040100000002000000000000000000000000000000000b5354414b45204c494e4b0b5354414b45204c494e4b1968747470733a2f2f7777772e7374616b656c696e6b2e696f00116f7073407374616b656c696e6b2e696f000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714c5dad8e8b3b4327c8cc1b91e8946862c2c79915a4bc004926510fcf71c422fde977c0b0e9d9be40e": "0x040000000002000000000000000000000000000000000976696b696976616c0000144076696b6976616c3a6d61747269782e6f72671576696b696976616c406b6f6461646f742e78797a00000a4076696b696976616c000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714c5fdab086521b971d0e861d8e4257e09a778688629f5283e51f9875a3def184722a0112005cc931e": "0x00000000000000000000000000000000000a53616c73616f7368690000001473616c73616f73686940676d61696c2e636f6d000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714c605f4a4cc9de0cf60e353afd3230a13cbb023c276697f7c42071973b470b9b1e79a4c1d99f27857": "0x00000000000000000000000000000000002131334333384e657a734a4d6e434c7a56574d5070546b64504779696d6e71773600000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714c62159eb22aa2f9ee882cec1afe19967602ee2cb6ec847b913115fc2d2d1293b467f41f2a817f80c": "0x0000000000000000000000000000000000094d722e4368616f73094d722e4368616f7300001b746865627572726f776f666368616f7340676d61696c2e636f6d00000e404348414f535241424249545f000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714c62d71f1d9e80b5e284eb76f4116f4b75a718fd1a374cc5b6e02fc18f37e02deb3054e57539c5328": "0x00000000000000000000000000000000001ee29b93efb88f20444f542056616c696461746f7220416c6c69616e6365002168747470733a2f2f7777772e646f7476616c696461746f72732e6f72672f636f001b646f74616c6c69616e63654070726f746f6e6d61696c2e636f6d00001040444f5456616c416c6c69616e6365000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714c637b13dd6b9ed4474c76b2bb6e2e4b16fec1849aefadeae913aed26e72e2101a4dc34abb3e40776": "0x040000000002000000000000000000000000000000000e43687269732d5374616b696e67001b68747470733a2f2f63687269732d7374616b696e672e636f6d2f1240636c616e673a6d61747269782e6f72671863687269734063687269732d7374616b696e672e636f6d000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714c654d73fa3ebaa0b52de56cc1be8f484e681df0b45bea0eed7149eb4b83af80723b44eba4d04db1b": "0x04000000000200000000000000000000000000000000084c4f4e524f5448000014406c6f6e726f74683a6d61747269782e6f7267176572696b2e6c6f6e726f746840676d61696c2e636f6d00000e406572696b5f6c6f6e726f7468000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714c65c9dea76fe6a4a04c560690aaf6359dc5dd27d7ad3424eb447f4460f1dff44949de5dadb457545": "0x0000000000000000000000000000000000064b657474790d4b6f746b6f7661204f6c67610c6b6f746b6f76612e6172740013616e747a616b617a40676d61696c2e636f6d000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714c662ab00c0706d5924c127f0b5492bc5439fb0dc1acfed7132bc27b761eb5ac5904670091251d12f": "0x00000000000000000000000000000000000a5468654d61737465720000000000000940636f6e78657074000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714c67401b1f25d1590b45b073f1e692d18c2dcebae861b2f166a4dbfd95d9780ffef603c9e61d00935": "0x0400000000020000000000000000000000000000000004536f6c00001a40736f6c76616c696461746f72733a6d61747269782e6f726718736f6c76616c696461746f727340676d61696c2e636f6d00000f40536f6c56616c696461746f7273000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714c68cd80f169ec5de3040ea71921e73b1d72152deb0d9076de5b09d810cc575fb6d11b14820fbbb04": "0x00000000000000000000000000000000000974307a656d30306e0974307a656d30306e00001374307a656d30306e407961686f6f2e636f6d00000e40416e64726577346973686572000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714c693160e6ea97aa8369478717731349632db8341d2a8502aab460f8109dfd249957aeb9b77c3b546": "0x00000000000000000000000000000000000000000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714c69417cb51b0b3c2440d92a969cae5defa9cce85c117ff51435b149ce2a58c38052b195a64f8d050": "0x000000000000000000000000000000000017526f79616c20536f6369657479206f66204368616f7317526f79616c20536f6369657479206f66204368616f732068747470733a2f2f726f79616c736f63696574796f666368616f732e636f6d001e6368616f7340726f79616c736f63696574796f666368616f732e636f6d00000f40726f79616c736f666368616f73000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714c69593e93494eefa1a2b74aeaa4f3d498de298ffb9775c2918de5e045085edb29dc9f3e339045929": "0x00000000000000000000000000000000000b4a6f652041646f6e69730000001363686566796f6d7a40676d61696c2e636f6d000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714c6ad09b66af3693b2e9169837f2af124b7e7fbbed4f8b50f26e37f8cb31869d85bb773e9d9c6950b": "0x0800000000020100000002000000000000000000000000000000000a4a4657454e49534348000016406a6677656e697363683a6d61747269782e6f72671463727970746f4077656e697363682e7465636800000b404a4657656e69736368000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714c6bbf3f9dd9143a5fe6c31fcff28694469c3d4c1681270bdacf6edf7ec39bda6c68cf25738268b79": "0x0800000000020100000002000000000000000000000000000000001b494e46524153545255435455524520434f52504f524154494f4e00000020737570706f727440696e6672617374727563747572652d636f72702e636f6d000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714c6c6796a808b7f32a8a99a7f49f1d3d72656674fea67bc18454325f00c9a5921ec6010c43409d43e": "0x0401000000020000000000000000000000000000000009496e66696e697479000012407a656230393a6d61747269782e6f7267107a656230394079616e6465782e7275000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714c6d8287d03be1c4e906896c321ac4e1c5b1fbdbadbe087fcb428471c1fa9509bec0baaa61bd69c78": "0x0000000000000000000000000000000000124b7573616d6120436f6c6c656374696f6e0101011c6b7573616d612e636f6c6c656374696f6e40676d61696c2e636f6d000011404b7573616d61436f6c6c656374696f000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714c6df602a0447f12d4ec842ef2dc300df355e4193020bcdd204bdb78978963f5a97afefebeed4c43c": "0x00000000000000000000000000000000000942616d6f72696d5f00000015622e616d6f72696d303840676d61696c2e636f6d00000a4042616d6f72696d5f000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714c6fc06d7099c81042ae8b4dd8a198039584f0bb410ba2a196dbbbbb5198d21b0932029e389c92c20": "0x00000000000000000000000000000000000a536f6e6963303538380e457667656e6969204f726c6f7600000000000b40536f6e696330353838000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714c706366b7fce759bea11db7fb06ce5dd7875ec9573d1c2666d4f079eb40a23df9a4e7295a72c3b56": "0x00000000000000000000000000000000000766727061726a0e46656c69706520416d6f72696d000000000011406d696e686176696461706163617461000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714c71b74a26f01154dee57f7f5b5354df1ba908ea77cd152cb3376295e904616bb8048e0ec0a731800": "0x00000000000000000000000000000000000a477265656e20446f6705466f4c69000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714c7289bc44ade334e8db5c746c14cf05e182b10576a9ee765265366c3b7fd53c41d43640c97f4a8b8": "0x040100000002000000000000000000000000000000001144617277696e6961204e6574776f726b1144617277696e6961204e6574776f726b1a68747470733a2f2f64617277696e69612e6e6574776f726b2f001768656c6c6f4064617277696e69612e6e6574776f726b0000114044617277696e69614e6574776f726b000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714c7306504e44e5ca6b6e98494bfd1254db60b4239094d4ef9e9b0d011ae4b27419d31b265f52d3b1e": "0x00000000000000000000000000000000001054616c69736d616e204d696e74657200000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714c7431d97f66121b2fe0a9613f17e9a72fa193ef556525358015d183e34a58d63832eddb68fc78873": "0x0000000000000000000000000000000000094c696e6b53796e630e4c696e6b53796e63205465616d1768747470733a2f2f6c696e6b73796e632e746563682f00136e69636b406c696e6b73796e632e7465636800000f404c696e6b53796e635f54656368000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714c75dd7643a34b25812238aff71d46adf8a5d90a96a764310904cd460493fcfd8b59aec1e9a44781c": "0x00000000000000000000000000000000000c536e696666657220446f6700000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714c75f3283311aa7a1ecbe5cbbe411d0184ebbea1f6e66191f16cf08b10394de1504377a522b67bc38": "0x0000000000000000000000000000000000084a616b2d50616e000011406a6b75623a6d61747269782e6f72670000000a404a616b50616e696b000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714c76c5b0b61a843d020f7bade1ae4ca9f39f905afab90dc0973f36f6c6f4bf8a4869e074ff2fa7529": "0x00000000000000000000000000000000000000000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714c7a8b14e7c045596a8f4e76e2abfd5c4ad2714c6882ee548d8bb2673a8c5fbd4d5d7d8f156d02c52": "0x000000000000000000000000000000000009417274466c616d6509417274466c616d6518696e7374616772616d2e636f6d2f6172746631616d652f000000000b40417274466c616d6535000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714c7b5421a37e04c7cf27d586740d74313a7f109afe5b90bbbf4ce7bfaf6012e8cd417f517658bc665": "0x040100000002000000000000000000000000000000000f446f745363616e6e65722e636f6d0f446f745363616e6e65722e636f6d1768747470733a2f2f646f747363616e6e65722e636f6d001561646d696e40646f747363616e6e65722e636f6d00000f40546865446f745363616e6e6572000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714c7c50372810d645f1e58008212a2c39b0f3366f8698c6f4b3971fe5d694d943d60695da4c7307e7c": "0x040000000002000000000000000000000000000000000d57686974654861776b446f740000001777686974656861776b646f7440676d61696c2e636f6d00000e4057686974654861776b446f74000d77686974656861776b646f7400", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714c7d0409d778a3abd0a25fa0107b9d17ab528cfa9364e83d15ab9cb6b23cbb8e95434a10265e78861": "0x040100000002000000000000000000000000000000000a5369726975734c6565000018407369726975736c6c6565653a6d61747269782e6f726712616c653461696e40676d61696c2e636f6d00000c405369726975734c656565000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714c7e1ca011cc6d3a254c2eb516540f8e793d64120867503bc75ab13dbd7d372a84deb2383dd34be37": "0x000000000000000000000000000000000006504c4b445406504c4b4454000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714c7e9bc04cc0841dad6030dd61ad78ca1900865d2b53dd163bbbb5b40c82f94d25cb6ecc750a93c25": "0x040000000002000000000000000000000000000000000d536166655374616b652e494f001568747470733a2f2f736166657374616b652e696f1640736166657374616b653a6d61747269782e6f726712696e666f40736166657374616b652e696f00000d40536166655374616b65494f000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714c7fb1e9c29198d8a5a85dc8a03b70155cfa555804f87078d55ce094d664b93ca4fcb691b04581b4b": "0x00000000000000000000000000000000000c4f6e65536978747954776f00000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714c802b345e9db30fc5ee13a0870d2fe2f9fe52be9487d3981daacb54c0f5be2d258211757f2fabf45": "0x00000000000000000000000000000000000a5355534c4f20322e3000000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714c80d06b5de46ac115084e4f3181522430ad839d9f8ab908a9311f7bff7960d5620a4ece21dc6c373": "0x000000000000000000000000000000000003626e01010119656d697432746869734070726f746f6e6d61696c2e636f6d000001000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714c81b2ea6aabcc47572d9e3049948847b9e6a6530644c05a2cb45c106837134cf856a850edb5d984c": "0x00000000000000000000000000000000000e62696e616e63655f6b736d5f310e62696e616e63655f6b736d5f31000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714c84305f46d65de06525b16363e519b5050accad8bf325992eb4277f962c34a45908a3856d9b4df13": "0x040000000002000000000000000000000000000000001d4261626573205061706573207c20626162657370617065732e636f6d0000184062616265735f70617065733a6d61747269782e6f7267166f666669636540626162657370617065732e636f6d00000c4062616265737061706573000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714c8459543e4138852ec8bcfca5a803b4b7ff05c9370c75a32eb54ea934d0b70a79e28f3cf6f083f7b": "0x000000000000000000000000000000000012566974616c696e61204b6f6b6f6c736b6109566974616c696e61000019766974616c692e6b6f6b6f6c736b40676d61696c2e636f6d00000f40566974615f4b6f6b6f6c736b61000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714c87a0357c51f3bb52c12d0743cebb84ccae67b4976d38c592750755318e088a58787ed6748af1b06": "0x00000000000000000000000000000000000000000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714c880212d643a2db0cece410e91027546424d251e4f6b3ea9edda00a3436226fcfa0caf2d4abdd243": "0x00000000000000000000000000000000000a42697457697a6172640101010100000d40307842697457697a617264000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714c89160c2ea73fddbd66187af628f50edc02d990b6b1a67b9891a65885b9bb34c07ba4eda1b6c316a": "0x0000000000000000000000000000000000084d63466f726765000000174d63466f7267654070726f746f6e6d61696c2e636f6d00000a404d63466f7267655f000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714c89f64234957ad3efa26953ec6ea1b5ea142dc695d8b2d021297ad12925a3c8dab825c4b77eb3a71": "0x00000000000000000000000000000000000000000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714c8bc7c91a9135daa9c41d150136ee8ce0413d0d3b8943a3b40012daec573830dc5380540965c287e": "0x00000000000000000000000000000000001674686f6375747431303230534d53466b7573616d6100000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714c8bd1d64af2d39cd2aa84a3b6e4fa40f02ba25778f3b48821f93170a88a06541f5f4d0e98fb0d444": "0x0000000000000000000000000000000000086e656d626f6b6100000000000009406e656d626f6b61000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714c8c652a6c6cc03c086b64d128a69e9b1029f83eb7bf9fb1df919eb2986dd79d22800df7090ab2410": "0x0000000000000000000000000000000000034246034246000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714c8c74a2a3e4f4b82be8ca3e846ae7a889e4c1da80d271e206587513f37f603af9fbb27d79cdca91d": "0x040100000002000000000000000000000000000000000d444953432d534f46542d30370e4469736320536f6674204c74641a68747470733a2f2f7777772e646973632d736f66742e636f6d154064697363736f66743a6d61747269782e6f72671876616c696461746f7240646973632d736f66742e636f6d00000e4044697363536f667457656233000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714c8cf8e50848b5813a6005418ec9127ff3a23ff34480dfe3434895be2245e6f8673f4d44423f99b6e": "0x00000000000000000000000000000000001454616c69736d616e5f465220f09f979defb88f0000000000000d4074616c69736d616e5f6672000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714c8e58aea5331a2e440480cf82274010064f8deaa5c77dab6a2fa59daa455692ce54d12c9a994b269": "0x04010000000600000000000000000000000000000000094e46544261726f6e06526f676572010113726f67657231343940676d61696c2e636f6d000001000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714c9004303b036c946663e90acdccbcfe743f4c5452f91ff1839756d4799ff6459b49aaa5a438fb754": "0x000000000000000000000000000000000008636174736f756c00000016636174736f756c626f737340676d61696c2e636f6d000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714c91fe577b6a958b7284f0b64b6dee82e7183d0ba4c04670afd04ff4a63c9e1e14bda8a73f3b65450": "0x00000000000000000000000000000000001d4b7573616d612d437270746f666f6c6c6f776572202d20537461736800000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714c92c1ed9cc10809adcc362696a6099c29778cd123cbb6d0f495e3f1a9e72afeed4b2db4f2139626e": "0x00000000000000000000000000000000000e4b7573616d6120436173696e6f0000001a6b7573616d612e636173696e6f40686f746d61696c2e636f6d000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714c936f994b872349594c58421e4f981eddc24e9609efe14d2a9842c941333909917c948007928f203": "0x00000000000000000000000000000000000000000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714c937b7672d52bb682e5bb027d9dd92dce26c209287f9d28539eafca5a061f4813518986f7a938824": "0x0400000000020000000000000000000000000000000006416c696e6100000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714c96059c5a9afeefeba0cb35373e16ab18a85e196f1ee92c262bdcb1a5633bfd4e0d2de5566c7fb28": "0x000000000000000000000000000000000002410241010101000001000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714c978425d9379314ea415a980463876c54b503c358613b5c02d8ac9781c13378797c54ab37fc07c05": "0x0000000000000000000000000000000000086564797a65726f086564797a65726f0014406564797a65726f3a6d61747269782e6f7267146564797a65726f40686f746d61696c2e636f6d000009406564797a65726f000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714c98618f1bd5a9559866b5be7949c1d9d84c3dcb5261213de3a6de7673c9010f7228d3948025ea51e": "0x00000000000000000000000000000000000942657a53766574610b4b6f6e7374616e74696e2068747470733a2f2f6b617274696e696b692e776f726470726573732e636f6d0000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714c9894f2fca6676bee29fdae6c638b84830ee42c3038d1422fa07f3b588f818d58652187753c99747": "0x00000000000000000000000000000000000d5472616465204f722044696500000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714c99f95af84d55e0f7c1e751284e8cddc8b0ba57858b136458feea7fc3d78913c2a222e1486b81951": "0x0000000000000000000000000000000000074e4b59323235074e4b59323235010101000008404e4b59323235000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714c9a1faf09b047ace962bea82e7158b909964ed9a4cda3c07f9ceec8a8f3150264e706fe9c323a91e": "0x040000000002000000000000000000000000000000000857656233456475001a656475636174696f6e2e776562332e666f756e646174696f6e0000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714c9b1a3c984ec1527125166e9a73e926987e64576b3c811f492f4f68e014ea24d780d6442897b6226": "0x000000000000000000000000000000000005706c756b11446d6974727920566f726f7a686b696e000013706c756b3239303640676d61696c2e636f6d00000840706c756b3239000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714c9c02a3bfc8b9747e2b3d30136a5bf1ad99ed78efc1c0cfdc6a2c65d3e30d86b3303f3533e155032": "0x040100000002000000000000000000000000000000000a4d616e74726144414f0a4d616e74726144414f1b68747470733a2f2f7777772e6d616e74726164616f2e636f6d2f0016636f6e74616374406d616e74726164616f2e636f6d00000b404d414e54524144414f000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714c9cbe4bcf11c1191d2eb148157fb8d45267e129807f60a442f1ccc47ae4df830afa70d9f43a57b7c": "0x0400000000020000000000000000000000000000000011426c6f636b6f7073204e6574776f726b0000001d656e67696e656572696e6740626c6f636b6f70732e6e6574776f726b000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714c9eb326fa16dfefb70220894f522a1bc8fbef6774ee1c8a5a9ec8d1279b87238a7e19dbd30e72240": "0x00000000000000000000000000000000000000000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714c9ec7a14c6f069793af2efd3517588570b437e94d0681cb274292bcdc5691a669cc50c0359599419": "0x0000000000000000000000000000000000054375727500001140637572753a6d61747269782e6f72671363757275666972654067616d696c2e636f6d000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714c9f8fd074bd000b91e08d2544c9cd5587cbe30a3108cfc4cace618a9be8b454f063c9c572328a811": "0x00000000000000000000000000000000000544652e4b0101010100000a404b61726c69734433000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714ca0bdf2dfb6adbfd82bb64e45f4f9a337768606d2742d2d9a8f74c5b182538988f3f482385c5d710": "0x040000000002000000000000000000000000000000000e77332e6369736865722e636f6d000013406369736865723a6d61747269782e6f726713737570706f7274406369736865722e636f6d00000c406369736865725f6c6162000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714ca359eff9e5c98c4540dee563747c9e9b41643cdab9e52e9af92a94e44f4c66dd6fa90f384c2384d": "0x00000000000000000000000000000000000542656e6f00000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714ca36ea10611335000e26a5618f2b9e282f4d6638ed18fee981c6a14c8e9062fdbcb2e6d40f8c0e02": "0x0000000000000000000000000000000000135354414b4542414259204b534d205045525300000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714ca6541d4aefa2e0e7e7ffb2550dcf65f92cfe6aa95b1a6a14f48c7cccbbb86dec448ce0bc7d1060e": "0x000000000000000000000000000000000008537573616e746f00000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714ca89595ab373b7c7cc441e3c9176c763162f1c4653557b5d8db2826617b3047c71304d56af3dbd45": "0x040100000002000000000000000000000000000000000954726f70696361720000000f74726f706963617240706d2e6d6500000b4054726f706963617233000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714ca8ae099693f9dabd8004911e882a05affdcf81aea45f611077f07a29dacf6b754bb69ab118ae067": "0x00000000000000000000000000000000000b4441524b464f5245535400000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714caa21989ef628ddcbc63ced3f8fec642128f2aa9c37e989a9313a67e9635dd85e8bd689ae8d0ce1d": "0x040000000002000000000000000000000000000000001bf09f9191204b696e6720f09f9191204b7573616d6120f09f9191000018406b696e672d6b7573616d613a6d61747269782e6f7267156b696e676b7573616d6140676d61696c2e636f6d000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714cab78cfc920692024cc2c4fe71152a41691987950d065635bc8c151be2a230ec84bd9fc8174b2414": "0x0000000000000000000000000000000000044a6f65074d65646c6579000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714cad2d474a0dca84ae2a70ba05a38bfe12181cdbed954062cac47eb43b03bf8681d21ad3cd1622610": "0x0000000000000000000000000000000000086976693830353511596f656c2047757469c3a97272657a20000015796f656c736b6174653140676d61696c2e636f6d0000094069766938303535000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714cad415ee82b7dc86eca814d4775cf33d04650685b06650cf09795a82bb5190ae30f566fd4479c63d": "0x0000000000000000000000000000000000075349474d415201010101000001000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714cade31e76e0a70d17603f2862f044ccc7500542f4b7c1a506a906b92328e1f2b67bf5024d2af920c": "0x00000000000000000000000000000000000b504a53204b7573616d6100000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714caf961ad1b6e226da072610f1e1ffade38a6d64df55a89e6b07f65ed2be0eb6efffdade4ca576c12": "0x040500000002000000000000000000000000000000000b4b6972696c6c5f6e6577000014406272797a67616c3a6d61747269782e6f72671b6b6972696c6c2e6272797a67616c6f7640676d61696c2e636f6d000011404b6972696c6c4272797a67616c6f76000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714cb01c78fd35d35a1947a4a4de496a602e3a59632dbae52cae69ec75b3553f4e23d65480bd892463e": "0x0000000000000000000000000000000000064d69616d690a4e6f207468616e6b730d6d6f6f6e6265616e732e696f00136d69616d69406d6f6f6e6265616e732e696f00000b406d69616d6973616d61000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714cb0f792fe8070fe270499e87a23c3f1f543386563f418c35cc2be29aafabeb0cff59a0f15cddd465": "0x04000000000100902f500900000000000000000000000000000000000000000000000000000013536b794c616220436f72706f726174696f6e001868747470733a2f2f736b796c6162636f72702e6e65742f0017627573696e657373406b727970746f7666782e636f6d00000d40536b794c616273436f7270000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714cb15c6b86fc6d4c40c6a06de638df5f682965b5fc5e146942a192ce193d18f9d16a5c83e1c2d0e67": "0x0000000000000000000000000000000000076465706f6f6c00000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714cb175b4b598df6c7d264719b38fdf6e7c0826edbe8f577806f45dfc22730cf9c9c880eb6ca4f1258": "0x00000000000000000000000000000000000753696179766f094b61746572696e6100001963727970746f6b6174653139383840676d61696c2e636f6d000009404541726f766161000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714cb2e9537050cc6d62c945b125c1ddc7093d9eb5108eb5fb03fd7f5b2a356a60550e74b9e64597d56": "0x00000000000000000000000000000000000954726176694f6c690954726176697320480000185472617669306c694070726f746f6e6d61696c2e636f6d00000a405472617669306c6c000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714cb3200a490ec72062033f1e89095d22a9c51162dbcce5e28a6b12957fdcb4c3cf11ea8def5ea1e22": "0x040000000002000000000000000000000000000000000d426c6f636b20736869656c6400000017536869656c64626c6f636b734070726f746f6e2e6d65000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714cb33c8d6014b97d6009acf482631bef09c51464c57d5db30ddd875c5f21dd1199450ca32ef023955": "0x00000000000000000000000000000000000c4269674c69646f77736b690000001a6c69646f76736b692e63727970746f40676d61696c2e636f6d00000d404269674c69646f77736b69000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714cb4a358712ffad148aee4e164d5d70ac67308f303c7e063e9156903e42c1087bbc530447487fa47f": "0x040000000002000000000000000000000000000000000b6c6f6c6d637368697a7a0000000000000c406c6f6c6d637368697a7a000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714cb682ba63a12c17de85518efd0a4dd7c45fdd8c606b0ee505a47a27d346217a2109408ee13274c5c": "0x0000000000000000000000000000000000064a44756273064a6573736500000000000a407761726d616e6a6d000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714cb6a20ce60145023dc3ef96500d9246616e58c2621b52b0fe610b2877cc448729a0fa245d76c2e12": "0x04010000000600000000000000000000000000000000066a696865650a4a69686565204b696d0000156a656568656537383737406e617665722e636f6d000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714cb6fae720ea9e75188113b77ec9a05954eb87c58258f605a9e987cd76da77c6db8ba3fabeb8be144": "0x000000000000000000000000000000000006526f62627900000014726f6262796e66747340676d61696c2e636f6d00000c40526f6262795f4e465473000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714cb7cdfdf0c41b9fc9638b522bb7d9e74755fdaa96ac541ca9b3b1f287c413befaaa90d0dbeac2627": "0x00000000000000000000000000000000000b526f6e204d657869636f0000000000000a406a61647979637076000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714cb88098f8f0bdce5b8a47aa823c43efc9b5ffb19e212e2aa2cf3fd23347f618dbdb49319390fc870": "0x00000000000000000000000000000000000e43727970746f4368696d65726100000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714cb98884ad3631884800aab741beaf15ba953897b937ea73ec9d823b1f882e375e6e0863e1537d840": "0x00000000000000000000000000000000000000000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714cbad766d1d5ed042d8af91f9bc822770333d322df946d3fd70b816725c14aa94fbbd668cfe1afd26": "0x00000000000000000000000000000000000a4e696e6554616c697300000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714cbb80a8be45d87d27c766a66c689aeb53cfadb70d916bc8a976d5732a3e8657a43ce679104dd115a": "0x04000000000200000000000000000000000000000000046b6d76000000146c6164616b6d76313340676d61696c2e636f6d000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714cbc6d5a0fa733344dc1f18d3495ab571a17c68c9c9142e58c590637c1f07c582969acb8d3ef67603": "0x00000000000000000000000000000000000000000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714cbc819e175aad208ac2709eb9569c861e63940eefaec1f51ccb76eaa84544e56331adfcdec859911": "0x00000000000000000000000000000000000b4441524b464f5245535400000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714cbe70110da64cd0f364ab212143283a263d9a026f023d91bca9053138592463508fa9eebbb597235": "0x0000000000000000000000000000000000074255424c4f5401010101000001000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714cbeb065643b9d95a5e79c3b5b7ac8d930fa186708560edb94e9330c19942ba44830da6ee42171327": "0x00000000000000000000000000000000000b4475636b206f776e65720e446d6974726969204f726c6f760000176c6f7665636f6c6f72646f7440676d61696c2e636f6d000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714cbf301ce3bba9ceb6ab369ac6c6a1d4c5f3b22db6653f8a9f69a1337c993e224329c82e7c0fa0d72": "0x00000000000000000000000000000000000b414c43455520424554540b414c4345552042455454127777772e616c636575626574742e636f6d0116616c6365756265747440686f746d61696c2e636f6d000001000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714cbf8387678df0b09a4b09d484bc36928c3153a6beeaab89e92572b30c1bc4cffd7ef086994d01324": "0x00000000000000000000000000000000000754616465636f0e54616465752053616e74616e6100001074616465636f406c6976652e636f6d00000f4074616465636f73616e74616e61000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714cbfa34eb67b328eafaf4d633c738f86a7a26ef5c993a9079fd3fef82a565b65f14f9c4cc8e569e47": "0x00000000000000000000000000000000000453434f00000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714cc169cf732b5dc8c32b2070011076282b898fbaa43821fa6bb6dc3625b2698e52d79337b37c258d8": "0x00000000000000000000000000000000000c44696e6f20582044696e6f1144696e6f204d61696e2057616c6c65741768747470733a2f2f706c616e65746e656f2e636f6d2f001b6361707461696e2e6e656f6e40706c616e65746e656f2e636f6d00000c4044696e6f5844696e6f5f000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714cc3222aeb2d95a7cf60bb5621e8977718636c7ccb5a45c83def9c670175c845b9b38455da2718014": "0x00000000000000000000000000000000000b4a6f61642e726d726b2000000000000010406a6f61645f726f6472696775657a000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714cc35db54eb98ba1950e5130bfbe3f3c62d83fd50e01b839fd4d45ddf4e07b19faf39a183ec21a93a": "0x000000000000000000000000000000000009656c6f6e6d75736b00000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714cc38c8458a0ac5f12e4ec1a3f402d5b1d0164802b0aab98ae581a6c248cf84093634916377d2e733": "0x00000000000000000000000000000000000000000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714cc718a6b9e9964318ef5289702f6b8c7d22b3562ffda7d5593a5f6414226925e72097efbf9b25720": "0x040100000003000000000000000000000000000000000d5265676973747261722023310d5265676973747261722023311868747470733a2f2f7777772e63686576646f722e636f6d144063686576646f723a6d61747269782e6f72671263686576646f7240676d61696c2e636f6d000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714cc73c26e52b725e15869e5f3b7da844b1638ae3d076f73a439bd4477701b2b95bd4137893bd0a727": "0x00000000000000000000000000000000000944616769654465650000000000000a404461676965446565000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714cc8d0888d5d6f924400daf17b98e3592f65147d0fb6dbd1c322e5562ffeb11ebcf6763a171eb144d": "0x0000000000000000000000000000000000055354414e00000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714cc8de026a3642284a0e2ce7bf17dd65ae193d2b0a5723d089b5d2969045b2c7ca722a43d7efabf64": "0x040100000006000000000000000000000000000000000843727074646f740101011463727074686467373940676d61696c2e636f6d000001000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714cc9822c9da4c837c86b7409a11700afb027924cb40fa43889d98709ea35319d48fea85dd35004e64": "0x040000000003000000000000000000000000000000000ef09f8dba2047617620f09fa5831544722e20476176696e204a616d657320576f6f640c676176776f6f642e636f6d1c406761766f66796f726b3a6d61747269782e7061726974792e696f10676176696e407061726974792e696f000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714cca36d817010587dacdebce9d35e7cdf4793cd9eb2a1223e568c2ed0684d9b852fc21b70a0c86237": "0x00000000000000000000000000000000000f62696e616e63655f6b736d5f34360f62696e616e63655f6b736d5f3436000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714ccf50f8320382ca644da8d011a0f821b2e39d6151f8e17c417c0e09b664587dfe2021a194ee95d74": "0x00000000000000000000000000000000000b4441524b464f5245535400000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714cd07125b43213e171c82102e4554587f23cbd4bfdb0f43c9d2879d18feb6102bbed977930f695f22": "0x040000000002000000000000000000000000000000000e444f5a454e4f4445532e434f4d00001240646f7a656e3a6d61747269782e6f726716636f6e7461637440646f7a656e6f6465732e636f6d000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714cd16bfe2352b1748923f2994a4c517694b0c566751a4670c49cd95c9b545e37c46b9af820dd7dd6e": "0x0000000000000000000000000000000000066465766f68000000146465766c696e407a65697467656973742e706d00000b4064627261626173736f000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714cd1ac1ed28e6a58174b2a542bf7ec24dd9947ac9584d8352191f0154185cf7273f08a79e9ea75f00": "0x040000000002000000000000000000000000000000000e53504143455f494e564144455200001a4073706163655f696e76616465723a6d61747269782e6f72671b7370616365696e76616465722e646f7440676d61696c2e636f6d000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714cd23612967eaf930b8970463116cf97047eb507bc4cbaf1bf77b88216bb6e89b1da5672a44f02f4b": "0x040000000002000000000000000000000000000000000b414b617069746f6e6f76000014406b617032666f783a6d61747269782e6f7267126b617032666f7840676d61696c2e636f6d000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714cd367e518a4206c79653ea6fa2a3e4072178c4de671464a69d9c72c7ff7170bc76697b46b3947b0f": "0x00000000000000000000000000000000000453616d0d566c61642053616d6368756b000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714cd3c992836bd43255a17ce1052e06f947dda66c6144fffbbc07492394521bc16427f9b9851b48821": "0x00000000000000000000000000000000000642696767730000000000000a406269676773636d73000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714cd4606afef2e28ca7eb19cdd47013d60f73e4c9b3e7e95c07dc40841c72d62951b8ed39d46d64a2a": "0x000000000000000000000000000000000005636f646500107777772e636f64656e6f64652e63610000000008405f5f63306433000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714cd489db0874b4738a6483f0d061421d62af3e621dccb1ed608a177e4043ba4d2d73e0935976fcf2a": "0x00000000000000000000000000000000000a6b666775736d63323100000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714cd4a30ce889e7a55c04f1633da0ab6cb71f71ece4d1a5c32926d3f707d250f66ab712d65eb374b2d": "0x00000000000000000000000000000000000b4441524b464f5245535400000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714cd5a4e9b4e3a205200778b6f2104578c212125b47b52181aed777a047f3b299353c36063a5028a11": "0x0000000000000000000000000000000000115468652041766572616765204170657300000019746865617665726167656170657340676d61696c2e636f6d00000e40617665726167655f61706573000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714cd810312c75ed239feb72a25692ef5988cbd2a2b0d5712c47149820d2cb35f0c7fc97635b2eb4b4d": "0x0400000000020000000000000000000000000000000007477573746176000000166775737461762e6e69706540676d61696c2e636f6d00000c406775737461766e697065000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714cd8ba9536297030e5eb369d8759d592d5bab556aff1e2bac770979fc9bb30cb7dd503788a154826e": "0x000000000000000000000000000000000003445300000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714cd92383c67926cf490b857bd025228fc9efe2f2ba5a58a0bacfb3c40dcc0557e484c17a63be1cb1b": "0x00000000000000000000000000000000000000000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714cd9a6f0d7176c667f8903521d75aa8e9c24de8f9fea4011c1ba56c613da7b12bc9a894b896ae7a79": "0x00000000000000000000000000000000000c4d616e75616c204d696e740000001a737562737472796c75734070726f746f6e6d61696c2e636f6d00000d406d616e75616c5f6d696e74000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714cda0448328a47d986e78d0861320e3ba6c6b8eecb666b245d2bf06652c1fa86f7c150e9b2b6f772f": "0x00000000000000000000000000000000000a7061696e6b696c6c7a0e4d6f68616d6d616420417761640000157061696e6b696c6c7a4069636c6f75642e636f6d000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714cda070697bb44382d2cfdfb80cb90a4a5826c98846a367489fd25d3a2561838fa372f39f3f7fb138": "0x040000000002000000000000000000000000000000000c503250205354414b494e470c503250205354414b494e471868747470733a2f2f7032707374616b696e672e6f72672f1240316c3363353a6d61747269782e6f72671a7032707374616b696e674070726f746f6e6d61696c2e636f6d00000c405032705374616b696e67000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714cda793c07d75efb0d4b3dfa23d4da0e7b854d81a2da2d369bd1358ff743fedff29aa5cc1f5fb6444": "0x040000000002000000000000000000000000000000001141495745423320636f6d6d756e6974790000001261686a7863727a40676d61696c2e636f6d0000094063616f5f6c6162000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714cdb0222db39bc78600516484b2e6bac9fcaeeafa925b183ccd118b747074c475f188348e98d85644": "0x000000000000000000000000000000000009737544726f6e696301010101000001000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714cdc30a2149db3bc32a5473f95881089686743849021bc41ddafe705b0654f4fbd84a8c7f7518ad49": "0x00000000000000000000000000000000000b4578706572316d656e7409416c6578616e6472000010636f6f6c36363640756b722e6e657400000c404578706572316d656e54000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714cdcaf2c89675be00ca5963dcd0af5bd2441dd34631995251b151baa252bfc5b80b78637b779b8518": "0x00000000000000000000000000000000000b4e6f5f53747265535f5300000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714cdcb048b3228e1971c167f680b246a86565aa36eb8e525d2ccde935f9be8f53ff592326d7d7bec61": "0x00000000000000000000000000000000001c496e2070757273756974206f6620746865206d657461766572736501010101000001000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714cdd9fdbc6dbda2f1362f9efe78a0d238501313e68a74a9b6257f406c5c62c9162d96852a13f79902": "0x00000000000000000000000000000000001853696b204e4654207c2063726966666572656e742e6465001768747470733a2f2f63726966666572656e742e64652f1540646576305f73696b3a6d61747269782e6f72671a73696d6f6e2e6b726175734063726966666572656e742e646500000a40646576305f73696b000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714cde110fa4c51bbb438a48b1b98077c557c474ad091c854286fdf929b0e710299b16daae9e0ae4a77": "0x04000000000200000000000000000000000000000000084d65726d61696400001a406d65726d6169646f6e6c696e653a6d61747269782e6f7267196d65726d6169642e6f6e6c696e65407961686f6f2e636f6d000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714cde412338d7923785ebe5000d4785e181f7f84d06445071b0d4f5a98cc30d7c566830811b6d33c5f": "0x00000000000000000000000000000000000c54657373615f4461776e310000000000000d4074657373615f6461776e31000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714cdf45b2bad669b8abcb3857cb91529a5fb21358b1ce837e4c12dac8c095e87e689a91dcd58e9bd3c": "0x040000000002000000000000000000000000000000000d426c6f636b2042726964676500000016626c6f636b6272696467654070726f746f6e2e6d65000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714cdfdcd6d89826c1a521909b30a6816fa9a8796e5233ba76cae620e8577a525dd5606baf0797bcb6e": "0x00000000000000000000000000000000000d64726177696e676b656974680101011764726177696e676b6569746840676d61696c2e636f6d00000d406f6861796f6b6569746879000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714ce039cf8a6e0c411546c4b57539ccb82e3ca981340b2eee5b3c973798f1ffaa671d6276031a6d16f": "0x000000000000000000000000000000000007416e67656c6f01010101000001000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714ce0fc9b4caf7f03d56923fcb0c362b333a2833175025883860f6b93996233319503a4ac478b7b115": "0x040000000002000000000000000000000000000000000d414c474f207c205354414b45000016407368616465776f6c663a6d61747269782e6f726713696e666f40616c676f7374616b652e6e657400000b40416c676f5374616b65000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714ce591cccc3c347d0fc90e922a45ef6a5dc3c8abed38bb0aae5b9aa7efcd388fab60e329fe9c2d945": "0x04000000000200000000000000000000000000000000084252554d4d4945000017406a696d6d692e313939383a6d61747269782e6f726718756b2e6a696d6d692e3139393840676d61696c2e636f6d000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714ce5f7c846b1c490828bbb43cf5a770578c5bde89fbb3e4a71d3d19e7e28206bd70f41477984ca123": "0x00000000000000000000000000000000000101010101000001000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714ce79163e5f308367344c5f7ce70559bb401142aaab72f4f6edbe78b4908e6769084cde89349fe63e": "0x000000000000000000000000000000000014546865204772697a7a6c792057697a6172642000000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714ce8d111891bbfa55b4a5accc15f38c85625e18235ef02b0ac671d5016397b23c9d866706db431033": "0x00000000000000000000000000000000001143727970746f5f41726d6164696c6c6f00000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714ce98d27dee4a6c1028258fd47fd5ab4a8e87741bad51dc7a17217617e1d7105bc9b2f8ae4b4fe708": "0x0000000000000000000000000000000000054c656e610000001763696c696e6761726a616e6140676d61696c2e636f6d00000f40656c656e613937363534333235000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714ce9a50917cf77bb19681fe005baa3099a7d9c03a46e539b173d2b3de75b11e86cd5fbb7d4e92993c": "0x00000000000000000000000000000000000a4c69676874736f6e650e506564726f204d6172717565731968747470733a2f2f7777772e726d74657272612e6f72672f00196c69676874736f6e656d7573696340676d61696c2e636f6d000010406c69676874736f6e656d75736963000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714ce9f04748b26cc2d2a6bfaf3c320491696e649842333c75f041faf71e2676d8bfb45f71580372e48": "0x00000000000000000000000000000000000a417274204b697474790000001c6172746b697474792e73696e67756c617240676d61696c2e636f6d00000c404172745f4b697474795f000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714cea9b7b0be6d4be2f0e5ac8e356d7a3867e9919b8cb1984ee5a070b1659b6195deb85039a3b69928": "0x040400000002000000000000000000000000000000000b56344c494448344e44590000154076616c69646e64733a6d61747269782e6f7267166b75736e64734070726f746f6e6d61696c2e636f6d00000d4048616e647943727970746f000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714ceac28e060489d6e601c5348ef25d1c6c432065db0ce29dc6c0b45abe9b5f5e7f2e8f57a49479b6e": "0x00000000000000000000000000000000000b706f6e79737461626c65011c68747470733a2f2f6e66742d65786869626974696f6e2e6172742f010100000c40706f6e79737461626c65000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714ceb2fa92c621e2f85abce4b7d2e2b94046f1b7e77885b955a7cb214fa4a63055945accbf01debe17": "0x0000000000000000000000000000000000114152542047414c4c45525920494e432e0000001f73616c65732e61727467616c6c6572792e696e6340676d61696c2e636f6d000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714ceca4f391ff42f7042316a3e69911695b705e5428a3be87a2b656a09126fdcdd2ef105995132de1e": "0x000000000000000000000000000000000014546f6b656e20576f726c642050726f6a6563740f4761627269656c2053616e746f731a61727473746174696f6e2e636f6d2f6761626f75776e65737300156a67616273616e746f7340676d61696c2e636f6d00000d404a4761626f75776e657373000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714cecd17edf1cf34fa3640cf6c8548a076a324a04190b30c74a44809ee11fd684f49a46134204aa47c": "0x00000000000000000000000000000000000000000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714cecd3df8f50e86adfea23409b33280a4e0109a957dff8a732b88b7e8f85e415a124d64664176a155": "0x0000000000000000000000000000000000094d617279313636300a4d6172696131363630000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714cedae9c81b8ef8ff42be75cb933073a967d8cb8c6c723028208a678c5a58f5e8f49a237eb33e1654": "0x040100000002000000000000000000000000000000000d4a61792043687261776e6e61001e68747470733a2f2f6c696e6b74722e65652f4a617943687261776e6e6119406a61792d63687261776e6e613a6d61747269782e6f7267194865794a617943687261776e6e6140676d61696c2e636f6d00000a40476c646e43616c66000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714cef56560701eb05fbe5e55779d8749406e8ccc62030eafaeeaacb7fe4f583104b2c617c71f4ffb1d": "0x00000000000000000000000000000000000a42617272656c44616f00000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714cf11366ef8733f58e8926b5917a291918a2f0381c1213800798ff37689901f16b6cf42074c61f076": "0x00000000000000000000000000000000000d73756761204469636b736f6e00000016737567616469636b736f6e40676d61696c2e636f6d000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714cf1172ac1fb91b86c07040b1be7aedb10ffc0f136b7e147e4a1ad56944c1c76d6c2f6ca089cf316b": "0x04000000000200000000000000000000000000000000094252415645424154001668747470733a2f2f62726176656261742e696e666f154062726176656261743a6d61747269782e6f7267176272617665626174696e666f40676d61696c2e636f6d00000e404272617665426174496e666f000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714cf126c7c679daef68cbc7210c46afb6cbcbcc10c096d3d5f2c9032242bb4e919abf56300abe3ba37": "0x00000000000000000000000000000000000d50617368613139383870726f214f6c656b73616e64722056696b746f726f7669636820486c61646368656e6b6f000019676c61646368656e6b6f3139383940676d61696c2e636f6d00000d40416c657832303231626574000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714cf32922a67ceafba60ee9ce321ac84dee361edcc6f26a0e04a937a13c6ac1e9c5668805383331311": "0x040000000002000000000000000000000000000000000e42617a61722d5374616b696e670000001a65646f6172646f62617a7a6963613140676d61696c2e636f6d00000e405f43727970746f42617a6172000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714cf5169125cd7414c8875bb054b7e9b35a2d84c19152d17947b1ff629edbf1759ddd9f04ce33b495b": "0x00000000000000000000000000000000000753636f7474790000000000000f4043727970746f5f5379646e6579000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714cf9fb3a7967406dbd08ff136a249a1e0fa14d1dd102f4ca95436d000428a6bcf3dbc178afe19974d": "0x000000000000000000000000000000000009566976617269756d001868747470733a2f2f6372617a7963616e6172792e6f72670016766976617269756d6e667440676d61696c2e636f6d00000e40766976617269756d5f617274000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714cfab6a8090dafa3c00ad3ac9b1478e7fe24ec13e47acea1de9c52dc4b1dae34311524bacf23b5d0e": "0x04000000000200000000000000000000000000000000154a4741667261697343624379662d2d2d65644e3700000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714cfe36321ef78340db0d6a32a5f2a51d3814658dfdb3c0f9448c57cb18a766c755a6310166dae3137": "0x00000000000000000000000000000000001e4c6567656e64617279204b696e6720262053776f72642042756e646c652142757920746865204b696e677e4765742045766572797468696e6720456c736500001a6e656d6573697364656675656e746540676d61696c2e636f6d00000d406b696e676d6f6f73616d61000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714d001fc2ba95e343662be9aad248398097b439acd2534396228c1fbe87deb19fd5ba444715fe0e143": "0x00000000000000000000000000000000000d446562746f7665726c6f61640f54696d6f74687920436c616e63790101166d696c6f3837636c61737340676d61696c2e636f6d00000e40646562746f7665726c6f6164000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714d00914612039bd0a8c2906642eb60a6fc2223771fc33c3a96e94eba9683bc50a6e2b5c70db6fbf2a": "0x000000000000000000000000000000000007506f6c6b613100000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714d0122e96825a0068745a3099faa56c038133a62829a680ebda7b368b1659dde5237d8eb1a60efb30": "0x0000000000000000000000000000000000096c756b69636438380c44656a616e204c756b69630000186c756b69632e64656a616e383840676d61696c2e636f6d00000c404372797074446f673838000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714d013db7b7a6128798e6fef1631647c0defb15811a12f19e3a964322dbe0293f329824ff6d94e9805": "0x00000000000000000000000000000000000a6d636d61637374656e0e4d41524b2041205341594c45520000186d61726b2e7361796c6572313040676d61696c2e636f6d00000d404d61726b5361796c657232000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714d0197e8e8f3672a578cb58e575019116c0f5e1d698210f9e1981eac0b1bdd419dc029ba193accf79": "0x000000000000000000000000000000000011f09fa5b04d414d4143495441f09fa5b000000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714d0201be4d1c2cc92ee92a79760d0480aab1a940b0abab817dfcde83655e4d2c71682ce272b26ef0a": "0x040000000002000000000000000000000000000000000c4a6f73652e43727970746f0000000000000e404a30736552616661656c3132000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714d022db95af4618a2a875793cd52c841f83f61d346cd7ba2f5d6219e8a6ddb951b73df0a1887c7619": "0x00000000000000000000000000000000000000000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714d0524a63ed8afdc650df6ec6f3dbb1134df6fd1d572d4dfdbe1058fca0e7197ef8d0f3d05a720f5e": "0x040000000002000000000000000000000000000000000a446f6d694e6f646573001568747470733a2f2f646f6d696e6f6465732e696f001368656c6c6f40646f6d696e6f6465732e696f00000b40646f6d696e6f646573000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714d0569ffc10d41f9a4c70ba55ca8bec67d63f35b1a88daf1bae874e0f8df029e9b026447c3f025917": "0x040000000002000000000000000000000000000000000a56616c6c65746563680d56616c6c65746563682041421568747470733a2f2f76616c6c65746563682e65750012696e666f4076616c6c65746563682e6575000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714d0579c696be22af2a8b653aaf32a9addc7d2ed4216a147eb03688ceccf00ec0970dcf2a3b01c0227": "0x0000000000000000000000000000000000134a616d696526e282bf6974636f696ee2938b0101010100000a404a504b3130383120000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714d0588fe1333a77f1467535f6ed22a8ec7da3d7e7529f8c68380ffda3201bcecaf2d4d86c45618d78": "0x04000000000200000000000000000000000000000000084d656c616e67650000134070616c6163653a747a636861742e6f72671a6d656c616e67652e7374616b696e6740676d61696c2e636f6d00000b406f6d676c6f6c323437000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714d086b21014fcda260a50bd5098bfc45338fed742fc7a935aff9ed058c5377b20116585907f106201": "0x040100000002000000000000000000000000000000000f44656c6567614e6574776f726b73001268747470733a2f2f64656c6567612e696f1440636f736d6175743a6d61747269782e6f72671664656c6567614070726f746f6e6d61696c2e636f6d000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714d08db4c7456c2d34dab5043bb5134f4438965a1abaf5d431109935a6f973b5b9355c6e4811688f2e": "0x00000000000000000000000000000000000f4368616f7469632042696174636800000000000010406368616f7469635f626961746368000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714d09bef61f6731fab549209edfbe534c3455d7fee7e340f8f8c8c78e4af36250ef8771556f5006d0d": "0x00000000000000000000000000000000000f62696e616e63655f6b736d5f34340f62696e616e63655f6b736d5f3434000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714d09eaf34f53d7c401480bc228ee751c1aca34061c4952efb304aa94beed8e38fd9c5e693f62c3f26": "0x040000000002000000000000000000000000000000000d63657361722063727970746f00000016636573617267653133303240676d61696c2e636f6d00000b4063657361725f676573000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714d0a4a707f90f5d345a1351655f559e75b557ba12681698329a54cb32af516149d3022170a8e9da2e": "0x000000000000000000000000000000000012f09f98902067686f7374207c20f09faaac000016407265706c67686f73743a6d61747269782e6f726700000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714d0a70cfbeda907dac69dc00ee1c6849e18d9c051c8c1b1b0ceb69ae18ab0d65ef7c47a2bddee462b": "0x00000000000000000000000000000000000d4a61684a61684a61684a616800000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714d0b071ed4c82c6f2523d37e118dbbad00009bf4c20c246c8b2b671bfb53d1fcb43d9471c932db910": "0x00000000000000000000000000000000000d52756675732054616e67656e00147777772e727566757374616e67656e2e636f6d0016727566757374616e67656e40676d61696c2e636f6d00000e4072756675735f74616e67656e000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714d0c787a6865b130b8edef9f52ba1a7f47dc10e12cb4744142161796b5b5c7e75d680bc3b81c90a2a": "0x00000000000000000000000000000000000c5366792047656e6573697300000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714d0d9546392e1385bfcb1063d22c8af6fcd6eadf0954652aabfd55276889537d52a30cf388380a503": "0x00000000000000000000000000000000000c43727970746f67656e696b001568747470733a2f2f73796e63626f6e642e636f6d000000000d4043727970746f67656e696b000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714d0dbdf366d9f3ca08ec383bdee26bce0aa83397a3b9bb7ba40991930ba4aee2d9f2d34243e89c217": "0x00000000000000000000000000000000000c43726f77642d4c6f6e6572001768747470733a2f2f6269742e6c792f3330354e635250000000000d4053616d3837313632353637000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714d0df4de4538d923df2a82c1d57641de66f431f758780229672378cd679da86f6eba0b433162d8003": "0x00000000000000000000000000000000000f4275726e696e67204368726f6d6500000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714d0fb318e6895ef127add073714bbf9da81fe49db63778e918217e56c55e4f81f68e7d2e7d0e59d0e": "0x04000000000200000000000000000000000000000000114c696768746e696e6720426c6f636b7300001c406c696768746e696e67626c6f636b733a6d61747269782e6f72671b636f6e74616374406c696768746e696e67626c6f636b732e696f000011404c696768746e696e67426c6f636b73000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714d11ea423e08f049a7a7c74e948826a6398a493f365bf1804333f3c11e86f19836d5c10586a66cd47": "0x0000000000000000000000000000000000174b7573616d6120666f72205375627374726170756e6b1c5368656c646f6e20417274696d7573204c65746f6e20446561727200000000000e40417274696d75734c65746f6e000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714d1310d7acc9400e91e434355bc1417f634ec3ee756d9dad562220624b106c1dbc756953a47784d72": "0x00000000000000000000000000000000000441756e0b4b696d206a7579656f6e00000000000b406b696d6a7931303239000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714d1366f9ff3873f7d487410e002435daffbfedffa6d8618013f1e36554abbacb543030be0b7967b54": "0x00000000000000000000000000000000000b6d617472696d2e65746800000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714d13778bef3c90858128b1857f835ab1569c06a71e4de49df3154a9d5a5fabfa2a4f1ab1c458bc140": "0x040000000002000000000000000000000000000000000b50415354415354414b450000174070617374617374616b653a6d61747269782e6f72671570617374617374616b654070726f746f6e2e6d6500000c4070617374617374616b65000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714d14a0dfd491494bd5c57aa62fff146488c4f113b98906af70fc9ab8ec3684b907674631e68dbb60c": "0x0000000000000000000000000000000000054164616d06576f726c64156a6176617363726970743a616c6572742831293b156a6176617363726970743a616c6572742831293b1877656268756e7465727332323640676d61696c2e636f6d0000156a6176617363726970743a616c6572742831293b000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714d164f9f8d9b541902e69ac91dc2b3e54afd2d74736e7dfd95faa1e738dab066c80328980c7c9076e": "0x04010000000200000000000000000000000000000000054572696305457269630014406433636b6172643a6d61747269782e6f72670d6572316340747574612e696f000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714d17427312158ad52740a79bb171acbce71d00d7b3ba20b473c97e24210b6fc72709437cb2f255232": "0x00000000000000000000000000000000000000000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714d19c764f1166955be6618c285b3ffd78f73aca116933544ad022b9144c2b610e7e608e267d529060": "0x00000000000000000000000000000000000952657a69737465720747656f7267651f7777772e626568616e63652e6e65742f47656f7267656f72756439323861001947656f7267656f2e727564646b6f40676d61696c2e636f6d00000c4052657a69737465725476000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714d1ae9c278f9f249deccc7facbab0732bef0a1feacbf9ba3330b0cfa4869ee8176fbe89bcb0e36e67": "0x0000000000000000000000000000000000115961727a61722020f09f87b2f09f87b200000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714d1c6a0460fda08feac9e892f6429cb00d736600e22204ad08382011d46fb5493ef1463d04346417a": "0x040000000002000000000000000000000000000000000d4445564741494e532e434f4d000015406465766761696e733a6d61747269782e6f7267126d61696c406465766761696e732e636f6d00001040446576656c6f7065724761696e73000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714d1dd5241c7691a93e48a9217aed06778d9f2b22fb910dc2344aea38e5746bfe344094f33de9ceb2d": "0x00000000000000000000000000000000000747656f42697400000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714d21419bdc819121d18b69aebec4f5274c289716bb8b61f192243046dd34040a3f3c7a8d5ae9dff7c": "0x0000000000000000000000000000000000046b6970116769726c7320737461666620636f6f6b000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714d21b6f71d23b15bb1ea86f3c82538c486a25d8abca26760e57e76a01212419c7f1c8b510121fca73": "0x04000000000200000000000000000000000000000000074761746f727300001d406761746f72732e76616c696461746f723a6d61747269782e6f72671b6761746f72732e76616c696461746f7240676d61696c2e636f6d000011404761746f727356616c696461746f72000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714d22a996b9e9b22ce7c26453f69b2035a88c47342946a277c38c8f0b186edc76c70669d1cada5cf61": "0x0000000000000000000000000000000000096172676f6c61627300000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714d22cff40d8b99c1922a526d0737cdeb4db20761888e847735b40344277d06c13cd4c691a1ec5a45b": "0x00000000000000000000000000000000000749414d594f5500147777772e69616d796f756d757369632e636f6d184069616d796f756d757369633a6d61747269782e6f72671f69616d77686f796f757468696e6b796f7561726540676d61696c2e636f6d0000104049414d594f554f4646494349414c000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714d2350e1f5f2021c3d2170dd5961428199af9e238cfb231d3396505876859e13d08e89e39d7b4201e": "0x040000000002000000000000000000000000000000000e4b5553414d4150524f5048455400001a406b7573616d6170726f706865743a6d61747269782e6f72671870726f706865746b7573616d6140676d61696c2e636f6d00000f404b7573616d6150726f70686574000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714d23775b734524690003c82da67b26395b86b46bf7528a984e5593a9305e598b18829c1a9409b8c52": "0x000000000000000000000000000000000007627562626c650000000000000c403078696e766573746f72000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714d24c3c8c823f5e00224346ed63fa298c8064eddece0712330342a50f2f152a5fafb454f009a56855": "0x0400000000030000000000000000000000000000000011416c20736369656e7469737420773366000019616c6973746169723a776562332e666f756e646174696f6e00000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714d25b2b83caf5ac06d857fcac7bd9bb03551d70b9743895a98b74b06e54bdc34f1b27ab240356857d": "0x04000000000200000000000000000000000000000000065465736c610000001b7465736c612e76616c69646174696f6e40676d61696c2e636f6d000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714d264c3aadfa8b5d504926a875678c28947f61c56cd0a8fc948ff18e48315721fe44aa4be38489476": "0x00000000000000000000000000000000000b4172746572614c616273001768747470733a2f2f6172746572616c6162732e6f7267000000000c404172746572614c616273000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714d265ee733a44472d560fbd75b3db96ef71e33b61600e3f37a926400887daaaae380d3636949c0767": "0x0000000000000000000000000000000000064a6f736879000019406a6f7368796f726e646f7266663a6d61747269782e696f0000000f406a6f7368796f726e646f726666000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714d26b218cd225b87f20b9f0216e1f1c33834df5b215115336368c549891ac1171e9710c2126753c00": "0x000000000000000000000000000000000020f09f90b2204b7573616d6120447261676f6e7320546573742057616c6c6574002068747470733a2f2f6c696e6b74722e65652f4b7573616d61647261676f6e7300186b7573616d61647261676f6e7340676d61696c2e636f6d00000e404b7573616d61447261676f6e000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714d29a5a781e83f345f618d8489511f00682df9f7d794d081cf5716b012d014846c01a162e94091d15": "0x00000000000000000000000000000000000000000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714d2ccbf0f9e33bffd5446c059c4c78c9ead43f0694ab1eda254de55c5db245c4f8e45d95fc62def47": "0x000000000000000000000000000000000006576176657201010101000001000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714d2d52954fa3e2a736ad94ba63e2b5f27cdf2b293076d03d6fdff2c14a4613668d3f37596a78c9847": "0x00000000000000000000000000000000000e4669676d656e7420427261766f001368747470733a2f2f6669676d656e742e696f0000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714d2f1f3681fa9bb4720112dff656489548b0a7815a06d3a59f93880ea46ee2662a6439bb431bab046": "0x04000000000200000000000000000000000000000000096c7578382e6e657400001540616d6133313333373a6d61747269782e6f72670e696e666f406c7578382e6e6574000009406c7578386e6574000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714d2fad4b1e4fea8e60e04422d0a8edc33aac00d194877069ce2b3b5827b78bfe9b54124a24294d811": "0x00000000000000000000000000000000000b426974537461636b2d31001568747470733a2f2f626974737461636b2e636f6d0010626440626974737461636b2e636f6d000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714d2fd31147177f387ca4b1c51a3bf66af076145f088443de0ef7cd283e0db88a50032a1cd34f3232a": "0x0000000000000000000000000000000000064b4f4e414e00000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714d308cb70d43f28085c2a5b5f64917252f743cfd8fec900587436c383086598aa71c93692661e5f59": "0x000000000000000000000000000000000008546865204d697400000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714d30c2eb96b5970eebe15890524198006c60a31bcd93a4bbf321e5ae01bc561da4e64bbbcc6e9b359": "0x00000000000000000000000000000000000e4d616e7461204e6574776f726b0e4d616e7461204e6574776f726b16687474703a2f2f6d616e74612e6e6574776f726b2f0016636f6e74616374406d616e74612e6e6574776f726b00000e406d616e74616e6574776f726b000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714d30ea9c98411c92b82ec846c0a52b9c033f68406b9a83aa780305272c0cdb723aac4bcda7595b640": "0x04000000000200000000000000000000000000000000086269672d626167000014406269672d6261673a6d61747269782e6f726715692e66617a756c6c696e4079616e6465782e7275000000001338393038393431303039393835343133353300", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714d32859a272c0a2203614bc16c1df6ff786504c9b02854f49a59bf5379f5e23cfefad24e77cf00152": "0x00000000000000000000000000000000000f42696e616e63655f4b534d5f32340f42696e616e63655f4b534d5f3234000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714d344c21842905461f4561fb4cff90fcf5afefa2f170eabe539b19c1dd5d9d5df5dead7b26c98cf19": "0x00000000000000000000000000000000000000000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714d347ee113906d431bc8411a57314390768f469e76222ad677bfcddb342ad54dd76c3116593faea3a": "0x00000000000000000000000000000000000c4761627269656c566f6c7408457667656e69790000176469766f7261766f6c74393140676d61696c2e636f6d0000114038346c6870774277646e4753486833000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714d37aeb944733e681aa19053750bfb4dfacdab0e8ea94e0914fbb1b0aed9450755bc38df95f13f441": "0x00000000000000000000000000000000000b416e677279204269726400000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714d391d9d986f924c71875965235d98860a9695076ca95b03f5c532d79f0d0b8a53fa6247090fe1505": "0x00000000000000000000000000000000000b5261696e626f774e46540016646973636f72642e67672f416743557a443537377600157261696e626f776e667440676d61696c2e636f6d00000c407261696e626f776e6674000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714d3a269b657e1dfd090a4c78f16c247b4b438a25734d0479b32c196cacb25ecc95a79480dfc6cee7c": "0x04000000000200000000000000000000000000000000077368616d6230000013407368616d62303a6d61747269782e6f726713722e7261616a657940676d61696c2e636f6d00000940307368616d6230000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714d3b4bb9b7ce70c8d4e3711ff0fdcfc953c9ff93355ed42146e442c256b6010ddd5b5fe0ee8b8ac1c": "0x0800000000020100000002000000000000000000000000000000000f43727970746f537461636b696e6700001b4063727970746f737461636b696e673a6d61747269782e6f72672176616c696461746f724063727970746f737461636b696e672e6e6574776f726b000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714d3c431103710ce4ece8ab75ebb8a44502bc0a55f439d421f8d59372b5d9bba22e31b770e0317c236": "0x0000000000000000000000000000000000154f7263686964784d616368696e61202844414f2900126f7263686964786d616368696e612e696f0000000010406f7263686964786d616368696e61000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714d3d814d7f08cf77d28b199c10b2b388ce480499767f81d871cd1bc381f7106d810f69183ff0bb600": "0x0000000000000000000000000000000000097073796368656d79097073796368656d791568747470733a2f2f7073796368656d792e756b2f0011696e666f407073796368656d792e756b000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714d3ede878555e1dcebebf5aa73bf19935376f19460dacf00bf0dcd021ca37d6a2284cc6347dfbb13b": "0x04000000000200000000000000000000000000000000115354415244555354205354414b494e4700001d4073746172647573742d7374616b696e673a6d61747269782e6f726719696e666f4073746172647573747374616b696e672e636f6d0000114053746172647573745374616b696e67000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714d3f55d2a3bdb036484de146db749ad6f982921078e8dec36432724c2e58ee2523018794d66b4b33e": "0x00000000000000000000000000000000000f646f7473616d612067726565656700000017646f7473616d612e6772656740676d61696c2e636f6d00000d40637261696777696c6c3733000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714d4033833f41b67add80d0b0a6fe11c8257ab574e3379491172cf2e6398fdc12413ff1e8cb0dca602": "0x00000000000000000000000000000000000746524f444f4c1044414e49454c20564143554cc38d4b00001137766163613740676d61696c2e636f6d00000840377661636137000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714d414938ade2ffd6ad42bdf23d39282dc625dad8b2ffc0b8682b15b2fe16386a8b7d7670ef49c1034": "0x00000000000000000000000000000000000b64616e69656c74616e6700000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714d423ef3f47b52bf7c48a7d8c907eda4ec2ea41d9bc09584ef7bdf9771212672f0fc065a28eb5d809": "0x00000000000000000000000000000000000e50756e6b205661756c7420233400000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714d426b9c30d551db958a7854669ff1e281e737aae0f84d013eec326ab95a273c0c1632d009f02361b": "0x00000000000000000000000000000000001241646d6972616c204869726e77757273740000000000000f4061646d5f6869726e7775727374000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714d42a0215208f31fdb6ccd54659f4b9ffd747e6ba2dbebfd5d2a64ad3ab8dcf6b647965c20fde4b26": "0x000000000000000000000000000000000008416264204e46540e416264616c6c6168204661697a00001b616264616c6c616864657665736f756c40676d61696c2e636f6d000008404162644e4654000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714d4351e7307bc37c8d82318297ca7af51ac2546ea6bd24acca272e1627db952e2ca35df527a3cf257": "0x0401000000020000000000000000000000000000000007416e6e76616c00001340616e6e76616c3a6d61747269782e6f726714616d3539333137383640676d61696c2e636f6d000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714d435a9777e7ecc393c5862ed65c524b7bb3564776a81904218f44f3d7c35162a608e39dbadbcda05": "0x00000000000000000000000000000000000f4e6174506f6c6b6177616c6c6574134e6f7220536166696e617a20417a726169650000166e73612e70796e7574323840676d61696c2e636f6d00000b405379615f50794e6174000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714d452102e2cdc7c6d0615a0ee03c20ebb5fa2073580dbeb208997a4cfec6d0c45eb6aacae346e7341": "0x000000000000000000000000000000000010546865204b696c74204d61737465720000000000000f405468654b696c744d6173746572000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714d454f28df46217c3a413aba1432d6c746556ce43688ff333612f6abe674cd018143a0f819f9ae011": "0x000000000000000000000000000000000010556e646572646f6741636164656d790000000000000f40556e646572646f674163646d79000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714d4615d4a4674bc89b80441d3a9d744772eef9c1d6f9babafdc2cbd1b641134372accd4cba23b602a": "0x0400000000020000000000000000000000000000000019464353206b7573616d61207374617368206163636f756e741946696e6f6120436f6e73656e7375732053657276696365731668747470733a2f2f7777772e66696e6f612e696f2f001b636f6e7461637440636f6e73656e7375732e66696e6f612e696f00000a4046696e6f615f696f000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714d483e0981fcc955908f241657b6fafb70ad61e1d2ca48854400ac5499472047e2313837f22dbdb34": "0x00000000000000000000000000000000000559657469125969c49f697420c4b0c3a7696e6465726500001879696769746963696e6465726540676d61696c2e636f6d000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714d4860cb6eb01ff314c5586b7da01ac92974de944023354a80c57d22758be9e56ccc8fd3fce706556": "0x000000000000000000000000000000000005736562691253656261737469616e205265796e6172640000197461737465736c696b6570756e6b40676d61696c2e636f6d000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714d498e8af62b9b81f48cd9f664b904e5fa2943cb433f83c4747aa5503b65db20c3323ef45e3533c52": "0x040000000002000000000000000000000000000000000b4d6178426f6f6b50726f000017406d6178626f6f6b70726f3a6d61747269782e6f7267156d61786a6c7565646b6540676d61696c2e636f6d00000c404d6178426f6f6b50726f000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714d4bbaded83232e480a7ddf52460667c3f7adff6e3940814273085004a1ea440514c031b04273840d": "0x00000000000000000000000000000000000c427573696e6573736d616e00000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714d4c23f7b6dead31a72f6d064648a26d887389b6693722008d4caf3806559b92fb1ee8dfa0a45d033": "0x00000000000000000000000000000000001c63796265726f6d616e6f76202f2f2f20686f775f746f5f6e6f6465001968747470733a2f2f742e6d652f686f775f746f5f6e6f64650000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714d4ed4dd340a2cebbbc486ed2f394da6e6b58b130687b48d3d19f756ba6d0655d37bf58ff0f59f974": "0x04010000000200000000000000000000000000000000124164616d5f436c61795f53746565626572124164616d20436c6179205374656562657200154061737465656265723a6d61747269782e6f7267176164616d2e7374656562657240676d61696c2e636f6d00000e406164616d7374656562657231000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714d4efb6a7c466273b168cf2d861c66db1a3fbaf0ecf25df661c7d55787615a390763518e98de0b747": "0x00000000000000000000000000000000000e426565667920426f76696e65730000000000000e404265656679426f76696e6573000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714d4f3cca21e8eadd0dc3b9a6dced09d3d392ba7a559c5505304cb3bec0168909d1ef3ddea59bc3f40": "0x000000000000000000000000000000000008436173744f6f62064b656d6574010940436173744f6f620100000940436173744f6f62000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714d509c5c59195b1ec5c3739d60301126756a7510e34f9d656d4435cd4fe64bbd001f1f3473bc9c333": "0x04000000000200000000000000000000000000000000055a656b65000012407a6d6f73743a6d61747269782e6f7267137a2e6d6f73746f7640676d61696c2e636f6d00000c405a656b654d6f73746f76000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714d513a4d26b535221784eec0cca663bb2db534e9f62df416453ba125d1b7164fbd0e57cd3e8e97b16": "0x00000000000000000000000000000000000000000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714d53d5d90d84924fe4677245c32c396fb92974ba9bf94b8fd84a6ac489a98bbde7c24ac48b1105160": "0x040000000002000000000000000000000000000000000b5374616b656177656562000017407374616b6561776565623a6d61747269782e6f7267157374616b65617765656240676d61696c2e636f6d00000c407374616b656177656562000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714d55375322bd7510232888663bc260532b200b41cc9ef2fc128b68e8d533e3a7a948f9ac39f50ee0e": "0x0000000000000000000000000000000000104c6f776b6579204c75636369616e6f194e69636f6cc3a173204c756369616e6f20546172676973650f7777772e636176697065782e6d781b406c6f776b65796c75636369616e6f3a6d61747269782e6f7267196e69636f6c75636369616e6f323540676d61696c2e636f6d000010404c6f776b65794c75636369616e6f000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714d5591ec3b4ca405c90dae70c96bd25cc1a05708607846a56409ac0f5583da69993dbe51e9c745e71": "0x000000000000000000000000000000000006526f73696500000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714d55aed6a285552b8eea608b429d85b4dc655283ea9eab1228082aef03aeac6cdae6f54490cd08d1e": "0x00000000000000000000000000000000000e486f6e6579636f6d6220322e3000001b4064726970736c6f776d6f74696f6e3a6d61747269782e6f72671e64726970736c6f776d6f74696f6e4070726f746f6e6d61696c2e636f6d000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714d574ca61fe1791bf8286f065125f13ef660e4862d9c37ba16bf863ebb5190027c011da51d818d020": "0x00000000000000000000000000000000000a4c61204261737572611d74726173682067617262616765206e6f6e73656e7365207472697065000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714d577f5c3d9252401dcda723fe1d35644330dd76fb23e8a054ea173de8662658abd8c01b92215496c": "0x00000000000000000000000000000000000c43727970746f70617468200f4865726d616e6e2054726f67657213436861696e6578706c61696e65642e636f6d0011667269736972406b75666e65742e61740000104074726f6765725f6865726d616e6e000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714d58baa61c0bbca6b0294d53df32ffcce69720bff43ef091c4bb98746625ccd872c83020b6e60b92b": "0x0000000000000000000000000000000000094b534d5f6b696e67094b534d5f6b696e67000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714d5a0db274f5df4e104d8d6a7936466d0f9d111e89f97ba11695c0525bb136b68d9924299df236638": "0x04010000000100f0373a0002000000000000000000000000000000000000000000000000000011506f6c6b61646f74204dc3a97869636f11506f6c6b61646f74204dc3a97869636f0000187465616d40706f6c6b61646f746d657869636f2e636f6d00001140506f6c6b61646f744d657869636f5f000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714d5b36f8aabe01a6052dac5497bbdd42583d07aa46102790d54aacdcbfac8877189e3b609117a2915": "0x040000000002000000000000000000000000000000000453656200001b4073656261737469616e3a776562332e666f756e646174696f6e1a73656261737469616e40776562332e666f756e646174696f6e000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714d5ce1fd9020fbeba60b791f8467410a5ce2e880cc222933ad50705664917bc9d190a52596b987121": "0x040000000002000000000000000000000000000000001146494c494752414e2d5354414b494e4700001a40746f6d61732e7374616b696e673a6d61747269782e6f72671e746f6d61732e616e646572736f6e2e3230303440676d61696c2e636f6d000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714d5dc001e58cc1a2dc0e9999cf8e2137f6aa333a591dd91aae131fc563931ab47986d637283c7ed29": "0x00000000000000000000000000000000000f566976656b2773204b7573616d6100000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714d5e66d23eb784c1150fa056fe8636d5041e3a460e63839603087bf789ce60514f00bb2473b728e4b": "0x000000000000000000000000000000000014506f6c6b61646f74202d2050432047616d65720000001973657267696f2e6f746176696f4069636c6f75642e636f6d00000f4061706f6c6c6f74686562756c6c000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714d609065d758b7e8b9c8427ec1489648401391189a706384709fb9e657de816f41564e5b2cc9dcd3d": "0x000000000000000000000000000000000021536565722050726f6772616d204e4654204172746973742053686f776361736501010101000001000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714d60ed63674d67c971018f7a7cfcea5146f42a9f7514fd5873e7c0d523e8a244bc0662bd1d98e7a59": "0x0000000000000000000000000000000000096d666572686f646c096d666572686f646c00000000000a406d666572686f646c000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714d618b703260a53b98a5c48370385dbc1ceaddee2196bd1ea5e5617d5d6b8149a17d6dd4adaad8667": "0x000000000000000000000000000000000009666172756b30353813c3b66d657220666172756b206172736c616e00001a666172756b6172736c616e353840686f746d61696c2e636f6d000010406f666172756b6172736c616e3538000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714d6397f35e3bd3d7aa4da8ad5b663d506866eb429c70a606e73d6b78aaf04279691ae408213e6e206": "0x00000000000000000000000000000000000774736f6d697300000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714d65a76a86282a40a861cb62f476c70b7b610b759887b412fe5ccaf41056e76cb9702b6683309e329": "0x000000000000000000000000000000000008547269756d706800000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714d6672f8dabe56cfafc605754e335954ecf919857633f415d774d4d12712e213cceca16852f12d34d": "0x00000000000000000000000000000000000000000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714d6924a2febf0176cec55dae9d39f6758a5c07537eb7c64be8bb7417347bff0473ada40639784e33e": "0x040100000002000000000000000000000000000000001053756e7368696e654175746f732d5300001f4073756e7368696e656175746f736e6f6465733a6d61747269782e6f72671c73756e7368696e656175746f73696e666f40676d61696c2e636f6d0000114053756e7368696e655f4175746f735f000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714d696aaec0094a128f47313bfedaddff9c793fb87f947bc9444658705a5a1060cc6314f5a1986a90c": "0x00000000000000000000000000000000000a4b61636b766f67656c00000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714d69a25a402c5611e0c803a3771c8a186638032d9b7a49c853dd6277eaf7a2360dce82c0ec79a5755": "0x0000000000000000000000000000000000064e6f6a61580017687474703a2f2f6e6f6a61782e74696c64612e77732f00156e6f6a6178737765657440676d61696c2e636f6d000008406e6f6a615f78000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714d6cf502341600d556c519d42e162875d1d3c3c77e651f508aa6b0acb837c742d2708946f5927af2c": "0x0000000000000000000000000000000000085a45524f2e494f001068747470733a2f2f7a65726f2e696f000b6871407a65726f2e696f00000b407a65726f646f74696f000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714d6e8d01b506d9006a41e9f37a05aaac44e5eb8370e4bbffc6e80041574668571e5eaef0483ff7b09": "0x040000000002000000000000000000000000000000000b42617274616c616d65770000174062617274616c616d65773a6d61747269782e6f726700000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714d6f4a0256fc9f716e0edb40f22c7d63c19a54e07562c062b1eb09447d51f5cf6ab734ada60793a44": "0x00000000000000000000000000000000000000000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714d6fb5b84c25006bdc63c43b6438923bccf2d45e4c2f40cdd0487f6fa2642850b7a01df18dd27825f": "0x000000000000000000000000000000000004706f79024100000000000b40706f797369616e3033000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714d70a505217b108b4ac17e441d94f220689361662feeadf1c5c14876375a72a392dd67f276e538706": "0x0000000000000000000000000000000000086269676d66657201010101000001000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714d722c1e7fc34a853ec007f25ffe88b5e993645de184a0c7c32050eb68b8f47f05e9fa06844ac0f40": "0x0000000000000000000000000000000000174665656c20746865204c69666520596f75204c697665001e68747470733a2f2f74686174676f6f646f6c6665656c696e2e636f6d2f001b74686174676f6f646f6c6665656c696e40676d61696c2e636f6d0000114054686174476f6f646f6c4665656c6e000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714d73fd3a82863eee47ee233c6f97eaf8689fe85222c2e2b701c2e654d4c8dacb45fcc574f6f438e26": "0x0000000000000000000000000000000000095368726f6f6d697a01117777772e7368726f6f6d697a2e636f6d01127368726f6f6d697a6e667440706d2e6d6500000d407368726f6f6d697a6e6674000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714d7553e6d8d0f99e5f66b0ab84c0ad724138f81ce24ed1fa17897d6e75a6356c4115cf44d09e19e48": "0x00000000000000000000000000000000000776766172646906566164696d1b68747470733a2f2f7777772e67726963656e6b6f762e636f6d2f0016766164696d6b61746f323540676d61696c2e636f6d0000094076766172726469000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714d7685dfbd65585fb86bdd82d59404ffe1d6120c6358c14c1bef69a013fa91771c2594f6fa310187e": "0x04000000000100902f50090000000000000000000000000000000000000000000000000000000761726b7061721141726b61646979205061726f6e79616e1a68747470733a2f2f6769746875622e636f6d2f61726b7061720000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714d78969895bcedfdf5a3a1533b0a9025b41803b18e26fdbc2d218a87b27b1c31a1fae6d8098b3e457": "0x00000000000000000000000000000000000a72616a61746e616e6f00000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714d78ad17ef6e9b32a3c1defc518e6b625f5a9efd940404a1672285b33a1dcbb88b50209b76b79a74c": "0x0000000000000000000000000000000000065069616e6f01010101000001000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714d78b6631bad4877c52d49f4667f10ded3c5d8ada0c31d7f397ae650a30cd8ad7663b8f3bd7bfc355": "0x00000000000000000000000000000000000000000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714d78c16b89566f655563544356fb79169a553ad9bd500e2cc88159f56ece7c1fb8015872c68b0e522": "0x000000000000000000000000000000000011536572686969204d697368757374696e00000011666e6174756b40676d61696c2e636f6d00000840666e6174756b000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714d7a964305986fe6726b41bc4436bb3f47662366696bd1233bde29446c80949e3b92a435146462436": "0x00000000000000000000000000000000000a4b756d6163636869200000000000000e404b756d61636368695f617274000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714d7ae9fa2edfac512d4da8f91c6a4e472fbebceb3a995c6b3e6de9c452f9d72b57a56b28be0f0b323": "0x000000000000000000000000000000000006486f72736100000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714d7b596e66afccd2bd89ea70e822e338b7519379e4a4685595da674fd167b7bd12dbfd10c9bc2b50e": "0x00000000000000000000000000000000000d44415245444556494c337837000000134372797970746f7040676d61696c2e636f6d00000e4064617265646576696c337837000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714d7dd8684dd09ce27e8799eea1483bb11f30100b2a239f6fbb5098c5723dcd0d6bb4987abcf443642": "0x00000000000000000000000000000000000550756e6b00000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714d7e6c03d3b7013c492818e6a3df21899a1f1f3f2d3573e4c978bc23c05317715e288434396eeb155": "0x000000000000000000000000000000000006656452756d0365642168747470733a2f2f7777772e696e7374616772616d2e636f6d2f65643872756d001165643872756d40676d61696c2e636f6d0000084065643872756d000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714d7ef9a5ad88206463e968701c6259a89d5d0f6c7fba46ad0694cc8c66f4b21d4e174744376039402": "0x0000000000000000000000000000000000107472616e747579656e626e30333034107472616e747579656e626e3033303401010100000c40676f6f676c6562657374000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714d7efccf788fb1a6528d50241999da5b300f01f3004a67a25a11854608f1f437ab86ed2e115243a43": "0x00000000000000000000000000000000000a4b7261746973746f7300196b72617469737430732e756e6976657273616c2e7061676500184b72617469737430736e66747340676d61696c2e636f6d00000b406b7261746973743073000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714d807711226d31b907054f0231a7bb2c4d8e1b64b4b2a77e7216e5d225552d00235201b1889dc0e5d": "0x00000000000000000000000000000000000f62696e616e63655f6b736d5f34310f62696e616e63655f6b736d5f3431000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714d809a68f462b1287c285c81a263217572329f43c38dcee6f67b0cd9f25bae69e895080f546f6ba31": "0x0000000000000000000000000000000000076a6178646f7400000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714d8120c83cf91181312e6a9ab0eee280b366c26e0d43e7826406e7c9c2058ba0f8f31efede72c8653": "0x00000000000000000000000000000000000c626f6f6b77617272696f721f5468652043726561746f72206f66204c6962726172792047656e657369731368747470733a2f2f6c696267656e2e66756e0000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714d82897aac9ed9c653a68259c764c7a1aca790853256861dfb65ea084c82d10d40f8eb1dffe45e77b": "0x00000000000000000000000000000000000c7375706572737072697465000000187a6d616b696e616f6b73616e6140676d61696c2e636f6d00000f4073757065727370726974653134000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714d84deb4759f2e2e9f6a7fa830da55dde09b411ff877ed0ee8fd1ceb2009067ab5bc0ffdc54af4065": "0x0400000000020000000000000000000000000000000006416e6b616e00001140616e6b616e3a7061726974792e696f10616e6b616e407061726974792e696f000008405f616e6b346e000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714d851abfc5265e96b5015c74ff78d632ca10ecfc0d0fa9fa2009cb4e644d73f6518260f5cb9c34633": "0x00000000000000000000000000000000000947723379686f6f64010b343434657665722e6361010100000d40626c617369616e77616c6b000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714d86d654f0eadeda8ee73cfdef6c4ba205b9b7afadb214de4510b3fdd98d5b7284e09b350e277cf2c": "0x00000000000000000000000000000000000b6672616e6b7977696c6400000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714d87333d9765befa4e643e4515fa656d6d830c088ec251ab76ba6cebd85be7e7d6362eafff654e222": "0x040000000002000000000000000000000000000000000e534f4e59412d5354414b494e4700001840706572656368656e6b6f733a6d61747269782e6f726716706572656368656e6b6f7340676d61696c2e636f6d000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714d87f50ab0b5f9643ec5909db1fe8581fbe80eaf39b4577c12a99d5abc87131bc3d4363f623412f42": "0x04000000000200000000000000000000000000000000097363686d6961747a000000167363686d69747a4064632d7363686d69747a2e6465000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714d88c6fec2fd9c900b8687aa6d3e0c8659930f6d8f8066260b6633445304d2a3e657a6edc2e42a849": "0x0000000000000000000000000000000000055468656f00157777772e7468656f6a616d696c6c65722e636f6d000000000e407468656f6a616d696c6c6572000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714d894f8bb10a8b63f0a06fa6798320860c09dd8b4880aef12921f0d1c03b90d5426aa94a8192ada3f": "0x040000000002000000000000000000000000000000000b4b616f7320496e204241000000166a6f736562656c6f73736940676d61696c2e636f6d00000e40706570656172617563616e6f000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714d8a98d8378f930af20836789ec1d218962edb199c7d65158e0edbe4e5ce0db190f6993b64d4aec42": "0x000000000000000000000000000000000006494f594f49011e68747470733a2f2f74727973686f7774696d652e636f6d2f494f594f49010100000c40696f796f69696f616f69000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714d8aa498f3b53b82dc203ae26c4e67f3dfd9c338f9f5f605abe950945d6077c23db6345041818e73b": "0x000000000000000000000000000000000009417572656c697573104d617263757320417572656c69757300001c417572656c6975735f4e46544070726f746f6e6d61696c2e636f6d00000e40417572656c6975735f4e4654000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714d8c344e11655410c54fda5a0e241e5497283afebd81b53f6a0235abf62a9bd39594be3f42d291e7f": "0x0400000000020000000000000000000000000000000008537461747574650000001b73746174757465636f72704070726f746f6e6d61696c2e636f6d000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714d8cb784790741db174dcae90cfd7a3fc9a75e4cc21bd550113b44888ffbf67741c8081c6d121d306": "0x0000000000000000000000000000000000094d69746368336c6c0000000000000d406d69746368336c6c5f5f5f000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714d8cc1e377a948511bed8e57427b9ba0d58dfeec1e37715621b7216c6953afbfdcfe181c2f6a2ca6e": "0x0000000000000000000000000000000000094372616967657273001a687474703a2f2f6c696e6b74722e65652f6372616967657273001863727970746f6172746e66747340676d61696c2e636f6d000010404372616967536d69746841727431000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714d8cf92a45f6a096b5401c2b936283c6674f9f30be30276a706373c0bd7b7a8dd511e1ceaf4ce1932": "0x00000000000000000000000000000000000c6b7573616d615f6b65726d0dd09ad0b5d180d0bcd0b8d18201010100000d406b7573616d615f6b65726d000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714d8fccba6b760676a5a98b9e09c1d2e5a120a1be952593d0d542ceb6f6843133f6d64c674b736ae55": "0x00000000000000000000000000000000000c4b7573616d61736872656500000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714d906663357299afc882e4951811038cfeb6e891c2c574e88d2d950aaf23d6cea7b030e17ab9c6569": "0x04000000000200000000000000000000000000000000094c6974656e747279194c6974656e74727920466f756e646174696f6e204c74642e1a68747470733a2f2f7777772e6c6974656e7472792e636f6d2f164068656177656e3131303a6d61747269782e6f726712696e666f406c6974656e7472792e636f6d00000a406c6974656e747279000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714d942aa586baec2e388c16bc644b9877b22f0fc11c18bf143398267feb48c3ac9cc110440e9a5d873": "0x00000000000000000000000000000000000953657661546f7267074d616b73696d010101000001000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714d946b6c106a956cc7cfa423244c9a3bf66c12432dd93d3806d184e01b58e3eb75b4b19b26bf61a75": "0x00000000000000000000000000000000000000000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714d94bcf5481a16dedec03e526f073255828e91779339158fc05b68430ebf66df109820b79c1da4053": "0x00000000000000000000000000000000001d5370656e63657220486172726973207c20426173696e204c6f6769780f5370656e63657220486172726973001540746967657274776f3a6d61747269782e6f7267197370656e636572626840626173696e6c6f6769782e636f6d000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714d954df8fd662305d365572e4f9d2762cc1c4312399485b3b3bbfe113fe2b5a12a73f9ffb5b9e694b": "0x0000000000000000000000000000000000066d696c6f7300000000000011404d696c6f73436f7374616e74696e69000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714d97b21772959b4b83870abfd18505f673c1808b61dd0d7067a810a9719c2ddee18f9b879752f4c50": "0x040000000002000000000000000000000000000000000a53746173526f766572000016406b61346f6b313333313a6d61747269782e6f72671873746173726f7665723133333140676d61696c2e636f6d000000001373746173726f76657231333331233632363300", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714d994ff06d05e1d5898989f74514aeaf57d4f41069770242a83d619c9ae5d46cc05b85136edd53776": "0x0400000000020000000000000000000000000000000010426c6f636b636861696e2053696465000000196172636869656772616e6437373740676d61696c2e636f6d000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714d9984fac3c81ec12248ba6a719705efdd003caab9383ce61c9bba7e7bd914a96be918a4ab12d7251": "0x0000000000000000000000000000000000087479726f6e657a00000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714d9aa60f59932d95d362c1f2bbb4871a52be7e6f8354082c4d83f54fd249689fc820be7e5c672cc69": "0x040100000002000000000000000000000000000000000943484c4c2e4f4e450d4b726973746572204178656c1568747470733a2f2f7777772e63686c6c2e6f6e6517406368696c6c66696c74723a6d61747269782e6f726714696e666f406368696c6c66696c74722e636f6d00000c406368696c6c66696c7472000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714d9aacd1a800a357c2822e6207970510d1c0d65af57522c8832c810f86d512a09f960efd78f570110": "0x00000000000000000000000000000000000a506f6c6b61546f747301010101000001000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714d9c21406bc86d487b46a62619c41606297ea55f07d4c2ff4e3abec149e1f9fe241cf6ea0b12c7a15": "0x04010000000100fc8d0e8000000000000000000000000000000000000000000000000000000018475245474f52592054484520494c4c554d494e41544f52064c554d2d411668747470733a2f2f7777772e6c756d2d612e636f6d1540677265676f72795f3a6d61747269782e6f72670f696e666f406c756d2d612e636f6d00001040464c41545f455f415f525f545f48000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714d9ce7cfdde49af449a9495310a1c0626605d804f4fff2446ca5a6dad3d2372ded3b1a049ee71df6d": "0x00000000000000000000000000000000000b546865204c2046756e64000000000000104054686547616c6c65727931313131000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714d9d39ccedf4c2000b463dd5343005043ca12d524c7dd5d64ca6dfc3ad830665130a214da689d5078": "0x040000000002000000000000000000000000000000000b4d616462757374617a7a0000000e616c696461646140626b2e7275000011406976616e736d69726e6f7670697273000d2e6976616e736d69726e6f7600", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714d9e7b18acf37afc5109ac2869eb1def6cc0654c320d9aeda6a800ae69b1d90efe0ad42850616e614": "0x000000000000000000000000000000000009536c6f77726973650000000000000a40736c6f775f646f74000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714d9f5cf21929f1a4c4acd55e7e637540708f860361c1ec0c092cf8169b300d9a4bdeb58faa8a52053": "0x0000000000000000000000000000000000184269726473206f66204368616f73206f6666696369616c1d4e6f7420616666696c69617465642077697468204368616f7344414f00000000000d406368616f735f6269726473000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714d9f5e42a995ae306029b3f206024f24646fac96836b670bb999eac5b44eda65ab262ccc0a4a6b542": "0x00000000000000000000000000000000000962656d74696b7275000000000000104062656d74696b72755f6d69746368000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714da1658728cb5fb3c82299cce0c148ac684639df678476effcae36c4eb8cf15592c511512a857e745": "0x040000000002000000000000000000000000000000000d44696f6e79737573f09f8d87001a68747470733a2f2f64696f6e797375732e6e6574776f726b2f1f4064696f6e797375732e76616c696461746f723a6d61747269782e6f72671468694064696f6e797375732e6e6574776f726b00000f4044696f6e7973757356616c6964000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714da1bc1fea1f074aac68a07f4359b73788575a33635beb03280ef3c52062d5bd01f825e2f463e0b4c": "0x00000000000000000000000000000000000e41786f4b656c2053747564696f001e687474703a2f2f61786f6b656c73747564696f2e74696c64612e77732f001761786f6b656c73747564696f40676d61696c2e636f6d00000f4061786f6b656c5f73747564696f000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714da23f4f6f4d9e6bc96140a201be6f41e63c5b3bf6b02f67da3f232c6715397302494f894f964ac78": "0x040500000002000000000000000000000000000000001156696e6365436f72736963615f4b534d1856696e63656e74204469204769616d626174746973746100001076696e6365407061726974792e696f0000114056696e63656e7444694769616d6231000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714da40d28d53abbfcf16f9415c34da11ca5a35f3f18627af4ef312d90777ed086ea20e364b11656921": "0x00000000000000000000000000000000000647454e47450667656e676500124067656e67653a6d61747269782e6f72671667656e67656b7573616d6140676d61696c2e636f6d00000d4067656e67656b7573616d61000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714da4eb90d88caf07f5c2341c52e242c57f00d78b9f40cb486714dee3e10bcaefba283e1e4df0e5f75": "0x00000000000000000000000000000000000f4465736b746f702d4b7573616d6100000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714da569c826c2fd86b76739ac0320c03658b64366855bd6ab037488fb23fa0d183f53b989106e25a2d": "0x00000000000000000000000000000000000b4441524b464f5245535400000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714da7ade542996fb4cb6631de2987e1fa759f6aef3e72550a528749c4c52cf38710602bfbac9af7305": "0x0000000000000000000000000000000000064d2d455343174d696775656c20416e67656c20457363616d696c6c6100001773657669796f6e31303740686f746d61696c2e636f6d00000e4044657361726f6c6c61646f72000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714da9b32cffd9fd809beef167bab8457606e5de5733ed8762eb7d0aea76041e7cdc691a21b95e67013": "0x00000000000000000000000000000000000654696e6e6905524d524b00000000000f4054696e6e693839313936333138000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714daa1ed579e87685ab8f0171b9d40e58e80585aa9997bab2ae23d35557b5442824ad73deba484e36d": "0x000000000000000000000000000000000009597567656e65383900000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714dac410871d142aa90a53d0ced11a23bb33da1a2fa77b236ad1de8272b61bef478771f5bdd344fc06": "0x00000000000000000000000000000000000e43797068657220526561646572000000186379706865722e72656164657240676d61696c2e636f6d00000f406379706865725f726561646572000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714dae3f8d26516ccd80224ef86df87db7c4c36488f6f2c49f554c73fcf4a1572b0b1dcd79155784740": "0x00000000000000000000000000000000000e456c656e655f5473756b696b6f002168747470733a2f2f7777772e696e7374616772616d2e636f6d2f456c656e655f000000000b405473756b696b6f456c000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714daef22360126f077784ee8a444a606185328b11e83357bfa6541dde1e05b95e69879b1b716f7a247": "0x0000000000000000000000000000000000095375626461696c79001468747470733a2f2f7375626461696c792e696f000000000d407375626461696c795f696f000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714daf69a211b7a8ea508a23d4b915d29be5d2aa20f36649e004c6ee8df393064edad697934281bd51f": "0x040000000002000000000000000000000000000000000a6c75636173796f6461000016406c75636173796f64613a6d61747269782e6f726700000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714dafe1c73fef256963e7af6741991062099fd8cf649f36396d77271db62ee03370c1e53ff12cb2642": "0x0400000000020000000000000000000000000000000005454b415400001440655f6b5f615f743a6d61747269782e6f7267146b7573616d612d65314070726f746f6e2e6d65000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714db13904a8fd920d916f2af47aa45d69386e441ad73b7ec1ba5065bdd787f7ab7b2d8eb428c5b6967": "0x00000000000000000000000000000000000000000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714db2524c5144787d7780dfaafebd37476b57e181c3636209591f2df438004ae02ef2d759092832870": "0x0000000000000000000000000000000000094561727468415254115061766c6f20504f5a485944414945560000137061756c646a656440676d61696c2e636f6d000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714db2d56e31fe5a23ba827364a1e01162f7f1647ff0fc967a83f1ef1d8c8da59414d312de7514c1678": "0x04040000000100902f50090000000000000000000000000000000000000000000000000000000965746853706c69740000000000000a406e7468657269616e000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714db3176a845829b906e0417d9e62b75535a2c606b13a74bdde967684d6971d58cd0cad8986e3b3044": "0x0000000000000000000000000000000000075374616b6558001668747470733a2f2f7777772e7374616b65782e6368000f696e666f407374616b65782e6368000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714db4738c957436cf21e9c00f9c0788391f63681ed1addd7984e37aa04a96cb887beac70eda9b4766d": "0x00000000000000000000000000000000000c43727970746f44616464790000000000000d4043727970746f4461446431000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714db51125ce2e8c4560c2017a4f115c013d899b494c955a7ec4cc9786a3997f1823baacc213896a35a": "0x000000000000000000000000000000000011506172616c6c656c2046696e616e6365000c706172616c6c656c2e6669000000001f68747470733a2f2f747769747465722e636f6d2f506172616c6c656c4669000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714db564ac3abd62540844152eccf08725bea8ce898d6fc5362ff2d0bc9dfc21ed15fd138438d160622": "0x08000000000100902f50090000000000000000000000010000000200000000000000000000000000000000164b7573616d61204865746176616c69646174696f6e002068747470733a2f2f7777772e6865746176616c69646174696f6e2e636f6d2f1540686574616972696f3a6d61747269782e6f72671a4865746169726f6931384070726f746f6e6d61696c2e636f6d00000b404865746169726f6934000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714db70f2601c34332880a135db57d4d35273d9a4f661d3dad8f153a1b5bad478f9b0e5223657aabc0b": "0x040000000002000000000000000000000000000000000d574f4c465f5354414b494e470000184070657465726b6576696e733a6d61747269782e6f72671b70657465726b6576696e732e3139393940676d61696c2e636f6d000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714db89725fce7ce8f3bc61b0519cbf119fe5dd6b22fdab9032f2af003c27b432e081cca41eb8621c3c": "0x0000000000000000000000000000000000154e4654204162737472616374205061696e74657201010101000001000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714dbc1bb2de0590492cca2a0719fad006090aad6536ca8b7d8c527589be01b0012564dbdd36d9a4923": "0x04000000000200000000000000000000000000000000066c6f626973000012406c6f6269733a6d61747269782e6f72670e6c756973406f6269732e646576000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714dbcec1429555e3577a5c2500b0c12120ca4683d8b1046a98d324b1cc45461c2bf69ee7e2f4708207": "0x00000000000000000000000000000000000b6a6f736870656c6b6579000f6a6f736870656c6b65792e636f6d000000000c406a6f736870656c6b6579000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714dbf0bac829c264486eea07ae188cf16042168843c5c29299196e610dfda7d9efd3f0421119629a61": "0x00000000000000000000000000000000000d56616c6565765f52696e61740d56616c6565762052696e61740000127672722e69646f40676d61696c2e636f6d00000e4052696e617456616c65657637000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714dc22c730a7ef5a54488b87e574eee2f9b8e7810eb3567edffc303c4f9c76946da200ce429b444d59": "0x040000000002000000000000000000000000000000000a4d617843726970746f000000166d617863726970746f6f6b40676d61696c2e636f6d00000c406d61785f63726970746f000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714dc5cbe2cf41cf8f57a66844d9bd974ceeab7c9da2b3870bf98bb2179a0d385d644c5f73593aa7f16": "0x00000000000000000000000000000000001b5a57485f46616d696c795f54727573746c6573735f5472757374000000157a61636b77696c64654069636c6f75642e636f6d00000d407a61636b68616e6466616d000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714dc6abb1030271996440465c2ff462a9545455781afd16c1d7f650935bbb34f696ebe205c14baa307": "0x00000000000000000000000000000000000c417373657420546f6b656e0e4b727970746f204c6174696e61127777772e6173736574746f6b656e2e696f0013696e666f406173736574746f6b656e2e696f00000c406173736574746f6b656e000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714dc70be881faf5789f2de250cbcc6a3881f004a862ae661a9794596c3ebdeb829a131989617f49e76": "0x00000000000000000000000000000000000f4973616163204368616f7344414f00000014616d656e6c6f39406f75746c6f6f6b2e636f6d000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714dc78925c32b0b66c0aba8ac93a0d8898810acf42a8b311fa20407dc181383901c240b041b34bf015": "0x000000000000000000000000000000000011506f6c6b61646f7442616c65617265730000001b706f6c6b61646f7462616c656172657340676d61696c2e636f6d000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714dc795a6b3289958b5678de8caf6f90c813fe5addb356e8154ea5e52463886d566cc8deaa0907e761": "0x00000000000000000000000000000000001543616f74696320506978656c2053747564696f73124a756e65204361726c204d616c61706974147777772e63616f746963706978656c2e636f6d0018636f6e746163744063616f746963706978656c2e636f6d00000d4043616f746963506978656c000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714dc90c8e009d95f3e24d573f4df9151235e457956765e6446cf33077033bbca48d8d5c6c9a1d7fd33": "0x000000000000000000000000000000000010524d524b20312e30204d696e746572011168747470733a2f2f726d726b2e6170700111636f6e7461637440726d726b2e61707000000940726d726b617070000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714dc97a320776a16d2f495309d22f770f6e7335dce5ba63efbe4cf7b429a83f4b7761f1c7f45a8d86a": "0x000000000000000000000000000000000009416c20446967697409416c20446967697400000000000a40416c5f44696a6974000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714dcacdfdedda85ff952e73898bf4601f9c9a7fa052de0cc313b159dd368d458f4cb0341eedcd6d818": "0x040100000002000000000000000000000000000000000f436f696e6261736520436c6f75640e436f696e6261736520496e632e1f68747470733a2f2f7777772e636f696e626173652e636f6d2f636c6f7564001b636c6f75642d737570706f727440636f696e626173652e636f6d00000f40436f696e62617365436c6f7564000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714dcbb9839570e5bf3e6587e304800d0184b470738807816bc1eb4b2a045521c2cb60bb15952866236": "0x0401000000020000000000000000000000000000000005566956690000001c766976697472616e313131314070726f746f6e6d61696c2e636f6d00000e40766976697472616e31313131000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714dcd3c1c3ae6b80e00c082ad8b544e64abc3af5764db1b455bf32231202ba50e5d0fad1794df7c905": "0x0000000000000000000000000000000000074b534d20453200000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714dcd8cda22151133450ac31b94e7738d9d7a0cf56f4333a3344218e1ae2dd80a6e0b676fee8049305": "0x00000000000000000000000000000000000000000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714dcdc014dbdae7ca15446b847834ce2b1208193849f7e824c3796b03fc99bd11222a01047e4e33823": "0x0000000000000000000000000000000000075441524f3039105048414e2051554f432043554f4e4700001871756f6363756f6e673039383440676d61696c2e636f6d00000f4071756f6363756f6e6730393834000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714dd1a53046ed0d2c60ec568f29d8aa8acbe44da52d65d455d583494cfc2f0f5ce14e463f0b9e5a559": "0x00000000000000000000000000000000000000000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714dd1ffac41df06f48cc41c23d8c527a9a9899831a5500fd27c799b5cd404f1757fcc7506e4a86cb6d": "0x040100000002000000000000000000000000000000000f6d617474656f6361736f6e61746f104d617474656f204361736f6e61746f1a68747470733a2f2f6769746875622e636f6d2f30784361736f1b406d617474656f6361736f6e61746f3a6d61747269782e6f72671e6d617474656f6361736f6e61746f4070726f746f6e6d61696c2e636f6d0000084030784361736f000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714dd3470a836ea9a4008c15279d0e5f0a7dd1171cbc78cbdf7fa5899b48955e7cfe05629cff078b40a": "0x000000000000000000000000000000000006446f6e416e01010101000001000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714dd3ebffa43946729c8c5e44031d85024e4bce12bfa0652da14d359159b1a8727acaf716a6b677e62": "0x0000000000000000000000000000000000084d656e646f7a610000000000001140496e666c75656e6333537068657265000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714dd5ac43b991d5bfdf68fd95ffc9cc02f15e28ce9df041da32f3b564e249fb4a8caa1c5135b1fad4d": "0x040000000002000000000000000000000000000000000549676779001e6c696e6b6564696e2e636f6d2f696e2f69676e6173692d616c6265726f001869676e6173692e616c6265726f40676d61696c2e636f6d000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714dd87ceda2aeb7b22302ee7cf59c56eaea2db6946c671da40489f9259e33eaffc7cd2cacec048a915": "0x0000000000000000000000000000000000096b6163637570313200000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714dd96490c9cce24c2deeba6321bbb28a052a289d857b882b77b9bb36b3f5d8f6b9d6bab2a8e173b38": "0x0000000000000000000000000000000000084f646f7672656e00000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714dda1f8e340e37b261c39ef78e57f239200072aa865312f87edfcb4d4133c6ccc0a7e33f5c799e201": "0x040000000002000000000000000000000000000000000c546974616e204e6f64657300001740746974616e6e6f6465733a6d61747269782e6f726714696e666f40746974616e6e6f6465732e6e6574000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714ddd3fac950db81638ae535ed048c6144428c430959118e0a34ff1150662b13143fcd1dc9a31a4773": "0x000000000000000000000000000000000005414d313600000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714ddebe5e9c243fb0a8cd03b329ea85dc19992ffdee21b7fb481915cf496571a4c3d6ef6a998077e42": "0x00000000000000000000000000000000000000000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714de0cc3ec4dab1c451e9b8842daafe40d555921fb6b47e66eb9907b10587a20add8f3676451b2e913": "0x00000000000000000000000000000000000a42756c6261436f696e000000196c7569736d61797374657231323340676d61696c2e636f6d00000e4042756c626173617572696f37000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714de10278d56e138a554624f504797213920029ad9a9e11f06218c5f20ca160d66fda311650ce84e2e": "0x0000000000000000000000000000000000074e6574686e79074e6574686e79000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714de11e082d85cbef160f94710848d9dce161724f257a240494c901728bdf2fa51c138fc5580ee3134": "0x00000000000000000000000000000000000e4e69776167616261204a6f61620e4e69776167616261204a6f616200001b6e697761676162616a6f61623130303040676d61696c2e636f6d00000f404e697761676162614a6f616232000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714de14b81ebe1d9b57fe4f532d7c92cf5241deddb7cc69437c1e14dd7a485a66e558b6e1277c130f32": "0x04010000000200000000000000000000000000000000106e6f74617261737062657272797069104e4f544152415350424552525950490015406b736368657965723a6d61747269782e6f72671f6e6f746172617370626572727970694070726f746f6e6d61696c2e636f6d000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714de17584cd268e75b0277ce02b2ac78ceeb9ae4fa0a595005489bf3f5f77898415e32a3e9504a5314": "0x040000000002000000000000000000000000000000001e436861696e68756220616e6420546578617320426c6f636b636861696e00001440737269766973683a6d61747269782e6f7267186d654073726972616d7669736877616e6174682e636f6d000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714de3cf3ad0cf1a2ef6c2c6040c18e9e1c7787a3205eddc2b25866a7bb9f4b37d08fb99a303b1aaa76": "0x000000000000000000000000000000000008446f6c7068696e01010101000001000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714de3f92404566ce2002d9033615be834251d1be3c49ef6824c62c23cf6c63670d6b525f113f7ec913": "0x0000000000000000000000000000000000054449434f00086469636f2e696f000b6869406469636f2e696f00002168747470733a2f2f747769747465722e636f6d2f4449434f3033323739373034000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714de4c51814f3dc0aaaa8c84c6ba3df3fb3e74c82f7c4d6821f3182367db869a24a695c6c79b9cfa06": "0x000000000000000000000000000000000006526f62696e01010101000001000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714de5c954dd6e8db73648bc880ddbc0f57d62d59f061c800d012e1a7592043d167fc0cc2c3a9da211d": "0x00000000000000000000000000000000000b4c65652042616e6e65720b4c65652042616e6e65721c68747470733a2f2f696e6372656469626c6563726f632e636f6d2f1b4049433a7777772e696e6372656469626c6563726f632e636f6d19696e6372656469626c6563726f6340676d61696c2e636f6d0000104043726f63496e6372656469626c65000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714de635c0c26aa1285ced5f8289b742dd10e1346513b73e55878f5c758bcffee3b7b3aa2d591ac8f67": "0x00000000000000000000000000000000000000000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714de6f7157368189985cb1053f8515e1f6085856998ac902f61b60ae84eff323ea3fa5570e9856082d": "0x0000000000000000000000000000000000094c656f2053756d6f010114406c656f73756d6f3a6d61747269782e6f726701000001000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714de9c4d94174cd2477a74b06ace59a364d8c066e99d6019a3817505a1c8956316d65ad161e4a6f737": "0x0000000000000000000000000000000000066e6577203400000015424e6164657a646131304079616e6465782e7275000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714dea25247eaaa9075fe395dbcd412fb61e933d36cda92b15ccfcdc46c73d697cb59b0590a44e50c30": "0x00000000000000000000000000000000000f42696e616e63655f6b736d5f32390f42696e616e63655f6b736d5f3239000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714dea8918004244b5bae0ce04d8021516cbf0a10c00c4e721319c1e91c729402b232942f9e2c152320": "0x040000000002000000000000000000000000000000000653544156520000001561646f6d69786931326140676d61696c2e636f6d000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714decae94c7ca0c861584d715bcb7a2d3b6a3120891dba91b19b12df42cd50f1c76103e2581d5b4274": "0x040000000002000000000000000000000000000000000b4f6c6976657220e29aa100001d406f6c697665722e74616c652d79617a64693a7061726974792e696f126f6c697665724074617374792e6c696d6f000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714ded9112c2a84a8aa64f39f9d8db7d1f258b28769521e66ca79b2c1d7d0d001c1f5be2c7370948209": "0x0000000000000000000000000000000000084169724c6f76650000000000000b406169726c6f76655f33000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714dedbc2ce55177a93544ddc80d8569f43d39aa1e46f3d1a9a1aedc6d645d7aacde0184ef69ee9de76": "0x0000000000000000000000000000000000086a696e6e79383500000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714deef5a3a1ff7e51fc0f9ad73d248c215a9d3c09543dc4f739068837ff478226cf0e5bf6c32071c76": "0x04040000000200000000000000000000000000000000097a68616e6773616e000015406a756e6975736c693a6d61747269782e6f7267146a756e697573406c6974656e7472792e636f6d000010406a756e6975733939333233323139000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714deefb32e6fa3ca98ea6ac7bc02091c06ee39e01af4e3aad2d0bd738e65b8874e522e7cde04762a23": "0x0000000000000000000000000000000000176162726168616d20504f4c4b4120415353454d424c59104142524148414d204d55474953484100001c6162726168616d6d75676973686134303140676d61696c2e636f6d000008404162757a7441000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714df06261193a58ff6b0a8c24ac3491a353ac33a297990382a17a4f06945b7e8488024aad838e3be1f": "0x04040000000200000000000000000000000000000000084e696b6c617573000000156665692e6c6975406c6974656e7472792e636f6d0000094066657977756465000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714df39159abba55c6a2a221984248f769c6ee496bfc2c813cf000d2c2e10a7e19a67a4f4264a1b204a": "0x00000000000000000000000000000000000f42696e616e63655f6b736d5f33310f42696e616e63655f6b736d5f3331000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714df3ef2b86fcb50a608b7835785fff5f3ce266a55391bfa52c22fa622a1e48cb29490118a8f55e657": "0x0000000000000000000000000000000000096e61696c615f5f6700000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714df448953262dc4272a7dc6c670411c7f086514b9bb46732ed1e6a2045669bc883bfe540979366a70": "0x00000000000000000000000000000000000101010101000001000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714df50361da6149e1c9ec43214602db413abd2dd38bf27fc7fc76be1715f3a2a53e0c15f0be434a323": "0x040000000002000000000000000000000000000000000768696c75786500000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714df6216cf6db2390b967253bc4d2a74802f60bab1ee14e013e29df6605aad937e3bf3af3d06f01036": "0x04000000000200000000000000000000000000000000073154524942450000001931747269626572657075626c696340676d61696c2e636f6d00000b40317472696265646162000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714df658b757ba3a7aa702baf94343fc34fc6b80b225c14758484c91816726a7b3951bc0ce1daae9f53": "0x000000000000000000000000000000000005696e6b21001168747470733a2f2f7573652e696e6b2f000000000a40696e6b5f6c616e67000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714df81a03ab44db94de209cc11caff247c55ac63eea5e65246dfca0d3fa13caf596422e617add11c6a": "0x000000000000000000000000000000000014506f6c6b61646f742077616c6c6574202d203200000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714df83b335782ebc49a02ec4c0ee5ece6ebb979e895f5f677cc5af9c792057d4a16845ac03d866380e": "0x000000000000000000000000000000000007766963746f7207766963746f72000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714df9611452ac38ef494947b0c3d8d505f78a6945db572e9c264debb16f4bf269cb5d45570ce90e325": "0x0000000000000000000000000000000000084368617a626f740101010100000a406368617a626f745f000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714dfc59388da763570a87d5cc741b2db1901f13828456972aee17a7fd298dd4f58d4cbd4764d205c74": "0x00000000000000000000000000000000000000000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714dfc6a79ef6d03ce998b1bc55dfaaac7c42b022a3389ac81fde184e7cf7e4bfb6f1762efacc9dcd0e": "0x00000000000000000000000000000000000e526f636b585f4b7573616d6132001668747470733a2f2f7777772e726f636b782e636f6d0012737570706f727440726f636b782e636f6d00001040726f636b785f6f6666696369616c000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714dfcec3c491888b3ac25812ad6fd4ccdb20b9e39ae8869b92f24bcb112c27a1f8870cf73e3af40d01": "0x0000000000000000000000000000000000044d4f54044d4f54000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714dfd89ee5d28bdb06ee6f9eb0e537bdeea4b952e9232516a5fbb9c8fb3d49522da2dac4fec6b4d952": "0x000000000000000000000000000000000009537461686c646f740000000000000b40537461686c5f646f74000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714dfda9759c850e63fcad4349f82754f223d99182a3f9de949c41ff94e672f7f548e7f4e66c04b5c1b": "0x040000000002000000000000000000000000000000000a537465616b43686566000017407374616b652d636865663a6d61747269782e6f72671868656c6c6f40737465616b636865662e6e6574776f726b000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714dfdd2a5f61982fba4297a93d2faba768a0be3c2a69bee7a17d73264b9adebae51e28e7b37463f91d": "0x04000000000100902f5009000000000000000000000000000000000000000000000000000000064e3444524f000000156e3464726f4070726f746f6e6d61696c2e636f6d000007404e3444524f000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714dfe1e40570dd88f27c1178a97d52454f0c0b621adf94ed9ae7f5bcadd73d78918cd5f2e369afd539": "0x00000000000000000000000000000000000454696d00000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714dff9d344c62cc1a2a89a9920a98f3591ccc0a1a4bc827a0adfba37b75fcc108ae3c7191bb9a32750": "0x040000000002000000000000000000000000000000000a50756c73656d6973730000001b64756661756c7472617175696c64697340676d61696c2e636f6d000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714dffd6f88a42d7fac960e13bfebea36ecf357ec2e813c2c06cbe61c8b789f5e06250d51244ec65f2c": "0x00000000000000000000000000000000000000000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714e01262497050cc2b2e75870b38698bb3f2bd133e571bb0207310369eb624f12e27b640997c9fd079": "0x000000000000000000000000000000000005524b523200000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714e021d1dc17893ea928b07966a96b6a1985a177e15d42d894b3fb7792127b6fe90c2fd282eb4c897d": "0x00000000000000000000000000000000001a416c666f6e736f204b7573616d6120496e766573746d656e7400000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714e02cfa2f68a3d5d68c634afce5c235c94eb221a35c3f8cde8f45b961d713780f16dc561e98537e7a": "0x0000000000000000000000000000000000046e667404506174000000000010405061747269636b53616d61313830000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714e030fba8f6a1ab9562268ef984602bd656ee3f4ffd59ee4f91fb1b8dacc81561165acf09cb04b437": "0x0000000000000000000000000000000000114e6f205269736b202d204e6f2046756e00000000000010404d6178696d654164656c76696e67000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714e0557f0ae534aab028991ea1e64fe9abfa42ca2c940b83440041f53c1eacebcaaf946800df88bd65": "0x0000000000000000000000000000000000026d01010101000001000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714e056f1b2e24fa5d8887a4b3bf904dff1bd2b9db7d434a8293190a442e264f019255c799cc8755f10": "0x0000000000000000000000000000000000074d616d61544c01010101000001000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714e06d0f11fae617ffc00c1b295efcdc9a094f31f425d1728677ea4c978ba553d30a9df39737a6ec07": "0x00000000000000000000000000000000000d4869676843686956696577730e436872697320436f6c6f6d6265000011636f6c6f6d626540776973632e656475000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714e082b4d27c3e325290028c5f7ac635cc45299d9de9e04681d2d935461bb79e83faf9fe9021407001": "0x00000000000000000000000000000000000a466f7220706561636500000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714e09f03562c3730f22cd74deae018fa587decf7492a527329f06e44e9e9725c6e7c48dbf6fe3a0c61": "0x00000000000000000000000000000000001c4b656570696e672055702057697468205468652043727970746f731c4b656570696e672055702057697468205468652043727970746f731768747470733a2f2f6269742e6c792f334f686d6847410000000010404b656570696e6743727970746f73000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714e0a7bda9cabb2697382c2b16eff91187f088ea8902a92fd101c647fcf8fad4995dcda013f5674146": "0x00000000000000000000000000000000000a4e38746f72696f757300000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714e0b7b989a9a7b3882a26e8ab44149c0eca39f384f5461ac94d9db482f7048bcf01fa03ac974e9f74": "0x00000000000000000000000000000000000000000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714e0bcb14a63a8f407f082e865cb1640b9d304e0112f2a853fefab59cb646742a87b6efddba380bc51": "0x00000000000000000000000000000000000e446f7473616d612050756e6b730e446f7473616d612050756e6b7300000000000e40646f7473616d6170756e6b73000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714e0c1c0b1ba68c50b38442c5d5813e8982e7d0e48b0902a2fcd7dca14bcbcb2018b3be02ddd0baf2b": "0x00000000000000000000000000000000000f62696e616e63655f6b736d5f33330f62696e616e63655f6b736d5f3333000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714e0d88f101c60b968860b9c3afa9056b5861ea3252c32d4ceee039d5a328210b2f106e2362564c327": "0x0000000000000000000000000000000000174368616f7344414f2042616e6e6572204d696e746572000d6368616f7364616f2e6f7267000000000a404368616f7344414f000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714e0e206491404b059c229d8ccc5e5650d17760ce2b7c42bdae5f6afc6e8bab249ec77f3f779ee5a65": "0x040000000002000000000000000000000000000000000b4e6f64616d61746963730f4e6f64616d6174696373204c74641768747470733a2f2f6e6f64616d61746963732e636f6d14406162633a6e6f64616d61746963732e636f6d13616263406e6f64616d61746963732e636f6d000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714e0f9f6d0a22b7f4d7c101b5a4517817aa0e05d07291dc0f020daf435432ce8ef6996fa8fdf722a58": "0x00000000000000000000000000000000000a4d61747420437a617001117777772e6d617474637a61702e636f6d010100000a406d617474637a6170000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714e10f7130f3342868be48e86fb92b88b2cd58af2e0f83ce19054a1710f3285ec16cfa21c533070038": "0x0000000000000000000000000000000000076861727065720768617270657200000000000f406a6572656d696168736f6c7431000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714e14b7899b9364c96f4ee3ef446661d9952ca201eb16aed93217c14c48970106092ab7e3f2b4ae713": "0x00000000000000000000000000000000001048616e77656e207c204c69746d75730000001468616e77656e406c6974656e7472792e636f6d000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714e14f996a74ee6952fc76f7807f64bd43133d613e69b76210fd9613946365c01aece14d487d07c71d": "0x0000000000000000000000000000000000054265653700000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714e17e6feedc6d6c3e024f853befcdb3963b6c6405cd765edfdb6323afdc79c0a842154ba7e8bd7e4a": "0x040000000002000000000000000000000000000000000844656c616e65790000174064656c616e65795f73633a6d61747269782e6f7267136c6f70736c69746540676d61696c2e636f6d000011405363727567677344656c3639353636000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714e18ec3dbed3906928c2dee8f9acfbd0ace6ba1c804e4f592e39e4c9c895646d1cf376179a4de7d73": "0x0000000000000000000000000000000000086963656265726700000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714e192bdc41ba8b8537a4ea4898b3670047a9a245b16814151fe047e7f4317274b2322bc16bfc86777": "0x00000000000000000000000000000000000000000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714e1b9d02d9a1f50ab16da5bff34fefd1880608641996167d42ddf2832ad360eaaf26bd480f8b11510": "0x00000000000000000000000000000000000c597572694e6f6e6475616c0d597572692050657475736b6f001840797572696e6f6e6475616c3a6d61747269782e6f7267167975726970657475736b6f40676d61696c2e636f6d00000d405975726970657475736b6f000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714e1c590c2d461a2919affd71d6553897322cbc27d841267cbd0f4f61d5b2e1b55f1ccc4dee3dbbf29": "0x00000000000000000000000000000000000e676c6175626572626e756e65731a476c617562657220426172626172726f737361204e756e65732068747470733a2f2f6c696e6b74722e65652f676c6175626572626e756e65731a40676c6175626572626e756e65733a6d61747269782e6f72671a676c6175626572626e756e657340686f746d61696c2e636f6d00000f40676c6175626572626e756e6573000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714e1cc7e9a208fec062a60ef494b4278138c41a5abfaf31a98703d16cb817c121bffd6fe29922a717e": "0x0000000000000000000000000000000000075a6f6f6579730000000000000c40706978656c7472697070000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714e1d72d8b8fd19c1e180e0bbab137521c05b4d905878159e631e8d58f8f98eb54bcde45355a64a42d": "0x0000000000000000000000000000000000054e4f4e4f0000000000000a404e6f6e6f5f646761000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714e1e4563d8107381d90bc0687ec4207718cf796657debc704ddcd040fb7bfaf024a0112085e3bf44c": "0x00000000000000000000000000000000000f4f7374726f696e76657374696e6700000000000010404f7374726f496e76657374696e67000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714e1e83d6e28cd24a1cc5fb20e015e196772a14adb90f25ad646b55261cf41ba556058b2cf05e1d14d": "0x00000000000000000000000000000000000b617065586368696d707a001d68747470733a2f2f6c696e6b74722e65652f617065586368696d707a0015746f75636840617065786368696d707a2e636f6d00000c40617065586368696d707a000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714e1ea5606e60d1e1b6ec662611fe307a35f5071d69b7e38993e7ff1b0c887eb742ad5d4a5161fd10a": "0x00000000000000000000000000000000000b466c756666795f666f780956616c657269612000000000000e40466c756666795f465f6f5f78000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714e1edcfad4e61061fce792e53c1b7b7375ed58cfe1a68a88fc0dde4bd604942f99a5e93ff3b249d2c": "0x00000000000000000000000000000000001048696b617269204e616b616d75726f000000000000104048696b6172694e616b616d75726f000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714e2082f50f907e5d5a48539457aa2e54048493ccaf980be18253d8cabd6eecd295e6b62e6a357352f": "0x0400000000020000000000000000000000000000000009616c66616b696e6900001540616c66616b696e693a6d61747269782e6f72670000000a40616c66616b696e69000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714e21241c1f77eea219c34bbbde6bff80d45a0e9f3500e7aebd52d558fcd919b2e0d788dd8728a047a": "0x000000000000000000000000000000000010416e61656c6c65204c54444049425000001740616e61656c6c656c74643a6d61747269782e6f726715616e61656c6c656c746440676d61696c2e636f6d000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714e21499c80ca854b48c82bbbbb9667ffba6391a9562295f4138dc0d28c4a062c98c71892a3e149e33": "0x0000000000000000000000000000000000054d617279124d617279204f6d612d57696c6c69616d7300001c6d6172796f6d6177696c6c69616d7340686f746d61696c2e636f6d000010406d61727977696c6c69616d735f6f000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714e233542478d579cace65b4f9996573027bb9ed1f267033177462f9019642f1fa0b14a0ce41994525": "0x04000000000200000000000000000000000000000000084e4f434f314b53000017406e6f636f63727970746f3a6d61747269782e6f7267156e6f636f63727970746f40676d61696c2e636f6d000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714e267ed189b260f34e860a0f82dfd893ebf69b3ca5867e58dde45e4c03acc88dcf1881c05a1cbb624": "0x000000000000000000000000000000000007627269616e3100000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714e26aa6ab4f40124e083f39607241c8ebb62919ab2ed816cb6b20c7d0abad78a92570030d2f96c63c": "0x040000000002000000000000000000000000000000001443727970746f204a61636b2053706172726f7700001e406a61636b73706172726f7763727970746f3a6d61747269782e6f726700000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714e29cc92a3efbdcb4fade8b2ef9730e55caad79c952c433082849c133e8f4303c959124f881cff002": "0x00000000000000000000000000000000000c6172676f6c616273202d7300000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714e2b5c6849bd31d1a68a7a410afcdad03bb86018eb32bb188ce81f4a7bbac85f9a161511b4939252a": "0x00000000000000000000000000000000000a6368696c6477696c6408616e61746f6c79000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714e2d6e1cbb0d68059803a44e8667a858bf0cb69c031e7623d560e962c6bfd9b1d28438d6ef6a20e5a": "0x000000000000000000000000000000000010506f7274656c61204361706974616c10506f7274656c61204361706974616c01011a706f7274656c612e6361706974616c40676d61696c2e636f6d00001140506f7274656c615f4361706974616c000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714e2dbccbe79b6bc23a0c9c8a74436d2554b9a0249994899e527008da53b2e33dd45b51d07d0d3125e": "0x0000000000000000000000000000000000146172676f6c6162732d636f6e74726f6c6c657200000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714e2e24cb03e478499c2f8c1243fbad7e55982b37dc983137e4b9df19f5b31b5b35c5809d81cc4d03b": "0x00000000000000000000000000000000000e42494e414e43455f4b534d5f390e42494e414e43455f4b534d5f39000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714e2ee33ee9eb984f7467d94f60ca2fec8bdfc843926088df5ad274feb4a8c2cd0465ca8cb78f54c72": "0x04020000000200000000000000000000000000000000075472616e7358075472616e73581268747470733a2f2f7472616e73782e696f13407472616e73783a6d61747269782e6f72671173696c766572407472616e73782e696f00000a405472616e73583131000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714e3090a8f14b0a8a7e8fc78d54db8818125e186950a295ac7db278b9c83b6c04416ccf38869451405": "0x00000000000000000000000000000000000b44616e69656c20426172001768747470733a2f2f7777772e6269746677642e636f6d154073706c61736865733a6d61747269782e6f72671264616e69656c406269746677642e78797a00000c4064616e69656c74626172000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714e31041f839b1c98afe111b571b0ba64cb8365c7e9bba1e412d6fd57634a54bd1996314689e061a68": "0x00000000000000000000000000000000000000000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714e31e32af7d282fd42cf0838b05fb182718de859525fa1e6d53d557e5fcf631ee9ff44c619810d43b": "0x0800000000020100000003000000000000000000000000000000000843686576646f72001868747470733a2f2f7777772e63686576646f722e636f6d144063686576646f723a6d61747269782e6f72671263686576646f7240676d61696c2e636f6d000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714e3246305c87cacb27c660ea631e3433e76cda4223da22d0f40ff51d0790f9531c6dc017f04526454": "0x00000000000000000000000000000000000c4755494c4c49544f4c4d4f000000166775696c6c69746f6c6d6f40676d61696c2e636f6d00000f406775696c6c69746f6c6d6f6473000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714e32b208e65130e522045da46c7766eb3f515007cbcfa48187fd157189adcde4b0a36f5069661c147": "0x00000000000000000000000000000000000a4f6c61736b61417274074f6c61736b6100000000000b404f6c61736b61417274000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714e3450541d8d8d0681af27d40bf7e664781d62d3e0953bf49a7b6accab06d48acbea4c0497a285135": "0x040000000002000000000000000000000000000000000d426172616e2042617964656e0000001662617964656e5f62314064656e69736f6e2e656475000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714e35b67b937cc75caa81dfbac142664eb6f7ff61c5c0b2c8a180059b27ccb68ccc6b9c152be120b70": "0x040000000002000000000000000000000000000000000c6669616c6b612e6c697665001468747470733a2f2f6669616c6b612e6c6976650012706f6c6b61406669616c6b612e6c69766500000c406669616c6b61706f6f6c000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714e36e578a8e8879d6882cb987c0812a6223eccca2b949a700f23956c0fd0e078998aa202fbb3dd258": "0x0000000000000000000000000000000000084261746177696c094d6f68616d6d6564000013796565656573383840676d61696c2e636f6d000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714e38a55733df8b59a8afadb56a14267be2968192955ea0946c4c7654bf57edf48b8e2a0026ebb5c16": "0x00000000000000000000000000000000000e476f72676f6e7475615f4e46540000000000000f40476f72676f6e7475615f4e4654000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714e39df08f4aede84f78bd7b1645db34388b2de98519122d04ce82685b60b092e4a1a6b79495b06435": "0x0000000000000000000000000000000000086d7766696c686f1b4d6f697365732057656c746d616e2041627265752046696c686f0000126d7766696c686f40676d61696c2e636f6d00000a406d7766696c686f32000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714e3a4e80562b259ac10b09f2da2f405ee165a9288afdf2a8d28f77abedc0c71c2322d1e7bbf824573": "0x00000000000000000000000000000000000d446d69747279566973696f6e07446d69747279000017766973696f6e646d6974727940676d61696c2e636f6d00000f40646d697472795f766973696f6e000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714e3a998fba5b8bbd73c747e495e89089d355e243e1d3818a46c83423d4d230f6fbb516ca1f9a69498": "0x0000000000000000000000000000000000104b5553414d415f54524541535552591847656e736869726f20627920457175696c69627269756d2068747470733a2f2f67656e736869726f2e657175696c69627269756d2e696f214070657465725f7374723a6d61747269782e6f72674070657465725f7374723a1770657465722e7340657175696c69627269756d2e696f00000e4047656e736869726f44654669000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714e3aace461a41787e00dd250306b8d5d95cfcf010f9197aa6a23ac456c4dfa242648b45f3d7d73062": "0x00000000000000000000000000000000000d466f756e646174696f6e2e5100000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714e3b37bd998e2d5ae02e8b488ad53f796a30d332f94f9b86da98c5b4045e09dbec4b520787f2cc568": "0x00000000000000000000000000000000000b4b7573416d617a696e670b4b7573416d617a696e670000156b7573616d617a696e6740676d61696c2e636f6d00000c406b7573616d617a696e67000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714e3cc564421272ae1661e75c54ec564a0e3af9c0a50860fa942d9d1b02d73712fbf855ddef81f4b1f": "0x00000000000000000000000000000000000f5761737465206f6620796f75746809536f756c20726f741d46616d6f7573204368696e657365205061696e74657273402e636f6d0111536f756c726f74406d6565742e636f6d00000a404d7578696e617969000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714e3e27ff656075247d2553b686fdb9fcb522543211a26d6e2ec15fbe051b49ebd03c7ea920ab03a79": "0x00000000000000000000000000000000000b77617465726d656c6f6e01010101000001000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714e3e9a46b476478204c4769cc1bf4774f19c7433e31a5b8cb686944cdd758e193d264410d4918b120": "0x0400000000020000000000000000000000000000000009506172616d69746f00001540706172616d69746f3a6d61747269782e6f726715737570706f727440706172616d69746f2e636f6d000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714e3ee646b3e2aebc288214b102388d1c4506c188c7ed7e7d306c03c5bc6e3fa5e4e16b84ceb86ca7d": "0x0000000000000000000000000000000000066c6f756b61000000126c756b6f6c6172696340756e696e2e687200000d406c756b616b6170746f6c31000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714e415276d670b78fbbc8581a5550ab573ee71a5eb5424ffcf3669a47d5b165fbae9979c2232eafd35": "0x00000000000000000000000000000000000a4f7468657257524c440f4161726f6e205370616e676c6572000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714e4153a7e275b66f81c35024ca6ebe0f04f37160246226252f758640bc7fbdfd7d1862d1cc0709706": "0x04000000000200000000000000000000000000000000094e656f506f77657200000000000011404e656f506f7765724469676974616c000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714e4173fbb2e6bce95ea7e253f4ef614f3461f1b20259ff57dc1ed75397f9028c4446a3c49348d9610": "0x00000000000000000000000000000000000762616e64616900000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714e41ae28131a0427194b43554ce1f4d12431ecd9e98b526c8a2365c73c4df302762afe817f2014725": "0x04040000000200000000000000000000000000000000057074716100000011676f6431373540676d61696c2e636f6d000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714e424960c1224933864e05e73625f3f0991e3062733ad8480c5589a710a24beacbaa555f1c4a7f064": "0x0400000000020000000000000000000000000000000014f09f8db750726f6f664f6654727565f09f8dbe000014407665727374616b3a6d61747269782e6f72671870726f6f662e6f662e7472756540676d61696c2e636f6d000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714e43bc3dbea2aea278cec9d853f1e271b254904cbaad9b96cf5674111df2712e106782b6d03ad4a02": "0x000000000000000000000000000000000004496b650000000000000a40496b654275696a73000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714e45b9c4b5333e7a93e814767c06c6f8cfbe0c531c5bc2545ec897f41427faeed5f2a796107c98425": "0x0000000000000000000000000000000000064f7369656c064f7369656c00001a6f7369656c2e6d6d6d6f72616c657340676d61696c2e636f6d00000f404f7369656c3035333933323130000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714e46a0a1f27bec44a52b901aa3d7b55a32518b419e7759d281a620269621b460dc2f44c1d8d49ec3c": "0x040000000002000000000000000000000000000000000d4d4943484953414d412049490000001a6d69636861656c2e7361726e69747a40676d61696c2e636f6d00000e406d696368697361726e69747a000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714e47308a662ac61d8ec748cd857304d85365e8189c61bd414d5553f1aa4190b6743f528b30dc43939": "0x00000000000000000000000000000000000000000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714e4862976694931a99c188166a98813c80bd47da8c69317282ba30fda0052e8f26c9afd4226793553": "0x0000000000000000000000000000000000074a6f736569370b4a4f5345204d4154454f1a68747470733a2f2f7777772e6b6170617a6b6179612e636f6d16406b6170617a6b6179613a6d61747269782e636f6d146b6170617a6b61796140676d61696c2e636f6d00000b406b6170617a6b617961000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714e48e1e2716de291fb003e858a649acbfde98acf1d9e7863397984405fc8e0ff9d91fa4c9025afc27": "0x04010000000200000000000000000000000000000000184b41474f4d45204b7573616d612076616c696461746f72000014406b616d696c73613a6d61747269782e6f72670b6b40716472766d2e696f000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714e497fbc93f6011c0ce1120d245e6912eab85477f9a806728f4bf82ee50ccb4f8750ae14feb7d9c7e": "0x0000000000000000000000000000000000084d6f6f6e4b6f6900000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714e4a7b18b604b590ebe4b9973a7f6a5586a38fa295ec8e64d4026aa878c840630a7ccfa7f3914d162": "0x040000000002000000000000000000000000000000000b476f626c696e53616d6100001740676f626c696e73616d613a6d61747269782e6f726719676f626c696e73616d616e6f646540676d61696c2e636f6d00001040676f626c696e73616d616e6f6465000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714e4a9fa782e599e6e54bbe132da515c57b551b15452d06341ce9212859c8a0d8d5eba38b9f82f486f": "0x0000000000000000000000000000000000114576726c6f6f74204f6666696369616c00107777772e6576726c6f6f742e636f6d00116c757575406576726c6f6f742e636f6d000009404556524c303054000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714e4adb7a829a6d528623f9120f5e76a9988d6273e32e15a6a3db3ff0bbc551c081bf8716a6f152d22": "0x0000000000000000000000000000000000000000001544414f6e32456172746840676d61696c2e636f6d00000d4044414f6e546f4561727468000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714e4b32bdcfe8a21ed50b428a44aee6d7d7971bc278208f295b647bd1cd44985423c3cf405adc2e336": "0x00000000000000000000000000000000000b6d616c696b656c626179001c68747470733a2f2f7777772e6d616c696b656c6261792e636f6d2f0013686579406d616c696b656c6261792e636f6d00000c406d616c696b656c626179000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714e4b5facde9bf411dee16a0a68c6bb00ee88ee56a12ad67e778bbee540f868ead35fb6851fc522c0e": "0x040000000002000000000000000000000000000000000959414f20476d6268000000176c756b6162616c6173686f7640676d61696c2e636f6d000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714e4cea58d581e6c8f707c9246c1c227f1495885cb2f4c59297248ec5abeff2d0f68495075a16bc17a": "0x04000000000200000000000000000000000000000000034147001668747470733a2f2f76616c696461746f722e61672f154061677831303030303a6d61747269782e6f72671368656c6c6f4076616c696461746f722e61670000084041477831306b000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714e4d0c3afd0945f3b8eebe1699e80aa195f76826c2c9da998095018f6d60a0446b6074736a68b3922": "0x00000000000000000000000000000000000c50756d706173617572757300000000000010407069636b61736175727573303037000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714e4f24b48776a5907d860c42aad31e29765a88620672b42628634a6901e9a2e327b3b77de463a4051": "0x00000000000000000000000000000000000a53545238204641433300000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714e4f801fde83ab27b86d96411e256368ca351706e72275f29a0190becaf81dacd4983d5f17e41442e": "0x00000000000000000000000000000000000b4261727279204f6e797800000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714e51a8e774114148a1cb8c4e3b0331a1d7db9a12dad422096a3b2ea8634aba36a00947686d818077a": "0x0000000000000000000000000000000000095376656e67616c69010115407376656e67616c693a6d61747269782e6f72671963727970746f747261707065727a40676d61696c2e636f6d00000f40756e636c657376656e67616c69000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714e5226b3101e1a2cf16ea73eab943eeb2bbf8c6c5e5ac7bd92004c3c395f2db8e095b8c4afc063324": "0x04010000000200000000000000000000000000000000094465436f6d6d6173094465436f6d6d61731568747470733a2f2f6465636f6d6d61732e696f2f000d6d4033636f6d6d61732e696f00000a406465636f6d6d6173000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714e54b0dce3847be9f2a9aefeadfe561f9c27106bf951d4d362b26fff6beff8b7949881071c973ee63": "0x000000000000000000000000000000000008497a204172747303497a1a7777772e696e7374616772616d2e636f6d2f697a64726177730019697a7a61636f6d6d697373696f6e40676d61696c2e636f6d00000940697a6172747373000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714e560702c07b98769501c6522acab8faebe0aeb74bc5cfb6e0c0062134ce4139b2b4d29e690306942": "0x00000000000000000000000000000000000e4b7573616d615f77616c6c657400000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714e57b6fff5aa31fc5dc73e84c4d039277ae7819cf959a0092683ea8e6e7e9d2447c918d8aa89d681e": "0x0401000000020000000000000000000000000000000009456c2050696e746f09456c2050696e746f1768747470733a2f2f63616e6172796e6573742e696f2f0015656c70696e746f6d616e40676d61696c2e636f6d00001040416c6550696e745f43727970746f000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714e5838dc3419931bafcee617f4c62eba023c5dd5bd4b3c4168e6c5cfdf504b50d611c0550fd078557": "0x000000000000000000000000000000000013456c656d656e7473206f66204b7573616d6113456c656d656e7473206f66204b7573616d612068747470733a2f2f7777772e656c656d656e74736b7573616d612e636f6d2f0015566f6c74756d2e6e667440676d61696c2e636f6d00001040456c656d656e74734b7573616d61000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714e5c3e4a6b7f9ce9d1a3064ba1947c88f8d8e8d68296a5504fd3c1f3261509b4ce40b92b1b75c7174": "0x040000000002000000000000000000000000000000000a54657261204368616400000010676d40626c646e6f6465732e6f7267000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714e5c7849de4c2d8485cccaa999b535cd15c18bb2d22db70e4d7e8c83bb85bcbd3efbbd71f29c5d401": "0x00000000000000000000000000000000001257656c746879204d6f6c65732044657673002168747470733a2f2f6d656469756d2e636f6d2f4077656c7468796d6f6c65732f000000000d4057656c7468794d6f6c6573000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714e5d8672abc761749fad2d3a08e033ef653430391e3b208f9e17119de384eab78084c1dd817893439": "0x00000000000000000000000000000000000b416c616264756c6c616800000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714e5e12c84a1884bd50a6ef463d858cf46d27ad2129b04f078a6b009eb588f9d651e399bce59fff579": "0x0000000000000000000000000000000000054a494c4c00127777772e6a696c6c73656e66742e636f6d000000000b404a696c6c53656e6674000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714e5e77e17df143c51388c3c690f7ce15672f086b6a5e3ad7263b36986392cd5c8a70ee62f11554553": "0x000000000000000000000000000000000021547269636b79204e46542052657365617263682644657374726f792044657074001868747470733a2f2f747269636b792d6e66742e6172742f000000000d40547269636b795f4e465473000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714e5ec7a33cbbb8d9e04f3da939fa351c562c7e06e1e3716976b5e14230e83a45995cbad9086f49e17": "0x040000000002000000000000000000000000000000000a506f6c6b61476174650a506f6c6b61676174651668747470733a2f2f706f6c6b61676174652e78797a1640706f6c6b61676174653a6d61747269782e6f726716706f6c6b6167617465406f75746c6f6f6b2e636f6d00000b40706f6c6b6167617465000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714e5efd10bd264dbe62c0adc4df234352b61fd60a32c2890fc64c2c0a3de5e33ee1c5bc9d8f581642d": "0x0400000000020000000000000000000000000000000017f09fa7b12053656974616e20426c6f636b20f09fa7b10000184073656974616e626c6f636b3a6d61747269782e6f726700000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714e5f35c89aa222ad08a0b27e25e4d62869f8aaf9e23c69e9b494b1fc617d0ebeb4c8afdcf1fd1aa59": "0x00000000000000000000000000000000001246757475726520426c6f636b636861696e000000166768726973746f7636343340676d61696c2e636f6d00000e4046757475726542636861696e000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714e5f95c682343769f3070122f5a708702492ef47c9113a8896a9d4bd33a24a071cead7303e1158f26": "0x00000000000000000000000000000000000f4069696c696e67776f7274683232194a6f686e205269636861726420496c6c696e67776f72746800001e696c6c696e67776f7274682e7269636861726440676d61696c2e636f6d00000f40696c6c696e67776f7274683232000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714e5f9a2fa2a6ae21fc86f4ad4a9c9032c14426b27d2b899a9813ade10664beb503c3076f78a87ca09": "0x00000000000000000000000000000000001b576f6c66207cf09f97bb4261736563616d70205374616b696e6700000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714e60d3fee20a9683954802ea0b430910788de53c221bf8c0f1a349719284af18c1ea1f2807c4fec44": "0x0000000000000000000000000000000000104149207769746820612042727573680000001761697769746861627275736840676d61696c2e636f6d00000e40414977697468614272757368000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714e61845ff24d5cc1e342f12106e62dc91fd042c6ea03f570502e69314d5cdf9128c3ca1deab6d904c": "0x000000000000000000000000000000000011596f75646c6544414f204d696e7465720a596f75646c6544414f1a696e76617263682e6e6574776f726b2f796f75646c6564616f000000000b40596f75646c6544414f000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714e61c50b0b7f382f3fa8f1542a5136431ffaf6e46fd95cf784931de839ea17d154a4eee41308adb5b": "0x0000000000000000000000000000000000066c696c6c6f066c6564696f00000000000c406e6f5f757333725f6964000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714e61e63d1b5d2c29a1c90f53e61c20041e1a3df81248b4a6bfa420ec7cd5ad1dc37050bd50253be56": "0x00000000000000000000000000000000000f426c6f636b6174686f6e2044414f0f426c6f636b6174686f6e2044414f0f426c6f636b6174686f6e2e78797a0016626c6f636b6174686f6e406269746677642e78797a00001040426c6f636b6174686f6e5f44414f000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714e62a1248b05d3350b0a503c9745bfe83420884d860baa41869bec8a251e640d5769134e92119343c": "0x040100000002000000000000000000000000000000000d4c756e617220417669617279001368747470733a2f2f6269726463752e6c742f17406c756e61722d6563686f3a6d61747269782e6f72671c6c756e61725f6176696172794070726f746f6e6d61696c2e636f6d00000d404c756e6172417669617279000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714e62a64b055ddf8da2c8781410fcdb4a98b0d87447f73e46c2c5a285cbe3338e73cf213f4fa48851b": "0x040000000002000000000000000000000000000000000a6d6172697361727a65000016406d6172697361727a653a6d61747269782e6f726714666c79706574726f764079616e6465782e727500000b40666c79706574726f76000a6d6172697361727a6500", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714e6344678166f5ea4ce632205bea89e6a30ed4e150402ba7997fa946739dbff2d8bda1fbb73f6d461": "0x00000000000000000000000000000000001a4d41494e54454e414e43452043555241544f522050524f585900000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714e640a57f005246e16cc99fecae54278eb06aab56467bb644500ac7301cb1b9dd2f7b3bf8014cb40d": "0x0000000000000000000000000000000000065061626c6f067061626c6f00000000000940626974636f696e000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714e6571ba184d1dd340e24ef1865f800083d91176db91ceb22bc12386f4ad085843c7c2b1d2e457f61": "0x000000000000000000000000000000000006506f7070790000000000001040506f7070794f6e5468654d6f6f6e000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714e6641b78daaaa70c127d0bf5a272c4fce4b744027090fd032cd8dd569c52b8301727192d6df42f78": "0x0400000000020000000000000000000000000000000010f09f9a80616c6b6f393839f09f8c9b00001440616c6b6f3938393a6d61747269782e6f726712616c6b6f39383940676d61696c2e636f6d000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714e669931fb1d70de1e63bad33d41d23e049d4f9efea39e4f44426b3f82104800ef6a9f29fbaa18667": "0x00000000000000000000000000000000000547616265184761627269656c20466163636f206465204172727564611368747470733a2f2f67616265732e73697465194061727275646167617465733a6d6f7a696c6c612e6f726716617272756461676174657340676d61696c2e636f6d00000c4054696e6b657247616265000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714e67690be6715ac6dd24fb92b0c4972591887fd6bd35c641d80c2f6341c8ed8231afb779e4e26ea4b": "0x0000000000000000000000000000000000204d495353494f4e20434f4e54524f4c207c20434f4d4d554e4954594e46203500000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714e682263d2b1ef24bbc2d28f57741ea9f160b1dfa892f5ec7d27794a10faf0eaf864e3cec1f935c6b": "0x040000000002000000000000000000000000000000000747726f6d7a790000134067726f6d7a793a6d61747269782e6f72671367726f6d7a79313540676d61696c2e636f6d00000000085f67726f6d7a7900", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714e6a2e00133e91fa9b60df42b347f1fef9ff33a82e6cf842ee1cf51547ddb4ef66da57194e7b8ba4b": "0x08000000000100902f50090000000000000000000000010000000200000000000000000000000000000000094465436f6d6d61731533436f6d6d617320546563686e6f6c6f676965731568747470733a2f2f6465636f6d6d61732e696f2f1640696f736966313937373a6d61747269782e6f726716732e7368616d616e6f764033636f6d6d61732e696f00000a406465636f6d6d6173000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714e6a4ed08608c10747cd59ba5ff4fb96195e2ccb9eaccd78bff982e0f15db7e942d72d1b957a2fc0a": "0x00000000000000000000000000000000000774657566656c00000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714e6a7928211b426f8dc4cec4724b20afc1dc35f89679f2163a184c121c8dd74e00ee15114b471fb3b": "0x00000000000000000000000000000000000000000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714e6a7b17e0dc24fffb6c276d432f4efd1f1d1dac4ffe8b237884c3eff170579883e24752c4179f30b": "0x00000000000000000000000000000000000000000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714e6b52eb564f74eb652620328072469a6ddfdefbe41728a7de41dc26c6287529f220e562bc5030e63": "0x00000000000000000000000000000000000d456c656b74726f76656e696b00000015737472656c6f6b37353940676d61696c2e636f6d00000a40737472656c5f6f6b000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714e6bd40c93fa096fd767cba4f8c9944d922ec038b8e49798ded82982594176648e88846bab4dfb116": "0x0000000000000000000000000000000000084d65727269636b0101010100000c404d65727269636b323439000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714e6be2ef10957c7f700cc6d75d48ed09a1a77df6336e1de6610bd6cb012617f5adc7a0a0088589d60": "0x040000000002000000000000000000000000000000000b4c6f72656e61204b534d000014406c6f72656e61663a6d61747269782e6f7267166c6661627269733139373440676d61696c2e636f6d00000a40626c6f636b79615f000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714e6bf80afef0f87a4e8c096adce479e487ffbb318c037b5a6e6d3743f89f83c5f32aee60590fb325a": "0x040000000002000000000000000000000000000000000a47656f7267695f6967000000126a69673737303940676d61696c2e636f6d00000b406a696763727970746f000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714e6c2c15d71b57c80a8cc040d5d391967b6c50b54d81dbc18acf06fd13a704decc7df6f464679051b": "0x0401000000020000000000000000000000000000000008456c656e6f646500001740656c656e74726f6e69783a6d61747269782e6f72671b656c656e33393874726f6e6978626f7840676d61696c2e636f6d000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714e6e4f10f4a2d38dbb6511f13375482ec7f64612a9b23a6f9d0922d052b8ff65756e97640607d2476": "0x040000000002000000000000000000000000000000000a4e654e6120f09f8cbb000016406e616d6574616b656e3a6d61747269782e6f7267196d796d696e647365746f6e796f7540676d61696c2e636f6d000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714e6ea262a4e57686c7c95ac8365f9f4fc5f0979c438adaaa4766871c3080ab274904837315cdc8b26": "0x000000000000000000000000000000000008417274204c61620644617679640000156172746c61626e66747340676d61696c2e636f6d00000d404172744c61625f4e465473000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714e6ffdcce232e42d1f047d33d085908d48fd886c98b56792757c6dcc79df7549921a456c1500ad75c": "0x0000000000000000000000000000000000094e6f67617264657210416c69204361676c617220557a756e01010100000c404c6f626973696c696369000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714e76389c26b279edcfcc3adb5fd50be07e63c0711e10bf94a5e81e3049f58b4a1c0f78b7c63436a3e": "0x00000000000000000000000000000000000c446f776e736964655075740c446f776e73696465507574010101000008404e4b59323235000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714e7720d47146ee75b84ea64de1c450d5e719041fc2fe8cfb61bfbb8eb42790de3ff6f7bcf41ae432c": "0x00000000000000000000000000000000000a5f476f676f676f676f00000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714e77aa7455b2fe961fe4c363ca5fbd7818a873e807261aff6288a5c83f9464cbfa0fa0f280a9a7a31": "0x040000000002000000000000000000000000000000000761726b6177610000001461726b61776136303640676d61696c2e636f6d000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714e78e73a25356ee263028097756f2e6b331a1ab76fd0abe787b6a1e60d0174c9dfe44c4adae5bff42": "0x00000000000000000000000000000000001031706f73697469766576696265733100000017637572746973657472697070407961686f6f2e636f6d00000d4032676f6f64766962657331000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714e792229345a703fc4ec57d4ea0756ce490ae612b7566f87fd99d946fbb0acf030c3642807189ad04": "0x000000000000000000000000000000000014456d6d617320284164616d204173676172642900000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714e7a7f99c4fdd18b6aa45f39ba0061f8a7e5d4df583d003a9f11c89f09c6e0650be230552dbde8d65": "0x00000000000000000000000000000000000942657274696e686f144a6fc3a36f20466964616c676f2053696c76610000186a6f616f6166666273696c766140676d61696c2e636f6d00000e407075746f62657274696e686f000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714e7a9bfdf07bafce9e604df3ebc0fe5cf21a4b4be4c8f0b28a1c458b455316215b41da6f136f7910c": "0x00000000000000000000000000000000000b746f726f647261676f6e01010117746176726f736472616b6f6e40676d61696c2e636f6d00000c40746f726f647261676f6e000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714e7aeab5136b2e1a4182cf6a4edda25060a732818ecd359268b7cfe3c9ed503cd5a76fb4dfd8a1c5e": "0x00000000000000000000000000000000000f696f667468656265686f646c657205494f54422168747470733a2f2f6c696e6b74722e65652f696f667468656265686f646c6572000000001040696f667468656265686f646c6572000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714e7cb8e1a29da70a064f4c7e6a5f3f25b4d063e5461bf3882569aad883b6db400695ccfd7c6e6ef22": "0x00000000000000000000000000000000000c5843417374726f6e6175740744616b6f74611968747470733a2f2f696e76617263682e6e6574776f726b2f1940696e766172636869746563743a6d61747269782e6f72671764616b6f746140696e76617263682e6e6574776f726b00000d405843417374726f6e617574000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714e7cfb082496967f7ec22eb74dea33d78388ca084d35bb754ab5256d4d606d83818f639d0c63dd541": "0x040000000002000000000000000000000000000000001145617420596f75722043727970746f7300000019656174796f757263727970746f7340676d61696c2e636f6d00001040656174796f757263727970746f73000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714e806de170873b7f5bc955504a40c50ded178a8082516a78a68f503348c16b106fb2a1aa2c594743e": "0x04010000000200000000000000000000000000000000074d616179616e0e4d616179616e204b65736865741468747470733a2f2f6d616179616e6b2e636f6d14406d616179616e6b3a6d61747269782e6f7267136d616179616e406d616179616e6b2e636f6d00000e406d616179616e6b6573686574000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714e8132b78f5a4f887e6c77cda38a3c7f46fa96464dccc96f4d36f31ba1f4487c06dc83b5c8e45ad04": "0x00000000000000000000000000000000000f4b727970746f686f617264696e670000001364616d6f6d616e6740676d61696c2e636f6d00000d404b696e674461736f727461000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714e816cc3d6733171beecf668b36de6a7e53932f2a13c6e7a76ba18de1293eec95f2ab73259ccc9461": "0x04040000000200000000000000000000000000000000076c756967686f000000136c756967686f393540676d61696c2e636f6d000009404c756967686f31000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714e82fc91783bf46accadffbe2995ae2867e82d0509dd5b7e3f392bcc1c3f72d5c7c22b6992cea506c": "0x00000000000000000000000000000000000a506978656c20417274054e465473010101000001000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714e842dd34520b9eb24cc814dbc865ac0e41bf2d9c39177665f32cadb7d01093e2ad40cdca1d40b53f": "0x000000000000000000000000000000000015427564647920486f757365206f66204368616f730000000000000e404d6161743734333936343630000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714e84a92dfe79fe371cc16be5e77dbadcc7038bd9d447475d68dc4a9af67e3ecb92ca374c7cff9365f": "0x0000000000000000000000000000000000064d6172696e00096d6172312e646576000e6d61723164657640706d2e6d65000009406d617231646576000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714e85d0bcdbe07f1da309409e68f563d9e9160bc30f7418cbe5735e3e2dc9922db1826807029b8ba5e": "0x0000000000000000000000000000000000104d61785f43727970746f7a696c6c61044d6178001c406d61785f63727970746f7a696c6c613a6d61747269782e6f72671963727970746f7a696c6c616d617840676d61696c2e636f6d0000104043727970746f7a696c6c615f6d670009406d61785468656f00", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714e866dbe58dd02dc15480a8c33e4f8c5fe4fc96bf837793ce57e7e01fc24f3e49380c1da287dd0942": "0x000000000000000000000000000000000011506f6c6b61646f74205065727369616e0e4661726465656e20486171756500001968617175656661726465656e353040676d61696c2e636f6d000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714e86ac2d54fd84df0f4914e62f037cdb798c40ea01fd56e555b77635e0e9b7175b98bc9514021756c": "0x04040000000200000000000000000000000000000000094461726b737461720000001c6461726b73746172313938324070726f746f6e6d61696c2e636f6d0000114044466f726b6c6573736e6174696f6e000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714e8937a43ac980f1586f33a7ca64a28019e30c3d51516a96b2b2ac8686a25b6bed4d8755dc865d317": "0x000000000000000000000000000000000007726f6737333313526f676572696f204420466167756e646573000011726f6737333340676d61696c2e636f6d00000940726f6737333331000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714e8b0540980af6a340eecdc6635148c341055535da240f7acccb21659afb5aee9f9948c99359f3439": "0x00000000000000000000000000000000000d53616e63686f2050616e73610a416c656b73616e64720000177361766368696b2e776f726b40676d61696c2e636f6d0000104063727970746f617065735f6b736d000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714e8ea76be2017f4a28655c4ccb0364b450b7d2061b3c8dc099342216338374f2480b91cdb49c1033a": "0x040000000002000000000000000000000000000000000a6f67756e6b7563616e000000146f67756e6b7563616e40676d61696c2e636f6d00000b406f67756e6b7563616e000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714e8eb9b60e1513484462331eafa624d8d83071075364f17bd15016b013864863fff94db04a29deb56": "0x04000000000100902f50090000000000000000000000000000000000000000000000000000000a4d4943484953414d410000001a6d69636861656c2e7361726e69747a40676d61696c2e636f6d00000e406d696368697361726e69747a000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714e8f8b7184f9a04c0ca72d01b6c36c383e4ba984681b7b467dafefec8f44dab1ed507ae6ab2704c30": "0x00000000000000000000000000000000000a307854617973616d610000000000000b4030785461796c6f725f000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714e905397499085a5cd08b2f1e5fe95f103948c86163819e4cc144ab447ba4018277b63592ab942b29": "0x0000000000000000000000000000000000076e69636e616301136e69637363726561746976656c61622e6361011a6e69637363726561746976656c616240676d61696c2e636f6d000011406e69637363726561746976656c6162000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714e907703340da1e8f2e0b113a373a48400516429c6d481bc521ae1784536e67ad6208da18d4d0df19": "0x00000000000000000000000000000000000f42494e414e43455f4b534d5f32300f42494e414e43455f4b534d5f3230000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714e93245b557944f937e6a72893ffcd787d41621e01d10074d0d1425d910ed402a489111173fec4113": "0x00000000000000000000000000000000000e4173686c6579204475507265650e4173686c657920447550726565187777772e7468656173686c65796475707265652e636f6d011b6173686c6579407468656173686c65796475707265652e636f6d000001000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714e9422a057a1bb64b70c74263021641934d8ead99b5f41c35cef39e6381314c3b0818941196cebb35": "0x00000000000000000000000000000000000f42494e414e43455f4b534d5f343900000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714e944e964592233816e6a5f27e6e082241bacc990628ee760ceaee069a8a67c753d8018f040f31703": "0x00000000000000000000000000000000000b526f6c6d696e61746f7208526f6c616e646f010119726f6c616e646f676c7a3139383340676d61696c2e636f6d00000c40526f6c6d696e61746f72000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714e94531e277a1ad52dcb38c186bf97625f108b4832981d966ebed50d939349d4437a6f538d40d5676": "0x040000000002000000000000000000000000000000000f57696c64436f7573696e2e636f6d0000184077696c64636f7573696e673a6d61747269782e6f72671c77696c6c692e7365726b6b754070726f746f6e6d61696c2e636f6d000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714e94ce4f5193d45cf523700038ad442ddbadaa480e8faa91c55e9c0c4af0e2f76fa05c0a69065bb72": "0x00000000000000000000000000000000000d426f777365722053746178780000000000000d40426f777365725374617878000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714e9521ce485bf220366a4d150e1799ed9ffa721e7e95397c4484db801fb7f26fbc4f27e1d158ef839": "0x0401000000020000000000000000000000000000000004545831000014406f6c6567616e5f3a6d61747269782e6f7267116163656f6c6d4079616e6465782e7275000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714e95a2208b7916b225ce252657fba00b03c44e644c81a7c49f72fa99ec13aad281507b60c599bb82b": "0x040400000002000000000000000000000000000000000a6b61796c6132303231000014406b617977616e673a6d61747269782e6f7267136b61796c61406c6974656e7472792e636f6d00000e406b61796c6177616e676e6f77000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714e964b9924326e5859a226ee3bd37742f15c3dc4d267c60397718524d88a1fcab129877e2933c675c": "0x040000000002000000000000000000000000000000000d4d616e74726920436c6f7564000018406d616e7472696e6f6465733a6d61747269782e6f726700000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714e965b8ae173f1e967eaf727c21c8d3283dc379bd1241c2ac3ac744966bf2412ae8d7979a87894550": "0x00000000000000000000000000000000000d426f726e20696e204d657461001e7777772e696e7374616772616d2e636f6d2f626f726e696e6d6574612f0015626f726e696e6d65746140676d61696c2e636f6d00000c40626f726e696e6d657461000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714e9705190c69f75e984a135c14c92b678df586c20c8e3ca3511043f0dc8bfd88017d0bb97bfcff63a": "0x040000000002000000000000000000000000000000000a476f6c44204a615773000000136a61756d6540676f6c646a6177732e636f6d00000c40476f6c5f445f4a617773000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714e98578a74df70c3f7ef355626ce3b4bc8af2d9db491ff132f0127fbee6133a00ed09ff161fc2f70c": "0x040100000002000000000000000000000000000000000f4a61656c20522e2042616b617269001868747470733a2f2f6a61656c7262616b6172692e636f6d00166a61656c7262616b61726940676d61696c2e636f6d00000d406a61656c7262616b617269000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714e991a1b779e8a17838ae9a751c06cfc8b4bfb06f4d0b8d88df80fc88317415ad6f1b9bb6ca114941": "0x00000000000000000000000000000000000b4441524b464f5245535400000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714e99a82a5baf61a80de039a1751705e01c71d2be0ba56442f016e7cfbd1f71e9fdf4d0dc0ededf87c": "0x00000000000000000000000000000000000e45766572647265616d536f66741145766572647265616d536f66742053411e68747470733a2f2f7777772e65766572647265616d736f66742e636f6d0000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714e99e99015b0c69cb32da9fa3f73d7e9b211d6808b7bd15d9daa8a7372b48c13322a7371190793f0a": "0x00000000000000000000000000000000000b4b442053696d706c65780000000000000b4068756d626c656c656f000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714e9a6cafc1c447d4fc2a82d0740d343bbcf853665019f2afe81ddeb884f76dbb5c74533610f72a732": "0x04000000000200000000000000000000000000000000114c65707265636861756ee29898efb88f00001c40706f6c6b616c65707265636861756e3a6d61747269782e6f72671b69726973686c65707265636861756e4079616e6465782e636f6d000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714e9a810681c9b059d2a343a2b14c98d087a4cea739c23d62d9db79ed4933881d78a3ac20bab83766f": "0x000000000000000000000000000000000008506564726f203100000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714e9a8697c66e5c9b7b8e39e87c0fec96f7d012d31a4c27b44bfb504ab359662112e4270e380c84341": "0x00000000000000000000000000000000000f647a6d697472792d6c61686f64610f447a6d69747279204c61686f64612068747470733a2f2f7777772e636f6d706f7361626c652e66696e616e63652f1b40647a6d697472792d6c61686f64613a6d61747269782e6f72671b647a6d6974727940636f6d706f7361626c652e66696e616e636500000f40436f6d706f7361626c6546696e000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714e9a938ca9a4abd3102b2b0de562a79b5ad9c666c3f9e7752955f3b2c2b4a17c71125b2668ea9ce5a": "0x0400000000020000000000000000000000000000000007676c692e616c00001240676c69616c3a6d61747269782e6f72670e6b7573616d6140676c692e616c00000a40676c696f63797465000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714e9a948cc19db68dda45d1343d565c182e0e1cd3da2d6c0b1ab5b17a77ca165457d9620db19439a64": "0x00000000000000000000000000000000000b4441524b464f5245535400000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714e9b38311201d0c95cc79494a220a3cbaeb376cb092a438dffe13a31923d884592f34bfb0c4a8a447": "0x00000000000000000000000000000000000c576f6e64657277696c64730d4a6572656d792042616b657210776f6e64657277696c64732e636f6d0020776f6e64657277696c6473406a6572656d7962616b6572617274732e636f6d00000a404a6572627a576565000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714e9b876e9759b44dcc4d56916477150c0fe18c59b3fc21ed58a435a7fbf27c391353a1a4bbf90d305": "0x00000000000000000000000000000000000552616b750552616b7500000000000840307872616b75000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714e9c3058e8b7da671be86d32d322797f67dd5d386d29d8285cb32504a767956fc58ed8f04ff703c4a": "0x04000000000200000000000000000000000000000000057475677900001440747567797475723a6d61747269782e6f7267107475677940616d666f72632e636f6d0000094074756779747572000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714e9e499f3604f59e52c7807a22744a056fbecff1ecfbe7eba8b1936dde4dc054417c5cf2562bc2b0d": "0x0000000000000000000000000000000000154f6f2d626c612d6465652d6f622d626c612d646105f09f94a500001a6e656d6573697364656675656e746540676d61696c2e636f6d00000d406b696e676d6f6f73616d61000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714ea141d97c8b7bff6a84f5ec52d8e52699f686e95df25a2350fc0b43df597617b09e8f0a5e45be779": "0x0000000000000000000000000000000000064a6573757300000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714ea37edebb810a51f664657582db1ee9d6b05c183b0bf9d05794c88b96fd98ffabf1e03524a079f07": "0x00000000000000000000000000000000000c5068616e7461736d616765001e7777772e696e7374616772616d2e636f6d2f7068616e7461736d6167650000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714ea3dd7f24f32b641be7ed37a86e99b9c1197ff8fa3a5e4b6403b540196f6cd09af2fbc43ea9a5773": "0x0401000000020000000000000000000000000000000011776562336974616c792020203b2d29290a776562336974616c791f68747470733a2f2f776562336974616c792e706f6c6b61646f742e70726f0017776562336974616c7940706f6c6b61646f742e70726f000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714ea41c7234ed3632dc50f089e43c19f3f4ce606cd994bbecc50bf8dc53e970c0c1c592304f651966f": "0x040000000002000000000000000000000000000000000f466f726b6c6573734e6174696f6e0000001868656c6c6f40666f726b6c6573736e6174696f6e2e696f00001040466f726b6c6573734e6174696f6e000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714ea5174161abd84b3180e530fef04fbbe11194fb02ee20db23f2c6f1d5ab928cca1e1c6b4c1d9812b": "0x0000000000000000000000000000000000086d796b736d363900000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714ea659cd23e1b406c58efadc57a1952fc5829948986e5b86e2b7873ee16510800628e8bfd0344ac5a": "0x040000000002000000000000000000000000000000000d444f545f4b534d5f504f4f4c0000001577696c6c6f6e6c79323340676d61696c2e636f6d00000c4057696c6c79536f6e3233000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714ea6e9e7ff4584b959e5ba1a3731a16d3b5c632a184389a6e63f53fd33bc1f099f8973549b2e45818": "0x000000000000000000000000000000000009537469636b69657309537469636b69657300000000000e40537469636b696573524d524b000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714ea707eb9aaeed5b71ecccf5102c89a45733719ed85e43885b5354623e6e90ccc488ba2773a6d737a": "0x000000000000000000000000000000000007425453756c6c114272616e646f6e2053756c6c6976616e010117627473756c6c6976616e393140676d61696c2e636f6d00000e40627473756c6c6976616e3931000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714ea93374d7f1324e97e131d8f9ad19a2ca2dde965022455099c4e35f369fab9a66717bb32dc5b821c": "0x00000000000000000000000000000000000a5a454e5449454e54530b5a454e5449454e5453201f68747470733a2f2f747769747465722e636f6d2f5a5a656e7469656e747300145a454e5449454e545340474d41494c2e434f4d00000c405a5a656e7469656e7473000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714ea98afdd050adf1030b7a3a137092d0c4a8f82cec3a75dedd955c4f0547467e659c07dacbf787f7b": "0x00000000000000000000000000000000000644584d4f4e01010101000001000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714ea99648ce61b6d52d86dba437fa4388bc312e57328e808cb1d37cd49143b90c338714703867edd7a": "0x0400000000020000000000000000000000000000000015f09f8d8041524953544f5048414e4553f09f8d80135079746861676f726173204361706974616c1f68747470733a2f2f7079746861676f7261732d6361706974616c2e6e65741b407079746861676f7261732e632e693a6d61747269782e6f7267207079746861676f7261732e6361706974616c40747574616e6f74612e636f6d00000e405079746861676f7261734349000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714eaa1427619fd84d8aefc61195d8e3f213b241816aace9f79fa086f868616c9892555158be75bc252": "0x0402000000020000000000000000000000000000000007537562426f78094b6576696e53756e1b68747470733a2f2f6769746875622e636f6d2f7375622d626f7814406b6576696e636e3a6d61747269782e6f7267126e6f346c6f6e6740676d61696c2e636f6d00000b406b616968756173756e000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714eac64c1f4e558ab7d60c75740987ee89dac9107fb640ad94539c0aa174a045bfd788ba367246c00f": "0x00000000000000000000000000000000000d4d756c6c65722042415349430e446d7974726f204d656c6e796b0000196d64622e63727970746f3230323140676d61696c2e636f6d00000f40446d79747279694d656c6e796b000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714eacb05ddd012a5e58ed26dda286bde16d2dd807510bd269c8cebd598bbc85a528a87ce2a86123123": "0x00000000000000000000000000000000000c435f70657373656c6c696e0a63726973746869616e00001d63726973746869616e2e706573656c6c696e40676d61696c2e636f6d000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714ead73865098b4e268cbdf5f8b94b1e3e50d5258a934f3f005ce2ab97c47af0fae918b1135e29b67c": "0x040000000002000000000000000000000000000000001452656b7420537472656574204361706974616c0000174072656b747374726565743a6d61747269782e6f72671872656b747374726565746361706974616c40706d2e6d65000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714eada65ead440e226c0e28f6cce9440f36b1e0218286e2d618d3a96c63321eeafc17aaeaa627bbf5d": "0x0000000000000000000000000000000000115468654375744c6f737353747564696f115468654375744c6f737353747564696f155468654375744c6f737353747564696f2e636f6d001b7468656375746c6f737373747564696f40676d61696c2e636f6d00000f404375744c6f737353747564696f000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714eb447064e6bf7505cec975ab53753aa239ab05d83392a564b6b26fcde4b1e07b1e5a692d011e3428": "0x040100000002000000000000000000000000000000000f4d696775656c204d617271756573001d68747470733a2f2f74696e7975726c2e636f6d2f7963626f3479786315406d722e62726f776e3a6d61747269782e6f72671b6d696775656c2e6d617271756573373040676d61696c2e636f6d000011404d696775656c4d6172717565733730000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714eb7cf6adf6bf0eeb8a69eee1f91f7a4c18dd0f200bf9dab5149f0b5131d144024fd8d91fce375860": "0x0000000000000000000000000000000000164d79427572676572427261696ef09f8d94f09fa7a0001b68747470733a2f2f6d79627572676572627261696e2e636f6d2f00186d79627572676572627261696e40676d61696c2e636f6d00000f404d79427572676572427261696e000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714eb8a84fc1f2672fdf6eed613aedc88afa977c2982319ee6fbaf9aec7f8a285ce88f08c0dc84d4b0a": "0x0404000000020000000000000000000000000000000009717571757a6f6e6500001540717571757a6f6e653a6d61747269782e6f7267116c656f406c6974656e7472792e636f6d00000a40717571757a6f6e65000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714eba9e3af1be4519454d7eca7197b7feb6cc79725fcf5b873f1495add94c771682584d7d254163713": "0x00000000000000000000000000000000000a476c6f62616c45524e00000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714ebb9d8077a7da3fe98672c4edf6d578c3151aa2e8d55431cc874360eff95c4592d917fb09a6b6316": "0x040000000002000000000000000000000000000000000a4d61676963205461620000001564656e7665727437383440676d61696c2e636f6d000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714ebc3901876e1bb583cdf41f721ca5269ae0eeb4343cb60721fd8cbac7022328cf959d7c3e728d969": "0x00000000000000000000000000000000000547656172184765617220546563686e6f6c6f676965732c20496e632e1a68747470733a2f2f7777772e676561722d746563682e696f2f001368656c6c6f40676561722d746563682e696f00000c40676561725f7465636873000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714ebcbc6c0c66547df8c4c81f382ae2c201eed4b0b519f352aa9c0c8593122418b30ac9760844de2fa": "0x0400000000020000000000000000000000000000000009436f6c6f73737573001a68747470733a2f2f636f6c6f737375732e6469676974616c2f1d40636f6c6f737375732e6469676974616c3a6d61747269782e6f726716696e666f40636f6c6f737375732e6469676974616c00000f40436f6c6f737375734974616c79000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714ebe794990a349ea52ee8bb0f7ce771455d55e6bb0908b243c0c4805e6733c0ebbd91bea2ff5a4526": "0x00000000000000000000000000000000000b6a75636163656a75646f00000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714ebee8c2dc7e37890e84b20a21cd1f35835bb85d8e27d3b6d02bf08300998555443ec4cd3206ec37a": "0x0000000000000000000000000000000000114a757374696e65204372757a204172740d4a757374696e65204372757a010115726a6e65706f6372757a40676d61696c2e636f6d000010406a757374696e656372757a617274000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714ebfc2e29a73f2803cc1ba006a1715e894b621a36169165cb72343b1c6ad4ba2230d394be4033a645": "0x00000000000000000000000000000000000e7765616c6c64697361677265650000000000000f407765616c6c6469736167726565000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714ec33a2010bbc1c6a108079cf7fc4da7010feec2a6d3435947ca526d185fffa4c13b816eb9d38a107": "0x04040000000100902f5009000000000000000000000000000000000000000000000000000000046d656c000000126d656c7a406c6974656e7472792e636f6d00000b406d656c5f7a686f7531000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714ec3c3e9502045f3b68c1fc61924efb992b4e4c2c7a21d528dca21d3073fd304f536fd99a5cf1794a": "0x00000000000000000000000000000000000bf09f9088e2808de2ac9b00000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714ec423cda65dba1eeb21a6e8672731908c93ced8be633bb99e8535a8af267463d92a2dd37b6999e4d": "0x000000000000000000000000000000000011f09fa5b04d414d4143495441f09fa5b000000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714ec514a5caaf1ccf5be28e6585d6eba8b92193cdbeaa65fbb64f3b22a2f3043481f088e875f8fb816": "0x0000000000000000000000000000000000086265656a616579094f6c616b756e6c6500001262656562616e7140676d61696c2e636f6d00000d4067616d656f666761696e73000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714ec9971789d54b940607b422f959ab305856c1621be625a1776d2ffddfac9a03446da3052d7cd3a58": "0x0400000000020000000000000000000000000000000009434f5645524c4554000013406164653030373a6d61747269782e6f72671461646576617261747540676d61696c2e636f6d000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714eca845b41c8481b56a54690cc83eb7ead60699dddf84173f229fc713de735bc849b0b5d0164d971b": "0x000000000000000000000000000000000006676b686e3000000000000009403078676f6b755f000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714ecb301dad8fcf04b9e1f6008fd792e78fa56b6ae00b4f8b73b98d260ad04b38623d1a3423ada0957": "0x0400000000020000000000000000000000000000000004616e790000000000000a40616e796441707073000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714ecc10f82c1c9c473fe7ecf56bcdfd2f5c5570574eb8971fdc5b2ff7d929767b730066666a1493177": "0x00000000000000000000000000000000000000000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714eccde6810f3e4a3bbae434c3ce18cf1d398e23149fcc31fd5997284a7812839ca3bd6b477f449565": "0x040100000002000000000000000000000000000000000b4a6f736570685f4144561b6a6f736570682073616e6368657a2076616c646562656e69746f1768747470733a2f2f6269742e6c792f334d614f675741001b6a6f736570682e73616e6368657a2e7640676d61696c2e636f6d00000d406a6f736570686873763231000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714ecd56384808aea349692fa834a36faff24619a5a9559ce35082ea5247cfb0657e8ce2fe5fcce2d3e": "0x000000000000000000000000000000000007534b554c4c5a0000000000000c40534b554c4c5a5f585858000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714ece0cbfbc8b2ac0fb69dfe53765f807ba212f4c0f8c5f2c557143761c734f58ab36f1a584d77592f": "0x0400000000020000000000000000000000000000000019f09f939c20486f6c7920436f6e73656e73757320f09f939c000015406d6f67696f6d616e3a6d61747269782e6f726700000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714ecf2bd08370f7bd96c1c4ce21343d4de9268561b0872178a5f017362e2632e6d4019b17e73fd9a5b": "0x04010000000200000000000000000000000000000000134d2d5665727365204152542053747564696f064e696b546f18687474703a2f2f7777772e72617269746574732e636f6d001a646d2e646f6c676f6c65742e62697440676d61696c2e636f6d000011405579326c384547644677514d4c474a000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714ecfb9de5210ebb4164f5867915d7d9c1a1f95f772891efe46ada7f2c25a7124c55c7d08bcada7250": "0x00000000000000000000000000000000000a536576656e2041727400000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714ed170e36fed4d7829c7c545141ea2dd84fe5ef7d567ea450f59967e7afa68e5f1ff7f7c46db19627": "0x04010000000200000000000000000000000000000000085032502e4f5247085032502e4f52471068747470733a2f2f7032702e6f7267000f6c657473676f407032702e6f726700000e4050325076616c696461746f72000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714ed2422d97d69412f3848140170bdea2ed343c6cde80ba53793d9158f57f7160e5f5d78b1ac2ae124": "0x00000000000000000000000000000000000c4d61657878696d697a65720000000000000e405f6d61657878696d697a6572000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714ed256f19624cd5e520bdacc287bbcbea07e8fad8f43e5dcb222c425acd92d88da92131542f706827": "0x000000000000000000000000000000000006534b41455201010113736b6165726e667440676d61696c2e636f6d00000b40736b6165725f6e6674000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714ed28496342047e2cd2a250fe4fd3437ab1adf1aaecfa369933dd022c08ca5c5718a4843cf7fbfe32": "0x0000000000000000000000000000000000076b7573616d6100000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714ed2ea848bf9923e24a53c0383caec5273b6cd82cd4c343130767c2550df0fec0c5c7c76db58ded61": "0x00000000000000000000000000000000000d466f756e646174696f6e2e5a00000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714ed3dc3fca3bb7956b608ce37459ac5d38405203ab8b429207b21fe8aac7ee28aa964da0ae12fc970": "0x0000000000000000000000000000000000116b616d616c61696d6d6163756c617465124b616d616c6120496d6d6163756c61746500001b6b616d616c61696d6d6163756c61746540676d61696c2e636f6d00000d404b616d616c61496d6d6163000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714ed614c0e929782758c5359d2bdc1550dc83587f9fca8a411099eab04cc37f8d3480c0bc2daca9f4c": "0x00000000000000000000000000000000000f426c6173c3a920426f6e6f626f730000001b626c617365626f6e6f626f2e6b6e667440676d61696c2e636f6d00001140426c617365426f6e6f626f734e4654000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714ed61cc174562abef5a9635e41381688cc05f8f2a2abc1d3a020f4f6726998721f201a3e3fe061336": "0x00000000000000000000000000000000000e4b5553414d41205748414c45530e4b5553414d41205748414c455300000000000e406b7573616d617768616c6573000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714ed782455066cea4ee6f56f064baa721a0d8d32e52c80ddcb1f3ec711b3535f6ab6ee30510b88824c": "0x0000000000000000000000000000000000064162616e64000f68747470733a2f2f612e62616e640000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714ed9f378fe91a8125c4de4f9f5568e51e59a99d289673364dea82a180b4cff619e121c1ebf4e42735": "0x00000000000000000000000000000000000b43727970746f436f6f7000000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714edb9597552dee00bf6e36d6ffac19bf2cde9b8a6189939d02019b614729f72aa3fb4e95c5460b95c": "0x00000000000000000000000000000000000b505249534f4e455253200a574f524c445749444500001b707269736f6e657273776f726c6440686f746d61696c2e636f6d00001140707269736f6e6572735f776f726c64000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714edbd8e7a024325c3c0b08670875a44574a20f29df8e415a84e87548aee41a90dca4de6dace851c06": "0x0000000000000000000000000000000000057065726c000000137065726c6c676c6740676d61696c2e636f6d000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714edcb62732d88d5a1983ac92a9005b595553a62a3522499a38af23ae77e0c71f3b617abf004147e5b": "0x00000000000000000000000000000000000f5041524954592054495020424f5400000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714edd6a8685a4d3345b2bc481201f051dc46499103c6d0947c70967af1dcfacc2b34f5a1065256303b": "0x00000000000000000000000000000000000f416e64726561732053746f636b200f416e64726561732053746f636b202068747470733a2f2f7777772e6269662e64652f616e647265617373746f636b0011706f737440726f6c6c737465722e646500001040416e647265617353746f636b3135000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714eddc9e78603ad40bc8ef2ec23b4f86d82dce53a0569f1f1f1cac8b7eac2a36aae89ab1312720d51f": "0x04050000000200000000000000000000000000000000046d616b00000013746f406d6f7264616d61782e6f6e6c696e650000096d6f7264616d6178000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714edf0122a60d52d7dbc5054d8ce14774d438c9376642f6410f0ec0f9b02c20247923889ec58250227": "0x0000000000000000000000000000000000044f62690000000000000e404469676974616c706c75746f000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714ee0ce2c47daf1aaa5268f1c62243ca2f0e0ca3c43ac74c89c4d4f2aaf3135d5922b38679523b5704": "0x00000000000000000000000000000000000a4675747572654c656f0000000000000b404675747572654c656f000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714ee0e3a74bdfdeb1c92346d7a04f8c10608fff8e59d18ad02f32d018f562d61d58f7b4ed9d42b9602": "0x0000000000000000000000000000000000084b616c6541727400000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714ee2bc658fa0d1fc5fa8edfccb16e4748eadc9c5ec4e84fa3f9cd096b78dc8b6fa28b06e0b4945c31": "0x000000000000000000000000000000000013524d524b61626c65204372656174757265730000000000000e40524d524b61626c654e465473000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714ee37cb203df4b717dae56db2d898e18d0a96a0db1732e27d6c8d2a448649348b3d7b2b7a8b819e00": "0x00000000000000000000000000000000000459534101010101000001000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714ee577071e47d1ba7b8a40f17f9fc62194fe1b12c10e8a2bfb5efc7057b119f4ca3b05ba96eb7da6b": "0x040000000002000000000000000000000000000000000b7374656c6c61726a6574000017407374656c6c61726a65743a6d61747269782e6f72671762696c6c69626f6e7337373740676d61696c2e636f6d00000d405a616b68416c656b736579000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714ee7dbc12bc9252112ebd1171c5fcf0d3387bce6cbb7119410ca169b272b310775b1816de710d046c": "0x00000000000000000000000000000000000a444b2053747564696f01010101000001000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714ee8578075072e96cde26e94d5a74a70872172314f92fb0fd0d1c9fe186c38b594ad50e6079ca1218": "0x00000000000000000000000000000000000000000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714ee877a7a3953392aecdb6dcb19a0a30a0007a4cc863d9a3079801900d0e26493a9712f3a595c276c": "0x040000000002000000000000000000000000000000000d424245574f4e44455246554c00000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714ee89fee2b887b471a8274537b1ed72b005b2ae6e3c0e14273235d9c5556ade786172d842a2059e3d": "0x040000000002000000000000000000000000000000000a50726f66696747656e0000164070726f66697467656e3a6d61747269782e6f72671564696d61676f6c796f7540676d61696c2e636f6d00000e405a616c613131373634333039000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714ee9086e3eb095e4cd80e7cac81873a2f2b98cbe3f9a22fb2c640721759559dc7c074f558f274450e": "0x0000000000000000000000000000000000084269677a696e6501010101000001000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714ee977649867b775e26f6ba0b2c596d1a471444945c9fdbdfe25e3f8862096f8f6de11d87da1a7111": "0x00000000000000000000000000000000000f546865205068756e6b79204f6e650000001a7468657068756e6b79314070726f746f6e6d61696c2e636f6d00000c407468657068756e6b7931000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714ee9be5f0b44a2889287e6f010e50f642775dab59f39ee4de313fe6325181ca603824399cf4d42c08": "0x04000000000200000000000000000000000000000000074d65726c696e000000166d65726c696e6e6f6465734070726f746f6e2e6d65000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714eeb1fc610455dcdf22e0d42710f5fd45705ee39dadbc4a849457777499de8e0b28099344dc31dc53": "0x000000000000000000000000000000000005446f677a0000001763687670786a787264766e406f75746c6f6f6b2e667200000d406d786e65796a787264766e000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714eec11b5fca7cddef5270ec35ba01254d8bff046a1a58f16d3ae615c235efd6e99a35f233b2d9df2c": "0x040000000002000000000000000000000000000000000d506f6c6b61646f747465727300001440706d656e73696b3a6d61747269782e6f72671c706f6c6b61646f74746572734070726f746f6e6d61696c2e636f6d00000f40506f6c6b61646f747465727331000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714eec1d763f95c70cb16eaf9666bd95a04bc6ed619c30a4809a43fd7265e414284c11b27b8c666fd23": "0x04000000000200000000000000000000000000000000084b686173746f72000014406b686173746f723a6d61747269782e6f7267127374616b65406b686173746f722e636f6d000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714eeca900939080fcf9e4e11a50a1089b5e3c69cc838363d16616d94d9efb701ff2f53c08da7fd8062": "0x00000000000000000000000000000000000c46726f7374587472656d6500000000000010406c756361735f6b6f6666656d616e000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714eed3ee9b432687319609bc709020ebb74d5976e8a8632dddb6575b2faf53c0fc541578a0f67ec933": "0x0000000000000000000000000000000000104b7573616d612050726f706f73616c21476c6f20446576656c6f706d656e7420466f756e646174696f6e2c20496e632e1b68747470733a2f2f7777772e676c6f646f6c6c61722e6f72672f00136a65666640676c6f646f6c6c61722e6f726700000b40676c6f646f6c6c6172000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714eed7b5cd81ad90b934bc724bcd5c1a70cf8b27cee684404418666711f575d681780171cb7a1b6238": "0x040000000002000000000000000000000000000000000a66696e616c6269747300001240617269666b3a6d61747269782e6f726717696e666f4066696e616c626974732e6e6574776f726b000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714eedb21dd29e41c9e08862e05b832f2754899119b7a1c9ae77b3a70f67950ba318a4381a78eaa3b57": "0x0000000000000000000000000000000000095361736861646f6b0000000000000d405361736861646f6b4e4654000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714ef04f719a88861a1b08e12e3ae9711ae774eb42da22da000579ed96da9412dcf15c934e7072c287e": "0x00000000000000000000000000000000000b54776565747962697264000002400240000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714ef0a650cbf57826cbe5a0623e6c466eb58b6768fa79f2844a7c3bbec1fbb686efb86159d2884aa10": "0x00000000000000000000000000000000000c476f676f205975626172690000000000001040476f676f5975626172695f617274000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714ef1664294ee5e16e2e266f5e99f682a4439635c39dd3a9a0d8b35131cd0191ae0874b84c472b9e54": "0x00000000000000000000000000000000000f4d6f74696f6e2041707065746974001f68747470733a2f2f7777772e6d6f74696f6e617070657469742e636f6d2f000000000f40417070657469744d6f74696f6e000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714ef171686ae87d77572062f1b364867349593e0708e8b30cdc6f7bde5604d422bfae96ffcd2122d07": "0x00000000000000000000000000000000000830785369676d6100000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714ef2cb41d52259dc702d45a8cec8dc7ffa0ea3341fece5555c72125cfcb5f1664526b3b67bacee47b": "0x000000000000000000000000000000000008612e6b6976657201010101000001000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714ef545c0b52a14ce5fc8da8cd554b5256f00c5e43f8a30b62f77e2d9b34730eb823e819e141c029b1": "0x0400000000020000000000000000000000000000000015546865204b7573204b534d2044656c656761746500000016686579407468656b7573616d617269616e2e78797a00000f405468654b7573616d617269616e000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714ef58128d4ea34ecdcee02f04a44b248f0b7d6cf65d98e1cf6206e73af3e3bd66b2f9a3a9aafc573a": "0x00000000000000000000000000000000000b417263686976657273650b41726368697665727365137777772e617263686976657273652e61727400186172636869766572736538383840676d61696c2e636f6d00000f4061726368697665727365383838000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714ef6f4d8caafffa157a4a576c540eec2cc92a7b102e14205d349e8cb1fad5c68ba8eaba619031b820": "0x0000000000000000000000000000000000106b72616b61746f612d7061796f757400000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714ef7c516a16dc564edcb79cfb39e4a600a5f4782e73f48a4810604e9271ab8e26fb588f0ef4c6472f": "0x000000000000000000000000000000000010546572726120496e636f676e69746100187465727261696e63756b2e62616e6463616d702e636f6d001b7465727261696e636f676e697461756b40676d61696c2e636f6d00000c407465727261696e63756b000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714ef8e518f1522f7a6266cdd851a163dbc01f5c86d9c37b330e1a7bc66adef3ebbc6d59e2c1e61007e": "0x08000000000100902f5009000000000000000000000001000000020000000000000000000000000000000011475241424249545920e29ca8f09f9087001568747470733a2f2f67726162626974792e6e6574154067726162626974793a6d61747269782e6f72671368656c6c6f4067726162626974792e6e657400000d4067726162626974796e6574000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714efed57a5e9a3be1756825262aeddf95b1791f9553de6d166e7d00f337e6db4e9434714bc1164ea01": "0x00000000000000000000000000000000000a446f7473616d614d580000000000000b40446f7473616d614d78000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714f01934f45473693bdc53fda731682da4b15562fd4fe5007eb94dc36215862ca3c59cbb2a13ce6941": "0x00000000000000000000000000000000000f536f756e644f6653696c656e636501010101000001000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714f03497ce90d500570e687e3b4f19439aaa16f96132712ef6b7da695e0fb0844ebd9d0e8b901b8b6a": "0x0400000000020000000000000000000000000000000004303430000000143034306e657430343040676d61696c2e636f6d000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714f035a0d786dbcf44868cd54faea1a0e45836635b2bf658733436ec69c5567d651be592392cbb69dc": "0x040200000002000000000000000000000000000000000d5374616b6572205370616365001568747470733a2f2f7374616b65722e73706163651740676e6f737369656e6c693a6d61747269782e6f72671368656c6c6f407374616b65722e7370616365000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714f048620c32a1d7b6f420fff29f5ae4603668ff450ac4cbb0e7159abd5f5c094c552414a235452940": "0x00000000000000000000000000000000000b616d70657273616e64690a4150204d7572726179000016616d70657273616e64694069636c6f75642e636f6d00000e4077656973656e6865696d3372000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714f04f158721b89173b8ab024c586021c3755f9a592871796b7cf47213b9cf94534dc45e86e5e10e55": "0x00000000000000000000000000000000000a6475636b77696c646500000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714f04f805bb261ed68c0c8a73a690ab59186f16852e70a2406e1690d7d6f18419d0599f6a77a67ff64": "0x00000000000000000000000000000000000d4475627374617264204b534d001568747470733a2f2f64756273746172642e636f6d001c4578706563744368616f734b534d4064756273746172642e636f6d00000a406475627374617264000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714f04fc71c9051dc296467fd4e7038b925c2422357380d8cc0c5f17d272f639af8fcfd1f1156de7040": "0x04010000000200000000000000000000000000000000087265616c6761720d706f6c6b61646f742e70726f1568747470733a2f2f706f6c6b61646f742e70726f14407265616c6761723a6d61747269782e6f72671368656c6c6f40706f6c6b61646f742e70726f000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714f0548bed301be4ead497f54d401fe4c1ef4db2cba6f186f4404256684bf2a521ee1a996f8ed41717": "0x00000000000000000000000000000000000b43727970746f5f4d616d0c5265616c204d6f7468657200001843727970746f5f4d616d6d6d7940676d61696c2e636f6d0000104043727970746f5f6d616d756c7961000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714f055b74881490c4efee7b1c489dd25c0a0e860ddf45d685ae6f7dc9b2653833fad6f6df61dc52313": "0x00000000000000000000000000000000000a506f6c6b61746f646400000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714f092b7bcded3683bf06c3b60a5829f2e3712cbd93b0e13ff0c3501636335339563df022ab1a7f16c": "0x00000000000000000000000000000000000941565645204152540000000000000a40617676655f617274000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714f09bc0b626451c722aa5ba3cdeeff59135a45ca06af01181ad0015f5faf0161a5a9b9c50af228526": "0x00000000000000000000000000000000000e524d524b206f6666696369616c01010101000001000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714f0a0c6f78c3f1dec12210b384d6a6efb1d26a87c58d54edf034e8808df223c74b87ad9d798204b3c": "0x0000000000000000000000000000000000074b6f6f63757500000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714f0a750638d9b7c707658c8264ec0bd92d2493d772b1a6cc1fb7c338f08bafa4338b82e25a6543208": "0x04010000000200000000000000000000000000000000076b6c65766572001268747470733a2f2f6b6c657665722e696f0013666565646261636b406b6c657665722e696f00000b406b6c657665725f696f000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714f0db9ccb0fefbacde2016ad920a3b5d87e07a224e968ab74fe1e802a77c02010a7bd84a9e1cc853c": "0x00000000000000000000000000000000000b6e6b6f6e756b6f763834000000146e676f72656c6b6f7640676d61696c2e636f6d000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714f0ee0b687c5103e11ea2e788aba3561f0b05ba66ceb0aa5b95d9bdef6217e73e2685d744ab28dd64": "0x00000000000000000000000000000000000000000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714f0ee90ce47dd48389a46e76d7d1df5103771b0336b07765a168d2c4a123d08960b3577b39d6e204e": "0x0000000000000000000000000000000000075061706572730a5061706572732041471268747470733a2f2f7061706572732e63680012636f6e74616374407061706572732e636800000b40706170657273446576000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714f1018912203e086b3aa5bd02bbd345acea759dceec1e03e25dc20c3d42fa2518ce315721407fa371": "0x00000000000000000000000000000000000c4b7573616d6f6f6e4e46540e4d616e75656c204f6c6d65646f0000166b7573616d6f6f6e6e667440676d61696c2e636f6d00000d404b7573616d6f6f6e4e4654000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714f1173e4bb4bde3d2f4681dada28e955e70d77fb8ccc3286d5028f0c415be18f6068cd97d921b5824": "0x000000000000000000000000000000000008414b524f20445605416b726f1968747470733a2f2f6c696e6b74722e65652f616b726f64760011616b726f647640676d61696c2e636f6d00000940416b726f5f4456000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714f11f6c8614e661cdd26b6521fa6c7f27940601187600f400efb32375537a401099a582b9c65e0e76": "0x00000000000000000000000000000000000456757300000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714f1352327dc3be8a0948223bb2e7bcc8a55be248add34b625c1c0826c58fe037fa5c8e4591440dc59": "0x0400000000020000000000000000000000000000000007456e7a6f726f00001540726f6d616e7631383a6d61747269782e6f726715656e7a6f726f2e64657640676d61696c2e636f6d000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714f141bc71dafe807f7cd5f5ff9b7eefb11b8b32c1bb1e1fc63c08019d81124b3aa85f24ae8c779a31": "0x04000000000100902f50090000000000000000000000000000000000000000000000000000000e546865486f646c4661746865720f41726d616e646f2043617374726f00001861726d616e646f63617374727040676d61696c2e636f6d00000f40746833686f646c666174686572000e746865686f646c66617468657200", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714f15d5a7f73cec4735a5de862f77220d0aafd75335f986fbc18bb788aa8c4a5b61cc6b46f38a6dd58": "0x0000000000000000000000000000000000094d69636f6c656f6e0000000000000a404d4943304c45304e000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714f1697a69799d08e44211b834beac4f35ff92e0dcbb0167f6ae7a0c43b186727d581d3f69f10fea34": "0x0404000000020000000000000000000000000000000021414d414c4c594e20e29ca8e29ca8f09f928ef09f928ef09f928ee29ca8e29ca800001440616d616c6c796e3a6d61747269782e6f72670e616d616c6c796e40706d2e6d65000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714f1719675644622b35432349797f86c76049b09f36fe855c53d5bb87271a3186300feee6d2c040f3e": "0x000000000000000000000000000000000011576562336761696c206f66506865656200000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714f192451ba2e9b123969f7c9e5a153c9d9965ae28a973fdd9ebc270fe431e04396c711e12c6dc2356": "0x00000000000000000000000000000000000b4d59424553544c4946450e4a6f73696168204b6f747a75721568747470733a2f2f6d657461726f636b2e61707000184a6f736961686b6f747a75723140676d61696c2e636f6d00000f406a6f736961686b6f747a757231000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714f1945f40d5dd3f64e2d9b07342518d0e97bc74b6c54b1773db3081792d43ca2b54bf89b80e899562": "0x00000000000000000000000000000000000d4e4654616d61676f746368690d4e4654616d61676f746368691868747470733a2f2f6e6674616d61676f746368692e696f010100000e406e6674616d61676f74636869000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714f1a63d104e9537d648851bbd377e2584fdfe42e8b048d1537b53bb3d64a1a8eacbfb3dae3032ef79": "0x000000000000000000000000000000000008444f545f4f4e4508646f74206f6e651468747470733a2f2f7777772e646f742e6f6e65000e746f75636840646f742e6f6e65000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714f1aadb00106d1ec596417843ffb52469298959fef42e9153cc81531f708603e74562202f81dfcc0d": "0x00000000000000000000000000000000000a44616573756d6e6f7200000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714f1bcbe1d2866fe7bd01ee8b63206f50cc22749524193d58b84608aa3d895d839e42600fba1167261": "0x000000000000000000000000000000000012e0b98c4e657720436f6e74726f6c6c657200000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714f1d230b68b13fba664c4ce41b56c68a03cf22a7bb36fcd1a1b8678a37e3ac1dcbe8b354a526bc144": "0x00000000000000000000000000000000000f427566662041726d7320436c7562002168747470733a2f2f747769747465722e636f6d2f4275666641726d73436c756200176275666661726d73636c756240676d61696c2e636f6d00000e404275666641726d73436c7562000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714f1ea586879f7ec76f5a68515207a31aaa74c335955fe0e59af6323355169fd925e6fe9c60cba58ba": "0x00000000000000000000000000000000000a4e65777420f09fa68e0000000000000e404d7973746963616c4e657774000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714f1eba20e6d2d881a24558de70c92fafb84da6fc766eab8323bd9329ab7f2d868417418fd32fdd737": "0x00000000000000000000000000000000000e536172697361204b6f6a696d610e536172697361204b6f6a696d61157777772e7361726973616b6f6a696d612e636f6d00167361726973612e6468303440676d61696c2e636f6d00000e405361726973614b6f6a696d61000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714f1fc8f4f6212716380c6961c797a97f52859c85012b39dc1403ea0ef2cde3a48a3ba52a10570f77a": "0x000000000000000000000000000000000005566c616405566c6164000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714f1fd5669b551e9dca43b2797bd4dd454d7fb0870a2a4edd62b39eea0801f6baaf09b05c8634b5a25": "0x04000000000200000000000000000000000000000000074c4547454e4400001a406c6567656e64373334313231363a6d61747269782e6f7267156b7572746f736973407961686c6f6d692e636f6d000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714f2148a94f5867abb148a35cad2b2fe9cf6ffe0baf5f4f2f4ef894263baefead0e797a1e3e6d0a07f": "0x00000000000000000000000000000000000b4441524b464f5245535400000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714f215e5ad123be565c25d2c8739671f166c3885215a4ce4d6c458d6881aa62a47bc31561b9c6bfe3a": "0x00000000000000000000000000000000000b4e6164696e655f282a2900000000000011404e6164696e654d6f6c6c656e686131000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714f22fdb49d209542deec7098fe8a74adfd10b30379b411db2b7cef5389c589c6b68e41ca87a28b45a": "0x0000000000000000000000000000000000086b72697875733100000018316b7269787573314070726f746f6e6d61696c2e636f6d000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714f23d10c93f96a6ea7a2f3dc66d99575366f71c0de336ae877563eaa12c52abcc227bd8e990679443": "0x0000000000000000000000000000000000054c655469074c657261205400001056767431393836406d61696c2e7275000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714f23f862ecfa6f61f9cd77599356c6f5f72c36e612c088e526b92fe762a6a175b387df98ea737fb2f": "0x04000000000200000000000000000000000000000000144a6f726d756e67616e64204c616273f09f908d00000000000010404a6f726d756e67616e644c616273000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714f24d4d1adb36534d96f7daa1a00790f8b168d3db7f0175e5f8dfd3430dc7edb4c5b807bce2b9d93a": "0x0401000000020000000000000000000000000000000016e29caa20646f747374616b65722e70726f20e29caa001668747470733a2f2f646f747374616b65722e70726f1640646f747374616b65723a6d61747269782e6f726713696e666f40646f747374616b65722e70726f00000e40646f747374616b657270726f000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714f25ef82af77881fe240cc50e90684f175ebef583b904fbc0b9aef4b38aaafd53e6436ad3e70ba366": "0x040000000002000000000000000000000000000000000c477265656e20436c6f756400001840677265656e2d636c6f75643a6d61747269782e6f72671f677265656e2d636c6f75642d6b7573616d61406f75746c6f6f6b2e636f6d00000f40477265656e436c6f75644b534d000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714f268c9b97db7d42c36cd0bf4fb6d819171d9932d99299cc655a5debfb04d20aa5ae23649372e4f0f": "0x00000000000000000000000000000000000b43726970746f696f74610101010100000d404a6f736570526963617264000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714f281211dddf4de4c9804585392c70a2327e2f8047f73e66dfefaaf9e9ec544d7694b053774e4d014": "0x0000000000000000000000000000000000144d7920736d616c6c20636f6c6c656374696f6e00000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714f2852cbaf60c5e38269fa27098d88ecb1640185c91860fb62d92ae9a6ab7713c79485bae49862b39": "0x040000000002000000000000000000000000000000000b45584e4553532e434f4d0000134065786e6573733a6d61747269782e6f72671576616c696461746f724065786e6573732e636f6d000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714f2974ec4b5ddb395262da7eeb6f3e8342c04cbbf83f9cbc933d86aa980b53480a9e283668b73903f": "0x0000000000000000000000000000000000044c656f0d4b726973204d6f786e6573732168747470733a2f2f73696e67756c61722e6170702f636f6c6c656374696f6e7300196b7269732d6d6f786e65737340686f746d61696c2e636f6d00000c404c617a795f4c696f6e7a000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714f2b06e2ea680db3c12d9c0035dd422388e6d346f61df3d9f3667f8ab761c8c57120dd61917976e10": "0x04000000000100902f50090000000000000000000000000000000000000000000000000000000f4e757220736f20616d2072616e64000018406e7572736f616d72616e643a6d61747269782e6f7267166e7572736f616d72616e6440676d61696c2e636f6d00000d404e7572736f616d72616e64000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714f2cd0e6538047668a88e885b627a179f8a843e0765c142ef41b0d6a9c7b0f178fb1c208a1631ab0f": "0x0000000000000000000000000000000000096465636f6d383838066465636f6d1868747470733a2f2f6465636f6d3838382e7370616365200010383838406465636f6d2e737061636500000a406465636f6d383838000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714f3199d5f1f3efb1568883556ebca8ab4e219f9b9b122deac5f8a041091b7272e68209638c290a757": "0x00000000000000000000000000000000000c56697274756f7a5f41727407417274796f6d00001662626b6472617274796f6d40676d61696c2e636f6d00000d4056697274756f7a5f417274000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714f31ecd1e7a1b8236862fdfefe655dc35f3ac0b586e274ea252d32e5ad1e189c0b750facc56ed5f2a": "0x04010000000200000000000000000000000000000000104c6f79616c2056616c696461746f7200001c406c6f79616c2e76616c696461746f723a6d61747269782e6f72671a6c6f79616c2e76616c696461746f7240676d61696c2e636f6d000010404c6f79616c56616c696461746f72000f6c6f79616c76616c696461746f7200", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714f32bbb6fec42f4b03e89cc7fecc4ad46cd7ba606522a8d1679863da498718cf9acdafbde8cfe4b78": "0x00000000000000000000000000000000000b4441524b464f5245535400000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714f35a7cac67fba21d5aafb1f14904ee2cef477907d825f744a980129c6ff4c0a8a0fdb6279b5ae42a": "0x0400000000020000000000000000000000000000000018f09faa9e612073206820f09fa799e2808de29982efb88f00001c40626c6f636b636861696e637572696f3a6d61747269782e6f72670b314039373130342e646500001140626c6f636b636861696e637572696f000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714f37856c39e7d3aecf6729fb77338a94fd452c6455ced46c78844e967c3d3c7f45e176c38fafcd252": "0x040000000002000000000000000000000000000000000e56616c69646174696f6e44414f00001040786e693a6d61747269782e6f72671b756e6f7264657265645f73657440747574616e6f74612e636f6d00000540786e69000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714f37d13738f231aef9448479aee4be9b14df6c206964e8c9a41d990876f3fd02e189c81c7b59bd718": "0x000000000000000000000000000000000011446561642043616e61727920436c7562000000196465616463616e617279636c756240676d61696c2e636f6d000010406465616463616e617279636c7562000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714f3912249e16d7dcd3c5db0048c1bec2061c55ac6337fd40b995f0c0632c65d2985e607c34564f84d": "0x000000000000000000000000000000000006616d7572690b4f6d61722048616d69641b68747470733a2f2f7777772e6f6d61722d68616d69642e636f6d00146f6d6172406f6d61722d68616d69642e636f6d00000e406472616d75726968616d6964000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714f3b9e4d61581e2eca44ec60e8eb57e646921f1be1696bb0070169f1b55e6d976ea780ad4ceeaf32f": "0x00000000000000000000000000000000000b436f6e74726f6c6c65720000001464686172723931383840676d61696c2e636f6d000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714f3bdf92c808f3f22c68d6466972eb0ea83776198b4d770f8ec90104edf41d423329d403f541b5c1b": "0x000000000000000000000000000000000013547269636b79204e4654206f726967696e7300000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714f3e3959f84b063bcd6c29a7c39cee45b0e045a94081bc188ef73be2be086d66aefd850fc7eeacc45": "0x040100000002000000000000000000000000000000000ff09f9a804f6e46696e616c6974790f4f6e46696e616c6974792e4c74641668747470733a2f2f6f6e66696e616c6974792e696f124069616e68653a6d61747269782e6f7267156b7573616d61406f6e66696e616c6974792e696f00000c404f6e46696e616c697479000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714f3e86d44b0be98b4a485954cd0953248bfb4b47acf3124fe37bea4dd7436eb7286de6fec053b3437": "0x0000000000000000000000000000000000075a6169626f6e00000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714f3e912dce83414234c68f2680db04620157c7367e987bc1b502cc6e1512174de56e7839d05b16456": "0x0000000000000000000000000000000000114572726f6c204a6f686e736f6e204a7200000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714f3f6fc5915e7ebb79c5ccc281c8aadc84dde78cd7904bd5abd05211edb1aff353d9b0ec1455d380e": "0x0000000000000000000000000000000000074865726d697400000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714f3f9a9fea1c2bb71688f2dd2918739ffc90f280131b7d8bbfeaf9f0e2bacfe952a88bfa3bc168045": "0x040100000002000000000000000000000000000000001052414449554d424c4f434b2e434f4d001868747470733a2f2f72616469756d626c6f636b2e636f6d0015696e666f4072616469756d626c6f636b2e636f6d00000d4072616469756d626c6f636b000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714f3fe45df61eadb158e5dd2b0d1bbcb01196506ec753353b2698fa64d77e039c66bc43c747b375d0e": "0x00000000000000000000000000000000000862696e616e636500000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714f419f736dbf31d4544c2fd9d2cc17606f93644a75086320a77c729a97553d33b8c602b7304d82d08": "0x00000000000000000000000000000000000778616d65797a01010101000001000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714f42b57bfe87de580d6aa438803d5e6ab28efa5ef6f3b3dd1fc1442497fbdafad37851a62c1788c2d": "0x00000000000000000000000000000000000d5265626563636120417274730000001e726562656363612e6b7573616d612e6172747340676d61696c2e636f6d00000e40726562656363615f61727473000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714f4336ef56b1e116e966f06ede01dd4af9033cfce763ed647dad15ada85991dfa54ade147757b8346": "0x000000000000000000000000000000000005526f727900000015726f72796d6f7279393640676d61696c2e636f6d00000c40526f72795f4879706572000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714f43f187b68ff5147b29d3aa12cda294b6d5ea963d35f23e9afbc188aff49262c4903bb7b4dc04b1d": "0x00000000000000000000000000000000000f436c696d6174726f6e4143496e6313636c696d6174726f6e6163696e632e6574680000206a616d65732e6a68696c6c2e636c696d6174726f6e40676d61696c2e636f6d00001040436c696d6174726f6e6163696e63000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714f43f3b59a11d04ec6c2f2e246faf3c84c8486e43f7fa54578fa011764f1d2183b174faa2ed89942c": "0x00000000000000000000000000000000000a6d6570686978746165000000146d657068697874616540676d61696c2e636f6d00000b406d6570686978746165000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714f44c2f7410140cf19cbb16f064606fa2237ef9793e8c54e76e09934c0aa3616de195c3417ff47060": "0x040100000002000000000000000000000000000000000e4d584320466f756e6461746f6e154d584320466f756e646174696f6e2067476d62481468747470733a2f2f7777772e6d78632e6f7267000e68656c6c6f406d78632e6f726700000f404d5843666f756e646174696f6e000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714f45a1473eff966f38a1d68ff42661bb61ea1ba4d2818bd14bad9016823dd95ee0bd80d5cdc40a347": "0x00000000000000000000000000000000000000000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714f46797ab2e78531968922cb9e2094b7ae881da08890d1659e2c82d08878e45e7be83006aa6fefe35": "0x00000000000000000000000000000000000e5375624172742044657369676e01010101000001000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714f46951568dd99491466e8b633811f506b9d27c30141d4f5f03f41545aa8a3acd20a65f92599eaf1e": "0x0000000000000000000000000000000000124e6f6e46756e6769626c655472616465720000000000000c406e5f665f747261646572000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714f49c731c93e855d8e442aaad715153a1515d843b05b774fd7a3b52cfc011cd718975b44ad239d831": "0x000000000000000000000000000000000010416e61656c6c65204c5444404b534d001c68747470733a2f2f616e61656c6c656c74642e636f6d70616e792f001961646d696e40616e61656c6c656c74642e636f6d70616e79000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714f4b9a6863cc46670889af0630394f4684620003c6fbdb2bde3b1493ee257851e2c894c0f9b1fc13c": "0x000000000000000000000000000000000003565a1356696b746f72696961205a656d74736f7661000013766963747a61727440676d61696c2e636f6d00000f4056696b746f726969615a617274000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714f4cb3aeb24cf84a9e2815c08a727372ac028bf267fa8631226ccad9b689bb5b787b274c0828e1c51": "0x00000000000000000000000000000000000d733066746d616368696e6520011b68747470733a2f2f73686974636f696e7072617869732e636f6d1840733066746d616368696e653a6d61747269782e6f726701000001000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714f4d588a2f12c5abea6f3f09fac7be035067d4b4e8e18a47ab28a7bf50e3dcb90679e8ed631582645": "0x00000000000000000000000000000000000e5b4b5553414d415d207465737400000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714f4e09fff907e51dbba44ab1fc1acb0b1ff28165e08489416f665a4af1770ac45ab67642613d4a218": "0x04000000000200000000000000000000000000000000174d6f6e696e205374616b696e67207c204b7573616d61000017406d6172635f6d6f6e696e3a6d61747269782e6f7267186d6f6e696e2e7374616b696e67407961686f6f2e636f6d00000e404d6f6e696e5374616b696e67000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714f4ec2259201f165d10b51b925938bb414ec70b4a5b8179dde0028f4e00620e177839361f70bbd960": "0x000000000000000000000000000000000009506f6c6b61646f7400000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714f4f074392c48cb8b90c8b22b263271d5e7a8baf7ad89a918fa15a5ea58c33b0e03fdebae9f60db45": "0x04000000000200000000000000000000000000000000195769657a7a656c204b7573616d612056616c696461746f72104164616d20576965727a6269636b690000127769657a7a656c40676d61696c2e636f6d000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714f5052ba88cc9b0139609cdb14cf0b415f012433cfe2714ae591a0c0bdb443eecf99be67a6251da31": "0x00000000000000000000000000000000000673657268690000001f70616c616d6172656e6b6f73657268696937373840676d61696c2e636f6d00000e405350616c616d6172656e6b6f000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714f52104c468be8e69409e451afd449239c0bf71d2064b64ccb6fa40b7d64b31e070e867c298397563": "0x00000000000000000000000000000000000f416c65784973426567696e6e65720000001b616c657869735f72616d6f733936406f75746c6f6f6b2e636f6d00001040416c65784973426567696e6e6572000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714f5260a005d5a4f8b1aeffe4adfad627470d78b75ceeff90aed88685b9ab436611cf8b8aff4316264": "0x04000000000200000000000000000000000000000000074141726f6e6e000000176f786561706f7865616e6b6140676d61696c2e636f6d000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714f52b0b669e3be3189a649e148cdfacb89a0ed6ef6d1af70b4712cd09f0b079aee5fdebab7842584c": "0x00000000000000000000000000000000000c52756262657220466973680746656966616e00000000000d4061647269616e6573746131000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714f52dc65059840ede54d622206cdde1774f9ca2b05a09bb2679c97c6a2d7ad8a20d7fea2c7391d044": "0x00000000000000000000000000000000000c43727970746f5f70756d7000000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714f53a76b36f1f22087847a2bb5db0c9e65070fe05ce4e2a168a7a0e38c4e7238621c344445f1ba65f": "0x000000000000000000000000000000000005544f41410000000000000d40636861726c696562656e6a000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714f53d71829fabd2650c495817a6cd5cad36fa03114765a3e1189c1e8b11777d39f9c2ac1a18217505": "0x00000000000000000000000000000000000a416e67656c33356d6d10416e67656c20526f6472696775657a000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714f5488f1caf19f51ce69c23c5c6777d19d549efe56078bfd2f73f749f119c8ccf09023dfa6593347a": "0x0000000000000000000000000000000000074e7541725f7401010101000001000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714f55e346ed30a7e9fda296bb99c7df724f33539a3110c456b9a082e121734470a4cbd40703e519442": "0x0000000000000000000000000000000000094d41432d4e465473000000126d61636e66747340676d61696c2e636f6d00000b405f6d61636e6674735f000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714f5695ae6155ce7ab243612f0fc6c935d9ee0cbe21c453a83f58a9427054ccdc74966890ca57ca719": "0x0401000000020000000000000000000000000000000008416e74726f6d6500001440616e74726f6d653a6d61747269782e6f726714616e74726f6d65333740676d61696c2e636f6d000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714f56a3670b6cb3944bcabe2b0f21456b5d75d8987f79197e4df729c9283edc8f1b2f5558950f88860": "0x0400000000020000000000000000000000000000000009736f72612d6f707300001a40736f72616d697473752d6f70733a6d61747269782e6f726714626f7440736f72616d697473752e636f2e6a70000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714f56ab696ef80d1eec8f5635f081f1f774194a841f163cdc3ad27b3935bf1a928a9869627a0abe054": "0x0000000000000000000000000000000000124b72697374696e612044617679646f7661124b72697374696e612044617679646f766100001c64617679646f76612e6b72697374796e6140676d61696c2e636f6d00000b406b7269735f64617679000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714f59d68b847bcb2beacab23f327e732756f5d76a43cd32830d5d8a9a489cd9c5c6a8554a3374da056": "0x040000000002000000000000000000000000000000001cf09fa6bef09fa4962049766f72794e6f646520f09fa496f09fa6be00001c4077686974655f736e6f77666c616b653a6d61747269782e6f72671769766f72792e626c616e63614070726f746f6e2e6d65000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714f5a9403264d182764011221fbb00463b80a86f5b7e3ad507717724ff91c47cba6521d7f34983f527": "0x00000000000000000000000000000000000d4b7573616d6157616c6c65740000001467726567323730303140676d61696c2e636f6d000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714f5b6095599969b9da657fdb5080af7783a0eb74870fa95b2e0e4dc78445f4b4dffeb3ab18856e30b": "0x00000000000000000000000000000000000d424f55424f554b524154494100000017626f75626f756b726174696140676d61696c2e636f6d000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714f5c03f3c88350579aeb0e7400e227d10778810032a5c677766796398d0dfcec5d7cf210458f22142": "0x040000000002000000000000000000000000000000000746617468657200001440706170616b736d3a6d61747269782e6f726700000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714f5d0cc94e99850e8c2421666570ec7f9a5c94ef30c2c6443bd857faabcdeec6a96ef4280ef41f61c": "0x040100000001006c57c10b0100000000000000000000000000000000000000000000000000000c686173687761726c6f636b074a6f73687561001840686173687761726c6f636b3a6d61747269782e6f72671a6269747362656e6465724070726f746f6e6d61696c2e636f6d00000d40686173687761726c6f636b000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714f5e19c61928389eae882a0e173cddff84f834ad020772bfafa4022d9c9a823f54982e9b4d3fec745": "0x00000000000000000000000000000000000f4956414e2052204d4154482023330000000000000b406d6174685f6976616e000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714f5e44fd2e0ba9c81b88ac257042778fa648722b1500402f740f908e58d0bc8e19439a352e55dc613": "0x0000000000000000000000000000000000104d69737465725f436f6c65204b534d00000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714f601fb05d6c070e4da8564ba0f7e717dd8d61025823ef756b474d6a3f3e8099da01ce16b53d85154": "0x00000000000000000000000000000000000747656f726765000000136d7574613631353040676d61696c2e636f6d00000d40475768616c65636861696e000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714f6035b451942851ca231fc973b2ec593bcb98a447e9c221a999cdfd05cf2dbdcaffea0bf42cb0f02": "0x00000000000000000000000000000000000c46696368204d6f72736c7906416e746f6e010101000001000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714f60bbbed7d37752ebab59eee6a380bd486faf8abbb17790b47ab67cc2706ffeead8fc51f5949ae8b": "0x040000000002000000000000000000000000000000000f50726f6f66204f66204368616f730000194070726f6f666f666368616f733a6d61747269782e6f726721676f7665726e616e6365696e63656e746976697a657240676d61696c2e636f6d00000f40476f76506172745265774b534d000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714f61803895bb4ef9200d6a5e519858100b8f989048a9d6a202d0c588ff72f76fc9a18a4adadcab168": "0x000000000000000000000000000000000006476f627a790000001a6d6f68616d6564686166697a39313940676d61696c2e636f6d000011404d6f68616d65643135323833343535000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714f618fd21cfdd00cb0e8b58178acdc19d47b6b00140772db705f55e6d3a4881bfd3232b4de456103d": "0x040000000002000000000000000000000000000000000c536f666969615f56616c3200001740736f666969612e6b6f6e3a6d61747269782e6f7267136b736f6e696e393540676d61696c2e636f6d00000b40536f666969614b6f6e000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714f634b03876b8ef79806aaca020076fa26a81169d70fb62d932a440ab3c0ab77033285e572ad2b912": "0x00000000000000000000000000000000000b52454e454c494e3136380000001270636c696e3732407961686f6f2e636f6d000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714f6553f1969b75460800f8a9142fa2145a9dfd55f63917f1d56c61b019b92acc1e53669d281765a7d": "0x00000000000000000000000000000000000a59756d692041727473001b68747470733a2f2f6c696e6b74722e65652f59756d6941727473000000000d4059756d69417274734e4654000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714f66ebdaccf9fa53084b56b03893a12010b087eec53365d5b7d9b47b0b3bf17a012bfe096012f600f": "0x04000000000200000000000000000000000000000000074d6561646f77000000166e61746976612e7665746140676d61696c2e636f6d00000f40416e647265697461507261646f000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714f687f2305ea5dc3060ac960bd310b75e387525446daef1ceb98f322d3e5300ad8910568f6aef9d3f": "0x00000000000000000000000000000000000b7a6d6368656e2e6b736d011968747470733a2f2f6c696e6b74722e65652f7a6d6368656e01157a6d6368656e3133313440676d61696c2e636f6d000009407a6d6368656e33000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714f6b2883a4b0925a1f64c77c5a1bb3a45db136d8e36bd9fa3fcf0e060313b404650e59c97b7ac9030": "0x00000000000000000000000000000000000b416e676f2050616e676f0b416e676f2050616e676f000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714f6b5e0cd02d4b92f3a125886cdd1eddb5f8dc3fc266062e6066ea77566f7694efd93a97ba57a7e31": "0x0000000000000000000000000000000000056b72726e00000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714f6c04fa3dd4fac8ccaa7ea76d94fbb4715ca996b63214e8fa86bdd293fd5fc7b8fe9de231010e21b": "0x000000000000000000000000000000000010536f6c656d6e20537472616e67657210537472616e67657220536f6c656d6e00000000001040737472616e676572736f6c656d6e000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714f6d034c52a0fc194d6ac28ef62f212e4a5888fa5e72b1515a32233dfb118a9ea5de97558b1a53d65": "0x0000000000000000000000000000000000064b43435f3100000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714f6d774e91f506eba46e2c2e77afa347eb36b101757c3d004b088a324405c097fa561a750249cc44e": "0x00000000000000000000000000000000000101010101000001000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714f6e0d6bfbf124fd8c6d5a9d80d5559e34b6c16cea7f4da7d399aceeb54530bee71fcff718ee5a82c": "0x0000000000000000000000000000000000064561646c6500000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714f6e15252920b51ae5004bd06b509a6d463ef831486a0fa49b185bcb3f96e06020ae63615b284a81a": "0x040000000002000000000000000000000000000000000c526f647269676f3730303000001840726f647269676f373030303a6d61747269782e6f72671a726f647269676f373030302e6b736d40676d61696c2e636f6d00000e40526f647269676f5f374f4f4f0011526f647269676f37303030233533343200", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714f6e75d18b8b8218f6a73a035c39a045fd93aa3e85b7b91fb4a77d8072149182f8d42362fea9bf85a": "0x0000000000000000000000000000000000124f647973736579204d756c74692d7369670b4f6479737365792042561568747470733a2f2f6f6479737365792e6f72672f0011696e666f406f6479737365792e6f7267000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714f6fb66dae8fa6226a8d08e114a7bfeda36a14cb3db7b8085d867eb4e0f33eb3f2e0a50f821abd80f": "0x00000000000000000000000000000000000a506f6c6b616672616e00000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714f71158c0f51bb8fd5247e73b8ad3c36bb4e01c93a9bd6a6048afce1e2a45863ea5fe99778b530b61": "0x04000000000200000000000000000000000000000000094e5244204c6162730000000000000a404e52445f4c616273000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714f718691c7d2fecde924f9a8e5439d381aee00bd507a3d52321be607c5935bb0d6c9bfb2227875b5c": "0x0000000000000000000000000000000000094241545641554c54094241545641554c540000184261747661756c744070726f746f6e6d61696c2e636f6d00000b404261747661756c745f000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714f7199ad6b299d282d2d6d338d9b6d82049dba9d8a4e20feb2515bd7aeeb997247a02e56e8d3b1469": "0x00000000000000000000000000000000000000000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714f71b1777c4c6a13546b4eca928ede3e8075d86e25581d46adf3eff915646eab110d13e2fbd947b5e": "0x0800000000020100000002000000000000000000000000000000000e7765623376616c696461746f72074e696b6974611c68747470733a2f2f7765623376616c696461746f722e696e666f2f1a407765623376616c696461746f723a6d61747269782e6f72671477656233346576657240676d61696c2e636f6d00000b40776562333465766572000a77656233346576657200", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714f71c3bfdec4acbf06eb5904c5ae1d15ef5b700f4c30b87cfda092fe7e01b94f5ce7951b8b368a224": "0x04000000000100902f500900000000000000000000000000000000000000000000000000000005746e63680000001674696e636863727970746f40676d61696c2e636f6d00000b4064656d6954696e6368000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714f721344dcd79f9f76869fc679ec3b5cf08e4c2ea215ad2b3ab2fedf7263d019c4181e0f2e8e6071c": "0x0000000000000000000000000000000000114465657065726e6175742e73706163650c4a6f686e20426c616973651968747470733a2f2f6465657065726e6175742e737061636500166a6f686e406465657065726e6175742e737061636500000c406465657065726e617574000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714f7213bfc0e550eb660ba08bf2bacea0f40dcf6b9f8f253ca8267cb45f6db39acf5c71c5c1d1b3521": "0x0000000000000000000000000000000000056461336100000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714f72498dd00ff440c3c06757449eba15d09a779c6cbc249eb6fcd0dcf994ad9f3e4d6bf2b60ea8c74": "0x00000000000000000000000000000000001043696e636f2064652050686565626f00000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714f726e9532024780186f20c19f0c0238685e4802c2f7880579b4426a1724d0ad0a6daa88bfcbca026": "0x00000000000000000000000000000000000452614611526174696f6e616c204173204675636b2168747470733a2f2f6c696e6b74722e65652f726174696f6e616c61736675636b0101000001000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714f72fe494f8b2c13b50bc2d20f1106991d73e7e17202dd22c951c13552caefa2fe973490017f0015c": "0x0000000000000000000000000000000000074b2053756c7a010101010000084073756c7a5f6b000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714f7395a35358c5c73b03a577ca487cc73addcdcbd6b006aee80991427d8cdf2b732e4cda58bb06a23": "0x0000000000000000000000000000000000094f736361726c74630f4c65756e672054737a204368756e00001b6f736361722e6368756e2e6c65756e6740676d61696c2e636f6d00000a406f6f636974656f6f000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714f755c066638838c208ec81d6f3942d5955364977664f27b91f34f3b365ee0ef1ca87facc9bc1f900": "0x04000000000200000000000000000000000000000000056c616461000015406c6164612d6b6d763a6d61747269782e6f7267136c6164612d6b6d764079616e6465782e727500000b404c61646173756e6573000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714f75e019010e9d2891019993ccaf1f9dbd14e41793ebbc5dc0c3f301cb8323d75678deda1087d7e38": "0x000000000000000000000000000000000007594f4755525400000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714f762150cda5f8ed7ce6075c29ed1bf04552862e9068cd112761eca24d335514dbf43abd811512242": "0x0000000000000000000000000000000000184d6f6d656e74756d204e465420436f6c6c656374696f6e0c4d6f6d656e74756d58595a1668747470733a2f2f6d6f6d656e74756d2e78797a2f000000000d404d6f6d656e74756d58595a000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714f763d946684c55c7027342f61bb5ae7fd9a78ab16b23d56dc3bff26ce92fe6cb787cdd4c9abe7635": "0x0000000000000000000000000000000000064d6f7a7a6900000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714f7722cb2c8ef11377e78e4019711d39804f121a2c2e719158dec8f848e329d23af4f4df886b0ef59": "0x0000000000000000000000000000000000104775657272696c6c61204b61726d61002168747470733a2f2f7777772e696e7374616772616d2e636f6d2f677565727269001554656b756368656f6e6740676d61696c2e636f6d00000b404775657272696c614b000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714f7815b3b02445bee22e79717d0fefeab58a93b118b1da271ef308419ad31b7c88048b202a72a7f7c": "0x0000000000000000000000000000000000124c75646976696e652050726164696e6573124c75646976696e652050726164696e6573010101000011404c75646976696e6550726164696e31000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714f7b9882bb36b0080f043bee4b4c5a1387805a345d2ec765bbaf1368701292efa42c39592c8c74b4a": "0x00000000000000000000000000000000000c47656c6174614472696e6b00000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714f7d620f3759f37d922a83d766632d6c6b371f5936014822d228c16699a1d2770c465f04abc05d71f": "0x00000000000000000000000000000000000d64696e6f6e757473696e686f01010101000001000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714f7dee93d06f89424c8b27ef9420148d8711a555ecaf50fdcf0705f1af8fe4cb525f43fbeb2393125": "0x000000000000000000000000000000000004e99d9601010101000001000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714f803929b514c8374d44e8557e2484832376bb918ca7fb5743eb5befc52d4f2a3b9b54f21818f2d7c": "0x04010000000200000000000000000000000000000000064672656479001568747470733a2f2f64657266726564792e636f6d154064657266726564793a6d61747269782e6f72670000000b404465725f4672656479000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714f820b2f799e04c2e4ea5deb79975c49738ccfc00e2d53dda38c7bda5b9794643c071b3be46eb1629": "0x00000000000000000000000000000000000953757065726d616e01010101000001000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714f82d8b99311e7212a46c027c5b401f01d8d9bf548ab323785f6db26575c5fc9290434da5fef93960": "0x0400000000020000000000000000000000000000000011f09f918b203739616e766920f09f8d80000013403739616e76693a6d61747269782e6f7267133739616e6476696b40676d61696c2e636f6d000008403739616e7669000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714f836b36502f1031656f85acf479b193128bb0482a4f01191b48b10c4a2a13458d97da7bbb383f77b": "0x00000000000000000000000000000000001d56616c696461747269756d20742e6d652f76616c696461747269756d1d56616c696461747269756d20742e6d652f76616c696461747269756d0000157661696461747269756d40676d61696c2e636f6d000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714f846335f6916b0d70e5f9a5620405b32b9cf67bf7124b4e772a34e87abeab4ccc4e14389f1ce305f": "0x00000000000000000000000000000000000000000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714f846d171247e3f0f4aa63d199318cd993574507d7970c1cc69018124a96892f52a900debf38df908": "0x0000000000000000000000000000000000076b6173626f79184b617372612042617261646172616e20416e6172616b690000146b617369626f79363940676d61696c2e636f6d00000a406b617369626f7965000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714f85213a2ee7ef9df68f838c7f70002288722303bd1482bf8a2f2973ff548d3517ed8ef3a8c6cac37": "0x0000000000000000000000000000000000076c6673613739000000166c66736137394070726f746f6e6d61696c2e636f6d000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714f85b684a0310e669c4ce6a3336cbace999a6052c4dbc755fdb2d263490ec0fc2a8c3fe8e23376469": "0x00000000000000000000000000000000000e4b7573616d612057616c6c657400000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714f87b103429943affbc6f62a54d698249c4049a8ff3a7af9b5f28325adb33e1ef5d2ce402f954c65d": "0x0000000000000000000000000000000000204368616f7344414f206175746f6e6f6d6f757320766f74696e67207465737400000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714f87da1ee1c7abb802e0094a721c36e0ebceafaa1cc2fbd8d4e82f2bb1c85001ce8172ad6b5011d0b": "0x0000000000000000000000000000000000035056035056000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714f88f79bc67c8710cb6bc64fe84080c7fbb6c6dea980960f0cfc716695b2821bf7a28a356bc19070e": "0x00000000000000000000000000000000000773757265736800000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714f891e0d61d95d2f9ecc96f0e735d4677e64728f5300b27c97c3413ba01e7a60dd29cb89123990a66": "0x040000000002000000000000000000000000000000000b44722e52616e766965720000001564722e72616e7669657240676d61696c2e636f6d000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714f89ce40ac4f74c35cebfc6751f43de44d7aacff9d0e48240227560e071b4b2547edde36ae3c3ee59": "0x0000000000000000000000000000000000077469726f6c61077469726f6c61000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714f8b08ec665a49b5a566edc7dbb221131cb2aea38025779d4f4638c769b16c1b0cfb060fc613f2d6b": "0x00000000000000000000000000000000000f546f736b612053617475726e6120034169000017746f736b6173617475726e6140676d61696c2e636f6d00000a405453617475726e61000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714f8bcf5162393bea6c2f706cbfd0708a2fa387748388e4851012bb69b2e965d2dd933e452ddc36464": "0x00000000000000000000000000000000000f42494e414e43455f4b534d5f343800000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714f8ef4c38a66ac4223cf3f47f611c9dd952bd9007a85b0d84383f91e2f25edd0f13d6be20b5805110": "0x040000000002000000000000000000000000000000000a67747374616b696e67000000166761757468387a4067747374616b696e672e636f6d00000a40475374616b696e67000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714f8f2d058aa94f837b8356d7f4f32035fdf5b8188e4d1a5cb1639c580c48a29a1590bbcbc2df0597f": "0x040000000002000000000000000000000000000000000641424741520000124061626761723a6d61747269782e6f726716616267617262617273656740676d61696c2e636f6d00001040416476697a6f7254727573746564000b476172696b233537313500", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714f8f844a5b45ed4e5461490934113768b8b0bdc60810250ab77fc9c0fe05f69a05d8262fdc7a39656": "0x00000000000000000000000000000000000b4672616d6553746f6e65001768747470733a2f2f6672616d6573746f6e652e6e65740000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714f9047b8f088890cbc687ff86c75c1a2506c4aa4cea67f68276b6348e3f497bb845b42a3aef585025": "0x000000000000000000000000000000000009464b31203139333100000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714f93edb11f07d9b7c4e721644ba20842c4c89f36b89af12e53a513a43841728eae5ac5efccaa01f32": "0x00000000000000000000000000000000000b53696d706c6573656e640101010100000c4073316d706c6573656e64000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714f9423de3a5fdd2d8c8c87c93d349b6e30b0b00906c966e623b5a48b4a12803434c45dfdfd171f951": "0x00000000000000000000000000000000000552697a6b1469647269737369206a616e6174692072697a6b01011772697a6b2e6964726973736940676d61696c2e636f6d00000d404964726973736952697a6b000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714f945bddd0ac8d6e44a3258cc6d8bc991479bc724a77d8d74491a5e8cb3ceba66cedcd180b3290e07": "0x00000000000000000000000000000000000d44616e676572204d6f75736500000017546966664c7563617330303740676d61696c2e636f6d000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714f94e92ce97ad9912aeffde5a4dc7117e4cdde2d3fb3d2afc7b2f710d5d66c55c5d1d7c5873598706": "0x040000000002000000000000000000000000000000000c4d6f6f6e4d697373696f6e0000001973616e67616c6c69676c656e6e6140676d61696c2e636f6d000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714f952ae0f2dbd6fee08a876a9d0c017b4a35ec9a60da69cdf10e25dcbcf6e32398e911c8471576f36": "0x0000000000000000000000000000000000104b7573616d612057616c6c6574203100000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714f9540eba239b8a7078b5f7e8f099b66d62370d55e7423b65e5b813df52679626adec7b4b00de9565": "0x04010000000200000000000000000000000000000000075061726974791950617269747920546563686e6f6c6f67696573204c74642e1268747470733a2f2f7061726974792e696f001061646d696e407061726974792e696f00000c4050617269747954656368000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714f9588f41f8fb002552b993b5f03c0eb34858fd978eaba71182fd619307ab26a2fb31b3f34d098272": "0x040000000002000000000000000000000000000000000c6d7968616c657469736865000000126b6f76696440696e7465726e65742e7275000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714f96da090b9f585b1e68da6ba34b144a0ca598bfe9796b4308e750f5f76972296528b97a3d97e0e67": "0x00000000000000000000000000000000000565646976000000146564697640676172626167652e6d61726b657400000840656469765f5f000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714f9cdf9022f4cbf316e209998f669dba74194912c3e64d33dea4101e1e589b38abbdbbad88e93cc53": "0x00000000000000000000000000000000000000000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714f9d69d01e9632c5372ee5c9dcec858fe96783766b2c1894e26b95b52318652b7672b2c496a579b75": "0x04010000000200000000000000000000000000000000114d756d6d696573205472656173757265001d68747470733a2f2f6d756d6d69657374726561737572652e636f6d2f001a6d756d6d696573747265617375726540676d61696c2e636f6d000011404d756d6d6965735472656173757265000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714f9e4321423bc80888ef7167c4d50be846c6a03591e13005fa68ef858d87321bb79428b121e105a11": "0x00000000000000000000000000000000000d53455247494e484f464f474f00000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714f9ecb241324aeafbe63d1474c5ae8edc07f6b09e4efaa777640c6b1b1cfaab3cd797aecaa932010a": "0x00000000000000000000000000000000000730784d61723101010101000001000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714fa0bfc4dac243ee0f42b7fead1bb8eec5d895fb3d3bd145e85f0b6d5c8bb3d7edb4a6fa9dda2c021": "0x00000000000000000000000000000000000000000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714fa21d4617f82911d045dcf490090bbd75f4ab97f5984fc4792d122368c6a73cfb3d11873dd9e274d": "0x04000000000200000000000000000000000000000000064f7262697400000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714fa3f4bf18db4aa46bac3d54468165a2b6b4cc010beaedcd71ee772dabc384bc9a54d6eca6e14a20b": "0x000000000000000000000000000000000020524d524b2047656e6573697320436f6c6c656374696f6e20466f726765727901010101000001000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714fa43aa10b719e7a44a1f6aa44b0456c45ffe2e1314c991430734a090f57910425f9a5e9b6573ce3e": "0x000000000000000000000000000000000004414c5800000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714fa45a2d24a1b7d89a46615035c62da7a1906c838ac55e2ef1f38b679b9d5d6ab7c3633fd75280f43": "0x00000000000000000000000000000000000e42494e414e43455f4b534d5f370e42494e414e43455f4b534d5f37000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714fa48706896c81ac3544e034f612acb28ccbf0822adf1140335fa6e8bdccfac51a3bc7da22ebf7c58": "0x0000000000000000000000000000000000084461766579444301010101000011406461766579646f657363727970746f000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714fa4f3e525e10f673faeffbbb88ab949b51abcacd45d7f9addf608a6e6ddc3d4b39147454e1a23a16": "0x040100000002000000000000000000000000000000001356414c494441544f5252554e4e455250524f000000177367696f7661636368696e6940676d61696c2e636f6d000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714fa5550e0264faee9fa17408ad767e6d32032b8a73d670d87a8f2a339803d404d1430ceca36911865": "0x00000000000000000000000000000000000c676f6c64656e726174696f0000000000000d40396f6c64656e726174696f000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714fa56ae54f7bf8c8ed62b129a1d30afe9a2fd69a871f50355d01f0a5e9b7fd160f3a0d4e74a0d0a35": "0x0000000000000000000000000000000000084d564420525654084d5644205256540000146d7664727674626f7840676d61696c2e636f6d000009406d76645f727674000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714fa6a08c0d89c75d8801250e96cc2a1d70ef029adf57956e6a7100669076e8ccc14425142f4d7370a": "0x000000000000000000000000000000000008436f6c6f7375730000000000000e40616c7661726f64657265636f000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714fa894c90df0929a924454eab2e4e832c9d71afe1dd6345a7d889fab3430d8ad971888610af053317": "0x00000000000000000000000000000000000d506972617465205368656570001a68747470733a2f2f7069726174657368656570696e672e697400197069726174657368656570696e6740676d61696c2e636f6d000011407069726174655f7368656570696e67000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714fa9ac24df5ce07f888ce8ce9cd622ac98233ffcca795bd69097012a6bf409054c1ec522850fb3523": "0x040000000002000000000000000000000000000000000c43727970746f436172746f000000000000104063727970746f636172746f78797a000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714faa55b79d5b983962aad2d511e0a2ade151b1e3442675156b71aea1f049ce004311cf33c9d70c474": "0x040000000002000000000000000000000000000000000a53656261737469616e00001c4073656261737469616e63726970746f3a6d61747269782e6f72671b73656261737469616e63727970746f3840676d61696c2e636f6d0000114053656261737469616e43726970746f000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714faa9d42c4d30ce42e6d147ba2586400cf6696e4d7f4491f51cfd88f9ff1b25aafba296851e6dbe5a": "0x0000000000000000000000000000000000134e657572616c204361742057617220494920134e657572616c2043617420576172204949200000186e657572616c6361747761723240676d61696c2e636f6d00000f404e657572616c43617457617232000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714fb0aed06762dab03eed2052b53fd2a9cffaa55f84d4abf8a6143956ad77cf0579a70bac39da5cc50": "0x0000000000000000000000000000000000074269484f444c001668747470733a2f2f6269686f646c2e636f6d2f232f0013737570706f7274406269686f646c2e636f6d000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714fb0bfb045f7bf9b02c5a307190f900bfce402cda80d3e30768767064591707a00a4a3111d3fbbf21": "0x04000000000100902f5009000000000000000000000000000000000000000000000000000000064f7264756d0a4f7264756d204c54441c68747470733a2f2f6769746875622e636f6d2f4f7264756d4c544400156f7264756d4070726f746f6e6d61696c2e636f6d000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714fb0c0bcedbed5db3f689caeaa9e3abd42396b7fdd5bfc75162325cfd5dd65a1eb247a64a1bfa123d": "0x000000000000000000000000000000000010446f7473616d6120416d617a6f6e7300000018646f7473616d616d617a6f6e7340676d61696c2e636f6d000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714fb1e196ecaf7c6ef54ec6a7bfcee3ac00ab63b98e084f1a1c4d0e82ff63c31387aee91c9a721a81e": "0x04000000000200000000000000000000000000000000114e656a6c6570c5a1c3ad20766f6c6261000000157065746b6f6d65726b6f40676d61696c2e636f6d0000000017407065746b6f6d65726b6f3a6d61747269782e6f726700", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714fb20a4393f027fd3301da7198667c2c959b5f7d81068d819d90e8dfe3c4ead4a89d84d8691c07350": "0x000000000000000000000000000000000007594a534e50490f4b6f756a69205461646f6b6f726f17687474703a2f2f7777772e3131343531342e636f6d2f0101000001000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714fb2b8dee530cc653344c0541f063ddc8dcf4709789b93099da7e145f794116906f511061ca6de158": "0x000000000000000000000000000000000011432d4c20426c6f636b636861696e20200a432d4c20696e632e2000000000000e40436c426c6f636b636861696e000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714fb5b92a4cfa1db0b6c2856a7a778cecf99534917e33c2665c67734a7d666093b6b9c785a3428ec61": "0x00000000000000000000000000000000000f556e69517565204176615461727301010101000001000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714fb5bc1ff496d8054008d8404893c7b4b80f397605cc96e61fec3c89676c8c2794a2a7d281d678b1a": "0x0400000000020000000000000000000000000000000012f09f8f942048454c494b4f4e20f09f8f940000144068656c696b6f6e3a6d61747269782e6f726710696e666f4068656c696b6f6e2e696f00000d4068656c696b6f6e6c616273000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714fb81b24c2a962fd37a94eb167216d8c9dee6fc9b56b440f01cd6c3a982a52ee041148f324421e524": "0x00000000000000000000000000000000000b546f726f2056657264690000001b726176696b68616e726176693230323040676d61696c2e636f6d000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714fb84ec0986da67466055556b55210cc9d0f33bbc68d7c31bb5e28e1a639e1d6599aeffd7e49b6749": "0x040000000002000000000000000000000000000000000b4c6174656e744865726f0000001a6c6174656e746865726f4070726f746f6e6d61696c2e636f6d000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714fb91afe505259de7eeb02ffe6617932e5f2dd74bc81031fd5bec0272c7b3db1c7c28f511cac7a669": "0x04000000000200000000000000000000000000000000134a47412d2d48794846642d2d2d7741416d5800000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714fba64a5013aca5aeec056e28b5688b561339537ddcdf78522c50761995f97825b3cccabd1075cf2a": "0x0000000000000000000000000000000000084d696b6861696c084d696b6861696c010116656d70747931393836727540676d61696c2e636f6d000001000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714fbac4c060b088b92aeedb1738fb7133da240213ab0f0916eb7abaf4140693b7a3f54311732bdda33": "0x00000000000000000000000000000000000a477561726469616e7300000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714fbb58baf12373ea22a1fd6ec0eb5124ebd1a70b26d283cfd92c289a451099cf91d255b1d76492829": "0x0000000000000000000000000000000000054c6f76650d6d792073746f7279206f6620000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714fbb8612e16c166c53292b66610bfa155fa87e60a020cf1fbaa438270fee288cd37655c91b0e20d3f": "0x00000000000000000000000000000000000d6d65746165726f6372616674054f67616e157777772e6d65746165726f63726166742e636f6d00176d65746165726f637261667440676d61696c2e636f6d00000e406d65746165726f6372616674000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714fbbd751cf18b124e066c470486d44ccf316779b680487ebee03495f93504cae4ab095a8e84a14877": "0x00000000000000000000000000000000000a54656464792044414f0a54656464792044414f00000000000d40546564647944414f4e4654000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714fbc426fc6e0869cd6e440a8acabf4208776f36b78891e8374e587dddd3b9cd6b67c59bb5b5b21a22": "0x00000000000000000000000000000000000c5374616c69616e6f5f323200000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714fbc638e525d98b707a8d3cae2a718a52464bbdee0cc9f4356e79eea7df10450852f53653fb1db029": "0x0000000000000000000000000000000000054e696c7300000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714fbc6c8362eaa2f7cc8f449273529d94798e1b40063ab062e12c6274d3ebae93b22c221cd090acb23": "0x040000000002000000000000000000000000000000000c536d696c655f7374616b6500001840736d696c655f7374616b653a6d61747269782e6f7267197a616c75736b69766173696c697940676d61696c2e636f6d000011404161726e6149726f6e733339303734000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714fbcfcd76d1d892611ed66ffc1202460d3e4ef69ba4f0108332bf2c1129e03e027a8d9d8f43f76561": "0x00000000000000000000000000000000001031506f73697469766576696265733100000017637572746973657472697070407961686f6f2e636f6d0000114031706f736974697665766962657332000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714fbe3fad5beebd421de43fe93757a22e2588359fe423a4b1a9158369e27c839e63d7f7e1b4f1eac3d": "0x040000000002000000000000000000000000000000000a30784a6f7461456c650000001230786a6f74616c40676d61696c2e636f6d00000b4030784a6f7461456c65000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714fbeac673cf6ad96d86d0ca1a8d914606cd02075f08d7761ebd332ad86366ad394b204b574e7eb531": "0x0000000000000000000000000000000000084368616f73313900000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714fbffcfa5ca1c52b612ea0b1170fd52e15cead3cd728c55be445052ce3a9d0430c8f93d80e0f27a7a": "0x00000000000000000000000000000000000d706572696c69616e204b534d00000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714fc2c019dd594548ff8547fde2d99534f00b548363ea18c47f8e72003b1097417f4d337080a94890b": "0x00000000000000000000000000000000000000000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714fc350fd2d1e9b3546e069c9fdc08c7b545f21e2fa2d4d95d0ab995dab99975acb4a717c0004b6d1d": "0x00000000000000000000000000000000000a486f6c6c792e4254430000000000000f40686f6c6c796a6565785f627463000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714fc4000681dcc4060901fb59036fcb6811c92f7f8c0b4cfe288393f849c31ebf18e34c48886486227": "0x00000000000000000000000000000000000f56616c657269796152656973657200000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714fc597e338ba1693cc06ba3aa6dd4ef5128ca5b3122b6d7eb5414c205056cf542e593e2d63adbaf2b": "0x00000000000000000000000000000000000e43727970746f20506172726f74010101010000104043727970746f506172726f745f5f000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714fc6a73dec7fa79b18c8305ff8478e6309325ebbfb81e8c1883d39e65d2ef84f88e4a428615c49277": "0x08000000000100902f50090000000000000000000000010000000200000000000000000000000000000000085032502e4f5247085032502e4f52471068747470733a2f2f7032702e6f7267000f6c657473676f407032702e6f726700000e4050325076616c696461746f72000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714fc6efad6664e87cc02d16cb5729728b5237dcf6335c1a49a844fc8f86e63f6dd27cb9c1803df911c": "0x0000000000000000000000000000000000094c616d615f4b534d00000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714fc74e5b9fe588bd5bce565fbba1e8cc8cf794c368b755e0a57354b70d9a262b2a14b4c4363f6fc04": "0x00000000000000000000000000000000000b446f742057616c6c65740e5a68656e6973204162656e6f760000136b3233706978656c40676d61696c2e636f6d00000a406b3233706978656c000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714fc77c115641dccf2908fafa24788c23e2db2a4947d62813364fe3a4e6548a36b6cd7cfcaca30ca43": "0x0000000000000000000000000000000000134a524d522d424320436f6d70617269736f6e154a756c69616e20522e204d2e205269636874657221687474703a2f2f626c6f636b636861696e2d636f6d70617269736f6e2e636f6d13406a726d7239323a6d61747269782e6f7267216a756c69616e40626c6f636b636861696e2d636f6d70617269736f6e2e636f6d00000b405363616c6557656233000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714fc7f2ed947ce60905842026fdfe358c9320e35012deeedc83c1e19d2b677eba10a1fad0d93c82b66": "0x0400000000020000000000000000000000000000000005414e474c00001840616e676c2d63727970746f3a6d61747269782e6f726700000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714fca0f500e560ebb8aa2560b48e6acb448d5957b30400dacc88967f8ff0519c095a4628f7d001060c": "0x000000000000000000000000000000000017437270746f666f6c6c6f776572202d204b7573616d6100000018637270746f666f6c6c6f77657240676d61696c2e636f6d00000b40447572616e64696e73000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714fcbacdb7dda02f70504baa1f30e0267703f471e94de948bd9f09caaf3c3a2f4c2dad3685a79ee000": "0x0401000000020000000000000000000000000000000006616e76656c0e416e64726569204f6368696576001240616e76656c3a6d61747269782e6f726717616e647265792e76656c646540676d61696c2e636f6d00000d40416e6472657956656c6465000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714fcd27506d243061f2edf0fd8948ea642f135b314b1358c77ec6d0a4af83220b6ea18136e5ce36277": "0x04000000000200000000000000000000000000000000124368726973404f414b204e6574776f726b0000000f6368726973406f616b2e7465636800000d4063687269736c6932303436000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714fce5be1f766dfb1672b5848541435240ecc09392bdea68c4fc6f7bc06ea7389a09e02a6b22052164": "0x00000000000000000000000000000000000000000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714fd015b120265976186deb657c4754c485fad608accb98e195349f1d6f7b3e21fc0de1b49605f221a": "0x040000000002000000000000000000000000000000000641727347470000124061727367673a6d61747269782e6f72671562756c646f73696b706c40676d61696c2e636f6d00000a4062756c646f73696b000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714fd033442619da284ec5da3e8919335b965130fb9109eb55f02fc78db8e592ddb8db101dce2b1235c": "0x00000000000000000000000000000000001157616c747a696e67204368696d657261000000000000114057616c747a696e674368696d657261000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714fd13d95520bea732966b58639403c4a3e5ad93300a158d65f9b6a8dd1d4e053f7058fc19d1f5ca2b": "0x04000000000200000000000000000000000000000000116269726473626972746866617468657200000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714fd265413bf0cff23c261b264bdd11a41bd20702fb3119fffc00f49d035d4efc219cdb217448ec353": "0x0000000000000000000000000000000000010220010101000001000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714fd3e18c07f5fba3b662df7fc799864be8c99d11723b4ebdb4837ab3287a4668b1bd6d83f904cfb7f": "0x0400000000020000000000000000000000000000000011576f6c6645646765204361706974616c0000001768656c6c6f40776f6c66656467652e6361706974616c00000a406d6f68616b616772000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714fd47ebcc2ca5e8d37e4f4ebe251bb6361e0ddcaecfbad3da3bf473b678c7684af7792a7cf83a226d": "0x00000000000000000000000000000000001250617472697a6961207c20414e414d495800000016646270617474792e64657640676d61696c2e636f6d000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714fd49aaf383f13bb11ede7818a2f7f044a9dfa0755940d7f1468aee6f3df19695d4d74f77a8198a7a": "0x00000000000000000000000000000000000f4d64656e626f736368706f6c6b6100000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714fd6097824962e44cc095ca14303d34ff5b0b2e5846e62c65bc4bd81244d41c97b82b4ea2a05e7d6b": "0x040100000002000000000000000000000000000000000c527562656e20546f7069610c527562656e20546f7069611b68747470733a2f2f7777772e727562656e746f7069612e636f6d0014696e666f40727562656e746f7069612e636f6d00000d40727562656e746f70696131000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714fd70211d1db8fd913a94d7f01d2e2a30b20bf318bbd88a3e8897769a26eacbbbb3383e3cbaab1321": "0x00000000000000000000000000000000000d706974636f696e2e61737472064d6172636f00001d6d6775696d61726165732e6461726f63686140676d61696c2e636f6d00000a40706974636f696e5f000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714fd8ab13040828c7114896a045cb7bbcf45c0894fd388e23cc67d0697363530cae5cba9d5d28cc51e": "0x00000000000000000000000000000000000744616d69656e07446d7974726f00001964616d69656e2e746f726e2e373840676d61696c2e636f6d000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714fd8ca3f2d503cae5fa514f3f70cf1b8b3ff34cb7e783e3d8c38077409bb2dfc877b396a98703ae7e": "0x00000000000000000000000000000000000000000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714fdb56e406bbd33003c1db08dfc6786bee3b0e1b4aaf51e80b6f2ec9badbe3da87d30ad7605a2bd16": "0x04000000000200000000000000000000000000000000104b7573616d6120476f204c756e617200001a4063727970746f676f6c756e61723a6d61747269782e6f7267196e6f74696669636174696f6e7340676f6c756e61722e696f00000f4043727970746f476f4c756e6172000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714fdb8522cbdc728de58832b4a605c2e5200f88606aef263a82573ef1f8421ae19ac8f786661d77631": "0x040000000002000000000000000000000000000000001356696b746f726969615f44656e69736f766100001f4076696b746f726969612e64656e69736f76613a6d61747269782e6f72671368686f75722e647040676d61696c2e636f6d0000094048686f75724470000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714fdbb17eb6b8c97966c335d86444f3189027cd53244265047e52a96b4621fdaeeb9bc128577898676": "0x0401000000020000000000000000000000000000000009414c4c4e4f4445530e416c6c6e6f64657320496e632e1968747470733a2f2f7777772e616c6c6e6f6465732e636f6d0015737570706f727440616c6c6e6f6465732e636f6d00000a40616c6c6e6f646573000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714fddd722142c641e0666dc61de797e22de1ec2a15c79cc4d725fe3aeeed8f47ee6fc466644d1d3c21": "0x00000000000000000000000000000000000667667364610564667361000018677561696775616968616f303240676d61696c2e636f6d00000f40677561696775616968616f3032000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714fde28b6d3debc5d194ffa8f3ea040d3a0b39415d39710fcbb26534f05aba21f800cce0d95e3ab72b": "0x000000000000000000000000000000000009435245574d45525a00000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714fde7c0ce043a7c2de43473b2f1519b0970617b33670e00057d3379294c118fbac13505d5be3cd307": "0x000000000000000000000000000000000012524d524b205265776172642053746173680a524d524b205465616d1168747470733a2f2f726d726b2e617070000f68656c6c6f40726d726b2e61707000000940726d726b617070000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714fdee11c887534b61c8c8ab85b285f3b6e7927b775058a6e359e7bdab7e514d4450eb10199b1e2f59": "0x000000000000000000000000000000000009706f6c6b61646f7400000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714fdfdaed8db3ace0e7607dd168d84f61f878d7cd383e62e55e6e5cd1e34870ac8e6f1c294f6db5133": "0x0000000000000000000000000000000000054261626100000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714fe01bd1d10220f3e48caaec6c160b794721459c9d63038ea108a42f712993126256c6199f5358a15": "0x00000000000000000000000000000000000f62696e616e63655f6b736d5f33380f62696e616e63655f6b736d5f3338000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714fe0e61bb6b0e225d68170716ab7c6735dd0a1012045d9ea33891b5f6596cf97eb217d0962d86a518": "0x04010000000200000000000000000000000000000000076f6c616e6f640d44616e69656c204f6c616e6f1a68747470733a2f2f6769746875622e636f6d2f6f6c616e6f6418406f6c616e6f643a766972746f2e636f6d6d756e6974791264616e69656c40766972746f2e7465616d000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714fe0feebd17524d7b067b047f02b57d4c77caf508cfa3944d8dbf8cbc0a829ee797ae5d6fbed6047f": "0x00000000000000000000000000000000000000000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714fe13e8d69b79bd114ce421370cf0257d869618ec25c324ed4c6c7f65289297a3c134332c212e350b": "0x04010000000200000000000000000000000000000000174d617276696e207c205068616c61204e6574776f726b001668747470733a2f2f7068616c612e6e6574776f726b17406d617276696e746f6e673a6d61747269782e6f7267156d617276696e407068616c612e6e6574776f726b00000d406d617276696e5f746f6e67000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714fe162307295d89a332b6c05262048d5163640a9186784b80d74f6b6a8e1d72e31ed157a683c47103": "0x040000000002000000000000000000000000000000000e47726565656e204b7573616d6100001440677265656e30783a6d61747269782e6f726714677265656e3078406d61696c626f782e6f726700000c4047726565656e49744973000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714fe17f42c36004fd896505b10e2945a156440b36b640f87c7f88566ff332a9bd30caca8266a83126a": "0x00000000000000000000000000000000001e3520666f7220546865204b7573202853706f6e736f7220456e747279290000000000000f405468654b7573616d617269616e000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714fe1c0833ec392131b0d633f222e86340e41e28d35e643dfb99d9bb411f46de3ade8d52601fc7d349": "0x0400000000020000000000000000000000000000000012426173617261625f56616c696461746f7200001a4079657668656e626173617261623a6d61747269782e6f72671a657667656e69792e6261736172616240676d61696c2e636f6d000011406768366d786a78384f437754776373000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714fe2795bc5fbd003faedfec0ea8f603e5915da43d878d9aeca5066170b32b4ea1e6d770603c38ef27": "0x0000000000000000000000000000000000066972796e610000001c70616c616d6172656e6b6f6972796e616940676d61696c2e636f6d000011404972796e6150616c616d6172656e31000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714fe3b1c73aae091b8a4c6cfc20e8d5395e20291d6339f9c9e7f8df2bd4a5484010ba21089fed5db3d": "0x0000000000000000000000000000000000104261737461726420467269656e6473002168747470733a2f2f6c696e6b74722e65652f42617374617264467269656e6473001c62617374617264667269656e64736e667440676d61696c2e636f6d0000104042617374617264467269656e6473000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714fe4d46576752d75cce9903fecc2415a9ce35e5a39384b5005c1c1be3dbde661f3790fa6ef3d2d00d": "0x0000000000000000000000000000000000084772616e696141074c7975626f762168747470733a2f2f656469746f722e7769782e636f6d2f776562736974652f6200156772616e69616131313340676d61696c2e636f6d00000f404772616e6961414e6674617274000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714fe6c02a3d52a3ec7cc8b278ce627c23466aa5cb78b29ebddc340592d76013e1b36c5928a655b2c2d": "0x00000000000000000000000000000000000a4e657572616c41727405416c65780000167374735f6a6f6b657240686f746d61696c2e636f6d000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714fe77fb272c40cb3db6b5592052813d13946ba4cbe6b2a28b44e6bd1e4c858e0c27beff6fbd288115": "0x00000000000000000000000000000000000e506f6e74656d204b7573616d610f506f6e74656d204e6574776f726b1768747470733a2f2f706f6e74656d2e6e6574776f726b000000000f40706f6e74656d6e6574776f726b000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714feb09bd923dd400cca437639da37528d8edc0bb6b31966fdc0263218f4bd60c6f2cc37e963090371": "0x04000000000200000000000000000000000000000000064d6172733200000018746f7468656d6172733230323240676d61696c2e636f6d000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714fec276262411f83c54f248466e58cb2d3f15705e84d9cb4b5bc4cf4305e227c91b9754b1f3d2350a": "0x040100000002000000000000000000000000000000000a436f736d6f74726f6e0000001d636f736d6f74726f6e76616c696461746f7240676d61696c2e636f6d00000c40436f736d6f74726f6e56000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714fec4b60935b1627f3ecdb909643a31da23e3dec041ef8920632ec16fc5157297084eda7515badf68": "0x040000000002000000000000000000000000000000000f54617274616e205374616b696e6700001640616b68616e61746f6e3a6d61747269782e6f72671368656c6c6f40676f74617274616e2e636f6d00000b40616b68616e61746f6e000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714fee0771ebef0f5076e208dee4a11c78082248fdff110afc5decb7af87c23a482042b462e463ece3e": "0x00000000000000000000000000000000000000000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714fef0ad65a6e85d2fde8ba07168793b94e1f519c5a9485051c0cb161a10396fa38a5595887391da7f": "0x04010000000200000000000000000000000000000000054a61636b0e48752d4368656e672c204c65650016406a61636b37373132313a6d61747269782e6f7267146a61636b373731323140676d61696c2e636f6d00000b406a61636b3737313231000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714fef1a8c1f1bd721354cbb4f2c8af1be474301d9c9dabc20015aa5779c5885e77010252388b2b7c52": "0x000000000000000000000000000000000000000000000000104049736b616e6465725f636973636f000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714fefd9747bbaa6bd3dcfb89b5a15f3ed2e569b3ee58578a17ec547d42012d96c554b0154100793763": "0x0000000000000000000000000000000000134b7570706c657320636f6c6c656374696f6e0c477265656e204170706c65010101000001000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714ff27f362e41c7ee9487d7703ee644d9a9b59ad29aa7f27405851496306f69678965f1d18d1478740": "0x04000000000200000000000000000000000000000000086c75636b797665000014406c75636b7976653a6d61747269782e6f7267166c75636b7976656e6f646540676d61696c2e636f6d000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714ff295740e7cd48bec0fbef55637049c7352c1ef13f5db86359684ee1dfc32f76ce66c56776580b3a": "0x00000000000000000000000000000000000d524d524b204c6567656e64730000000000000d40726d726b6c6567656e6473000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714ff433a59c94c606d1c7c5bda689e0f7fff1f0012cd9c92d3ffdb3150b7585ca8e45d936a8c982674": "0x00000000000000000000000000000000000d46616c6361726975735f4b6f0756696b746f722168747470733a2f2f7777772e696e7374616772616d2e636f6d2f66616c636172164066616c6361726975733a6d61747269782e6f726714736172616e7461373240676d61696c2e636f6d00000e4046616c6361726975735f4b6f000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714ff58ab16118773668c1f986613ba74c810f3a640551d9a1d0831d4430eb9da2246019323f23ee244": "0x0000000000000000000000000000000000046a6163046a61630000196a61636f706f6d616e4070726f746f6e6d61696c2e636f6d000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714ff6779e6b83193fd281ba40c7b713abdb2ea8a124dec72cfd63d40bcc59b69550a0bf71c9a0d118f": "0x00000000000000000000000000000000000f476162652773204f6d6e6973696700000000000000000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714ff85748c4b4f90b8548b99326157f4a2e39916a7ea20553d6964876bd6b583108f36e8941bcef951": "0x00000000000000000000000000000000000101010101000001000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714ffb949961e1fd85deea39739cf422a6c6b2f350d2efb92428b71b408ef76b64165c32fedb7d32f16": "0x00000000000000000000000000000000000a4d616c6f6d62726573000000146d616c6f6d6272657340676d61696c2e636f6d00000f40545f4d616c6f6d627265735f54000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714ffb95c1195a068daa023764a372deb88243537045ff9b3144219b315385c1d8e8de6761542410d61": "0x00000000000000000000000000000000000b617065586368696d707a001d68747470733a2f2f6c696e6b74722e65652f617065586368696d707a0015746f75636840617065786368696d707a2e636f6d00000c40617065586368696d707a000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714ffc544aa04d3feb9a69484f2b10ec2f1dea19394423d576f91c6b5ab2315b389f4e108bcf0aa2840": "0x040000000002000000000000000000000000000000000a4661626920f09f90920000000000000d4066616269616e676f6d7066000000", + "0x2aeddc77fe58c98d50bd37f1b90840f9cd7f37317cd20b61e9bd46fab8704714ffee713c9a5ac32ea6a111bb9d56b51fd2648f68629b4e87f7b92915a16967f6d1a5777dfcbfc714": "0x040100000002000000000000000000000000000000000a487970657263756265001c68747470733a2f2f7777772e6879706572637562652e766964656f00166a6f657269406879706572637562652e766964656f000000000000" }, "childrenDefault": {} } } -} \ No newline at end of file +} diff --git a/cumulus/parachains/chain-specs/people-rococo.json b/cumulus/parachains/chain-specs/people-rococo.json index b2819157152174cd803e55cc7ede8fd38a626e08..a4361b77df790ad816d3c95afcf93c0575ee2b85 100644 --- a/cumulus/parachains/chain-specs/people-rococo.json +++ b/cumulus/parachains/chain-specs/people-rococo.json @@ -4,13 +4,11 @@ "chainType": "Live", "bootNodes": [ "/dns/rococo-people-collator-node-0.parity-testnet.parity.io/tcp/30333/p2p/12D3KooWDZg5jMYhKXTu6RU491V5sxsFnP4oaEmZJEUfcRkYzps5", - "/dns/rococo-people-collator-node-0.parity-testnet.parity.io/tcp/443/wss/p2p/12D3KooWDZg5jMYhKXTu6RU491V5sxsFnP4oaEmZJEUfcRkYzps5", "/dns/rococo-people-collator-node-1.parity-testnet.parity.io/tcp/30333/p2p/12D3KooWGGR5i6qQqfo7iDNp7vjDRKPWuDk53idGV6nFLwS12X5H", - "/dns/rococo-people-collator-node-1.parity-testnet.parity.io/tcp/443/wss/p2p/12D3KooWGGR5i6qQqfo7iDNp7vjDRKPWuDk53idGV6nFLwS12X5H", - "/dns/rococo-people-collator-node-2.parity-testnet.parity.io/tcp/30333/p2p/12D3KooWBvA9BmBfrsVMcAcqVXGYFCpMTvkSk2igNXpmoareYbeT", - "/dns/rococo-people-collator-node-2.parity-testnet.parity.io/tcp/443/wss/p2p/12D3KooWBvA9BmBfrsVMcAcqVXGYFCpMTvkSk2igNXpmoareYbeT", - "/dns/rococo-people-collator-node-3.parity-testnet.parity.io/tcp/30333/p2p/12D3KooWQ7Q9jLcJTPXy7KEp5hSZ8YMY9pHx9CnQVz3T8TKQ81UG", - "/dns/rococo-people-collator-node-3.parity-testnet.parity.io/tcp/443/wss/p2p/12D3KooWQ7Q9jLcJTPXy7KEp5hSZ8YMY9pHx9CnQVz3T8TKQ81UG" + "/dns/rococo-people-collator-node-0.parity-testnet.parity.io/tcp/30335/ws/p2p/12D3KooWDZg5jMYhKXTu6RU491V5sxsFnP4oaEmZJEUfcRkYzps5", + "/dns/rococo-people-collator-node-1.parity-testnet.parity.io/tcp/30335/ws/p2p/12D3KooWGGR5i6qQqfo7iDNp7vjDRKPWuDk53idGV6nFLwS12X5H", + "/dns/rococo-people-collator-node-0.parity-testnet.parity.io/tcp/443/wss/p2p/12D3KooWDZg5jMYhKXTu6RU491V5sxsFnP4oaEmZJEUfcRkYzps5", + "/dns/rococo-people-collator-node-1.parity-testnet.parity.io/tcp/443/wss/p2p/12D3KooWGGR5i6qQqfo7iDNp7vjDRKPWuDk53idGV6nFLwS12X5H" ], "telemetryEndpoints": null, "protocolId": null, @@ -79,4 +77,4 @@ "childrenDefault": {} } } -} \ No newline at end of file +} diff --git a/cumulus/parachains/chain-specs/people-westend.json b/cumulus/parachains/chain-specs/people-westend.json index 6dd8579cf257049edc1159f6b06d5d670284f7a9..26e165b4839fcaa895bfdf0f7f4c1242b8513968 100644 --- a/cumulus/parachains/chain-specs/people-westend.json +++ b/cumulus/parachains/chain-specs/people-westend.json @@ -4,8 +4,10 @@ "chainType": "Live", "bootNodes": [ "/dns/westend-people-collator-node-0.parity-testnet.parity.io/tcp/30333/p2p/12D3KooWDcLjDLTu9fNhmas9DTWtqdv8eUbFMWQzVwvXRK7QcjHD", - "/dns/westend-people-collator-node-0.parity-testnet.parity.io/tcp/443/wss/p2p/12D3KooWDcLjDLTu9fNhmas9DTWtqdv8eUbFMWQzVwvXRK7QcjHD", "/dns/westend-people-collator-node-1.parity-testnet.parity.io/tcp/30333/p2p/12D3KooWM56JbKWAXsDyWh313z73aKYVMp1Hj2nSnAKY3q6MnoC9", + "/dns/westend-people-collator-node-0.parity-testnet.parity.io/tcp/30335/ws/p2p/12D3KooWDcLjDLTu9fNhmas9DTWtqdv8eUbFMWQzVwvXRK7QcjHD", + "/dns/westend-people-collator-node-1.parity-testnet.parity.io/tcp/30335/ws/p2p/12D3KooWM56JbKWAXsDyWh313z73aKYVMp1Hj2nSnAKY3q6MnoC9", + "/dns/westend-people-collator-node-0.parity-testnet.parity.io/tcp/443/wss/p2p/12D3KooWDcLjDLTu9fNhmas9DTWtqdv8eUbFMWQzVwvXRK7QcjHD", "/dns/westend-people-collator-node-1.parity-testnet.parity.io/tcp/443/wss/p2p/12D3KooWM56JbKWAXsDyWh313z73aKYVMp1Hj2nSnAKY3q6MnoC9", "/dns/identity-westend.bootnodes.polkadotters.com/tcp/30532/p2p/12D3KooWKr9San6KTM7REJ95cBaDoiciGcWnW8TTftEJgxGF5Ehb", "/dns/identity-westend.bootnodes.polkadotters.com/tcp/30534/wss/p2p/12D3KooWKr9San6KTM7REJ95cBaDoiciGcWnW8TTftEJgxGF5Ehb", @@ -23,6 +25,8 @@ "/dns/people-westend.bootnode.amforc.com/tcp/30346/p2p/12D3KooWQrMQFAXxJJJCtVr8nViBR6EDsuT1RyqU3eoCMebRQxTf", "/dns/people-westend-bootnode.turboflakes.io/tcp/30650/p2p/12D3KooWQEhmZg3uMkuxVUx3jbsD84zEX4dUKtvHfmCoBWMhybKW", "/dns/people-westend-bootnode.turboflakes.io/tcp/30750/wss/p2p/12D3KooWQEhmZg3uMkuxVUx3jbsD84zEX4dUKtvHfmCoBWMhybKW", + "/dns/wppl16.rotko.net/tcp/33766/p2p/12D3KooWHwUXBUo2WRMUBwPLC2ttVbnEk1KvDyESYAeKcNoCn7WS", + "/dns/wppl16.rotko.net/tcp/35766/wss/p2p/12D3KooWHwUXBUo2WRMUBwPLC2ttVbnEk1KvDyESYAeKcNoCn7WS", "/dns/people-westend-boot-ng.dwellir.com/tcp/443/wss/p2p/12D3KooWBdCpCabhgBpLn67LWcXE2JJCCTMhuJHrfDNiTiCCr3KX", "/dns/people-westend-boot-ng.dwellir.com/tcp/30355/p2p/12D3KooWBdCpCabhgBpLn67LWcXE2JJCCTMhuJHrfDNiTiCCr3KX" ], diff --git a/cumulus/parachains/common/Cargo.toml b/cumulus/parachains/common/Cargo.toml index fa16205d0fd1adee1491cf3abb92a55829b16a44..2b943b6dca55989a891895b4abb3195970978b06 100644 --- a/cumulus/parachains/common/Cargo.toml +++ b/cumulus/parachains/common/Cargo.toml @@ -13,7 +13,7 @@ workspace = true targets = ["x86_64-unknown-linux-gnu"] [dependencies] -codec = { package = "parity-scale-codec", version = "3.0.0", features = ["derive"], default-features = false } +codec = { package = "parity-scale-codec", version = "3.6.12", features = ["derive"], default-features = false } log = { workspace = true } scale-info = { version = "2.11.1", default-features = false, features = ["derive"] } diff --git a/cumulus/parachains/integration-tests/emulated/chains/relays/rococo/src/lib.rs b/cumulus/parachains/integration-tests/emulated/chains/relays/rococo/src/lib.rs index 379a29d697bcb564b670eadb638f7088f042137a..7a3a936ec972f0a8c99e3b472c7cce9e9914e29c 100644 --- a/cumulus/parachains/integration-tests/emulated/chains/relays/rococo/src/lib.rs +++ b/cumulus/parachains/integration-tests/emulated/chains/relays/rococo/src/lib.rs @@ -39,6 +39,8 @@ decl_test_relay_chains! { Hrmp: rococo_runtime::Hrmp, Identity: rococo_runtime::Identity, IdentityMigrator: rococo_runtime::IdentityMigrator, + Treasury: rococo_runtime::Treasury, + AssetRate: rococo_runtime::AssetRate, } }, } diff --git a/cumulus/parachains/integration-tests/emulated/chains/relays/westend/Cargo.toml b/cumulus/parachains/integration-tests/emulated/chains/relays/westend/Cargo.toml index 12a3ad60e0e046f1881d322118d522da3f9b52b1..e4688a1c9f022dd9aafd821ee39bfc5906a7b2a0 100644 --- a/cumulus/parachains/integration-tests/emulated/chains/relays/westend/Cargo.toml +++ b/cumulus/parachains/integration-tests/emulated/chains/relays/westend/Cargo.toml @@ -11,6 +11,7 @@ publish = false workspace = true [dependencies] + # Substrate sp-core = { path = "../../../../../../../substrate/primitives/core", default-features = false } sp-runtime = { path = "../../../../../../../substrate/primitives/runtime", default-features = false } @@ -24,6 +25,8 @@ pallet-staking = { path = "../../../../../../../substrate/frame/staking", defaul polkadot-primitives = { path = "../../../../../../../polkadot/primitives", default-features = false } westend-runtime-constants = { path = "../../../../../../../polkadot/runtime/westend/constants", default-features = false } westend-runtime = { path = "../../../../../../../polkadot/runtime/westend" } +xcm = { package = "staging-xcm", path = "../../../../../../../polkadot/xcm", default-features = false } +xcm-fee-payment-runtime-api = { path = "../../../../../../../polkadot/xcm/xcm-fee-payment-runtime-api", default-features = false } # Cumulus parachains-common = { path = "../../../../../common" } diff --git a/cumulus/parachains/integration-tests/emulated/common/Cargo.toml b/cumulus/parachains/integration-tests/emulated/common/Cargo.toml index 8c44cce7d922dff0a69a4273af7adb69819d2fce..b010d2a296382f2f2d5f8ffd889f4643a17098d0 100644 --- a/cumulus/parachains/integration-tests/emulated/common/Cargo.toml +++ b/cumulus/parachains/integration-tests/emulated/common/Cargo.toml @@ -10,7 +10,7 @@ description = "Common resources for integration testing with xcm-emulator" workspace = true [dependencies] -codec = { package = "parity-scale-codec", version = "3.4.0", default-features = false } +codec = { package = "parity-scale-codec", version = "3.6.12", default-features = false } paste = "1.0.14" # Substrate diff --git a/cumulus/parachains/integration-tests/emulated/common/src/impls.rs b/cumulus/parachains/integration-tests/emulated/common/src/impls.rs index c8a2f097abe95bb0f6003957c7ef5cc90c4f09c3..8f2789eb2f3a0e45d5c98263a16a118bd63cb425 100644 --- a/cumulus/parachains/integration-tests/emulated/common/src/impls.rs +++ b/cumulus/parachains/integration-tests/emulated/common/src/impls.rs @@ -360,7 +360,7 @@ macro_rules! impl_send_transact_helpers_for_relay_chain { recipient: $crate::impls::ParaId, call: $crate::impls::DoubleEncoded<()> ) { - use $crate::impls::{bx, Chain, RelayChain, Encode}; + use $crate::impls::{bx, Chain, RelayChain}; ::execute_with(|| { let root_origin = ::RuntimeOrigin::root(); @@ -368,10 +368,10 @@ macro_rules! impl_send_transact_helpers_for_relay_chain { let xcm = $crate::impls::xcm_transact_unpaid_execution(call, $crate::impls::OriginKind::Superuser); // Send XCM `Transact` - $crate::impls::assert_ok!(]>::XcmPallet::send_blob( + $crate::impls::assert_ok!(]>::XcmPallet::send( root_origin, bx!(destination.into()), - xcm.encode().try_into().unwrap(), + bx!(xcm), )); Self::assert_xcm_pallet_sent(); }); diff --git a/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-rococo/Cargo.toml b/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-rococo/Cargo.toml index c5a672234a0d21603c86b64af75adc57beffb81b..9abecbecc48a725448cfb17508351d5e76f848de 100644 --- a/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-rococo/Cargo.toml +++ b/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-rococo/Cargo.toml @@ -11,7 +11,7 @@ publish = false workspace = true [dependencies] -codec = { package = "parity-scale-codec", version = "3.4.0", default-features = false } +codec = { package = "parity-scale-codec", version = "3.6.12", default-features = false } assert_matches = "1.5.0" # Substrate @@ -21,15 +21,20 @@ pallet-balances = { path = "../../../../../../../substrate/frame/balances", defa pallet-assets = { path = "../../../../../../../substrate/frame/assets", default-features = false } pallet-asset-conversion = { path = "../../../../../../../substrate/frame/asset-conversion", default-features = false } pallet-message-queue = { path = "../../../../../../../substrate/frame/message-queue", default-features = false } +pallet-treasury = { path = "../../../../../../../substrate/frame/treasury", default-features = false } +pallet-utility = { path = "../../../../../../../substrate/frame/utility", default-features = false } # Polkadot xcm = { package = "staging-xcm", path = "../../../../../../../polkadot/xcm", default-features = false } pallet-xcm = { path = "../../../../../../../polkadot/xcm/pallet-xcm", default-features = false } xcm-executor = { package = "staging-xcm-executor", path = "../../../../../../../polkadot/xcm/xcm-executor", default-features = false } rococo-runtime = { path = "../../../../../../../polkadot/runtime/rococo" } +polkadot-runtime-common = { path = "../../../../../../../polkadot/runtime/common" } +rococo-runtime-constants = { path = "../../../../../../../polkadot/runtime/rococo/constants" } # Cumulus asset-test-utils = { path = "../../../../../runtimes/assets/test-utils" } +cumulus-pallet-parachain-system = { path = "../../../../../../pallets/parachain-system", default-features = false } parachains-common = { path = "../../../../../common" } asset-hub-rococo-runtime = { path = "../../../../../runtimes/assets/asset-hub-rococo" } penpal-runtime = { path = "../../../../../runtimes/testing/penpal" } diff --git a/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-rococo/src/lib.rs b/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-rococo/src/lib.rs index 322c6cf1f2282670e474b0c5737fabd09afbe94d..2bd388bee400ed2e61869e126a1828b93422f2c0 100644 --- a/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-rococo/src/lib.rs +++ b/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-rococo/src/lib.rs @@ -70,7 +70,9 @@ mod imports { LocalReservableFromAssetHub as PenpalLocalReservableFromAssetHub, LocalTeleportableToAssetHub as PenpalLocalTeleportableToAssetHub, }; - pub use rococo_runtime::xcm_config::XcmConfig as RococoXcmConfig; + pub use rococo_runtime::xcm_config::{ + UniversalLocation as RococoUniversalLocation, XcmConfig as RococoXcmConfig, + }; pub const ASSET_ID: u32 = 3; pub const ASSET_MIN_BALANCE: u128 = 1000; @@ -83,6 +85,7 @@ mod imports { pub type ParaToSystemParaTest = Test; pub type ParaToParaThroughRelayTest = Test; pub type ParaToParaThroughAHTest = Test; + pub type RelayToParaThroughAHTest = Test; } #[cfg(test)] diff --git a/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-rococo/src/tests/foreign_assets_transfers.rs b/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-rococo/src/tests/hybrid_transfers.rs similarity index 76% rename from cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-rococo/src/tests/foreign_assets_transfers.rs rename to cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-rococo/src/tests/hybrid_transfers.rs index 6bdf89e6f277edb7d0e6e85383223d52b24c89ea..edaaa998a9ca11f97b9d2c85e8b2b88d1c570fbc 100644 --- a/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-rococo/src/tests/foreign_assets_transfers.rs +++ b/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-rococo/src/tests/hybrid_transfers.rs @@ -54,14 +54,18 @@ fn para_to_para_assethub_hop_assertions(t: ParaToParaThroughAHTest) { fn ah_to_para_transfer_assets(t: SystemParaToParaTest) -> DispatchResult { let fee_idx = t.args.fee_asset_item as usize; let fee: Asset = t.args.assets.inner().get(fee_idx).cloned().unwrap(); - ::PolkadotXcm::transfer_assets_using_type( + let custom_xcm_on_dest = Xcm::<()>(vec![DepositAsset { + assets: Wild(AllCounted(t.args.assets.len() as u32)), + beneficiary: t.args.beneficiary, + }]); + ::PolkadotXcm::transfer_assets_using_type_and_then( t.signed_origin, bx!(t.args.dest.into()), - bx!(t.args.beneficiary.into()), bx!(t.args.assets.into()), bx!(TransferType::LocalReserve), bx!(fee.id.into()), bx!(TransferType::LocalReserve), + bx!(VersionedXcm::from(custom_xcm_on_dest)), t.args.weight_limit, ) } @@ -69,14 +73,18 @@ fn ah_to_para_transfer_assets(t: SystemParaToParaTest) -> DispatchResult { fn para_to_ah_transfer_assets(t: ParaToSystemParaTest) -> DispatchResult { let fee_idx = t.args.fee_asset_item as usize; let fee: Asset = t.args.assets.inner().get(fee_idx).cloned().unwrap(); - ::PolkadotXcm::transfer_assets_using_type( + let custom_xcm_on_dest = Xcm::<()>(vec![DepositAsset { + assets: Wild(AllCounted(t.args.assets.len() as u32)), + beneficiary: t.args.beneficiary, + }]); + ::PolkadotXcm::transfer_assets_using_type_and_then( t.signed_origin, bx!(t.args.dest.into()), - bx!(t.args.beneficiary.into()), bx!(t.args.assets.into()), bx!(TransferType::DestinationReserve), bx!(fee.id.into()), bx!(TransferType::DestinationReserve), + bx!(VersionedXcm::from(custom_xcm_on_dest)), t.args.weight_limit, ) } @@ -85,14 +93,18 @@ fn para_to_para_transfer_assets_through_ah(t: ParaToParaThroughAHTest) -> Dispat let fee_idx = t.args.fee_asset_item as usize; let fee: Asset = t.args.assets.inner().get(fee_idx).cloned().unwrap(); let asset_hub_location: Location = PenpalA::sibling_location_of(AssetHubRococo::para_id()); - ::PolkadotXcm::transfer_assets_using_type( + let custom_xcm_on_dest = Xcm::<()>(vec![DepositAsset { + assets: Wild(AllCounted(t.args.assets.len() as u32)), + beneficiary: t.args.beneficiary, + }]); + ::PolkadotXcm::transfer_assets_using_type_and_then( t.signed_origin, bx!(t.args.dest.into()), - bx!(t.args.beneficiary.into()), bx!(t.args.assets.into()), bx!(TransferType::RemoteReserve(asset_hub_location.clone().into())), bx!(fee.id.into()), bx!(TransferType::RemoteReserve(asset_hub_location.into())), + bx!(VersionedXcm::from(custom_xcm_on_dest)), t.args.weight_limit, ) } @@ -100,14 +112,18 @@ fn para_to_para_transfer_assets_through_ah(t: ParaToParaThroughAHTest) -> Dispat fn para_to_asset_hub_teleport_foreign_assets(t: ParaToSystemParaTest) -> DispatchResult { let fee_idx = t.args.fee_asset_item as usize; let fee: Asset = t.args.assets.inner().get(fee_idx).cloned().unwrap(); - ::PolkadotXcm::transfer_assets_using_type( + let custom_xcm_on_dest = Xcm::<()>(vec![DepositAsset { + assets: Wild(AllCounted(t.args.assets.len() as u32)), + beneficiary: t.args.beneficiary, + }]); + ::PolkadotXcm::transfer_assets_using_type_and_then( t.signed_origin, bx!(t.args.dest.into()), - bx!(t.args.beneficiary.into()), bx!(t.args.assets.into()), bx!(TransferType::Teleport), bx!(fee.id.into()), bx!(TransferType::DestinationReserve), + bx!(VersionedXcm::from(custom_xcm_on_dest)), t.args.weight_limit, ) } @@ -115,14 +131,18 @@ fn para_to_asset_hub_teleport_foreign_assets(t: ParaToSystemParaTest) -> Dispatc fn asset_hub_to_para_teleport_foreign_assets(t: SystemParaToParaTest) -> DispatchResult { let fee_idx = t.args.fee_asset_item as usize; let fee: Asset = t.args.assets.inner().get(fee_idx).cloned().unwrap(); - ::PolkadotXcm::transfer_assets_using_type( + let custom_xcm_on_dest = Xcm::<()>(vec![DepositAsset { + assets: Wild(AllCounted(t.args.assets.len() as u32)), + beneficiary: t.args.beneficiary, + }]); + ::PolkadotXcm::transfer_assets_using_type_and_then( t.signed_origin, bx!(t.args.dest.into()), - bx!(t.args.beneficiary.into()), bx!(t.args.assets.into()), bx!(TransferType::Teleport), bx!(fee.id.into()), bx!(TransferType::LocalReserve), + bx!(VersionedXcm::from(custom_xcm_on_dest)), t.args.weight_limit, ) } @@ -626,3 +646,166 @@ fn bidirectional_teleport_foreign_asset_between_para_and_asset_hub_using_explici asset_hub_to_para_teleport_foreign_assets, ); } + +// =============================================================== +// ===== Transfer - Native Asset - Relay->AssetHub->Parachain ==== +// =============================================================== +/// Transfers of native asset Relay to Parachain (using AssetHub reserve). Parachains want to avoid +/// managing SAs on all system chains, thus want all their DOT-in-reserve to be held in their +/// Sovereign Account on Asset Hub. +#[test] +fn transfer_native_asset_from_relay_to_para_through_asset_hub() { + // Init values for Relay + let destination = Rococo::child_location_of(PenpalA::para_id()); + let sender = RococoSender::get(); + let amount_to_send: Balance = ROCOCO_ED * 1000; + + // Init values for Parachain + let relay_native_asset_location = RelayLocation::get(); + let receiver = PenpalAReceiver::get(); + + // Init Test + let test_args = TestContext { + sender, + receiver: receiver.clone(), + args: TestArgs::new_relay(destination.clone(), receiver.clone(), amount_to_send), + }; + let mut test = RelayToParaThroughAHTest::new(test_args); + + let sov_penpal_on_ah = AssetHubRococo::sovereign_account_id_of( + AssetHubRococo::sibling_location_of(PenpalA::para_id()), + ); + // Query initial balances + let sender_balance_before = test.sender.balance; + let sov_penpal_on_ah_before = AssetHubRococo::execute_with(|| { + ::Balances::free_balance(sov_penpal_on_ah.clone()) + }); + let receiver_assets_before = PenpalA::execute_with(|| { + type ForeignAssets = ::ForeignAssets; + >::balance(relay_native_asset_location.clone(), &receiver) + }); + + fn relay_assertions(t: RelayToParaThroughAHTest) { + type RuntimeEvent = ::RuntimeEvent; + Rococo::assert_xcm_pallet_attempted_complete(None); + assert_expected_events!( + Rococo, + vec![ + // Amount to teleport is withdrawn from Sender + 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::Minted { who, amount }) => { + who: *who == ::XcmPallet::check_account(), + amount: *amount == t.args.amount, + }, + ] + ); + } + fn asset_hub_assertions(_: RelayToParaThroughAHTest) { + type RuntimeEvent = ::RuntimeEvent; + let sov_penpal_on_ah = AssetHubRococo::sovereign_account_id_of( + AssetHubRococo::sibling_location_of(PenpalA::para_id()), + ); + assert_expected_events!( + AssetHubRococo, + vec![ + // Deposited to receiver parachain SA + RuntimeEvent::Balances( + pallet_balances::Event::Minted { who, .. } + ) => { + who: *who == sov_penpal_on_ah, + }, + RuntimeEvent::MessageQueue( + pallet_message_queue::Event::Processed { success: true, .. } + ) => {}, + ] + ); + } + fn penpal_assertions(t: RelayToParaThroughAHTest) { + type RuntimeEvent = ::RuntimeEvent; + let expected_id = + t.args.assets.into_inner().first().unwrap().id.0.clone().try_into().unwrap(); + assert_expected_events!( + PenpalA, + vec![ + RuntimeEvent::ForeignAssets(pallet_assets::Event::Issued { asset_id, owner, .. }) => { + asset_id: *asset_id == expected_id, + owner: *owner == t.receiver.account_id, + }, + ] + ); + } + fn transfer_assets_dispatchable(t: RelayToParaThroughAHTest) -> DispatchResult { + let fee_idx = t.args.fee_asset_item as usize; + let fee: Asset = t.args.assets.inner().get(fee_idx).cloned().unwrap(); + let asset_hub_location = Rococo::child_location_of(AssetHubRococo::para_id()); + let context = RococoUniversalLocation::get(); + + // reanchor fees to the view of destination (Penpal) + let mut remote_fees = fee.clone().reanchored(&t.args.dest, &context).unwrap(); + if let Fungible(ref mut amount) = remote_fees.fun { + // we already spent some fees along the way, just use half of what we started with + *amount = *amount / 2; + } + let xcm_on_final_dest = Xcm::<()>(vec![ + BuyExecution { fees: remote_fees, weight_limit: t.args.weight_limit.clone() }, + DepositAsset { + assets: Wild(AllCounted(t.args.assets.len() as u32)), + beneficiary: t.args.beneficiary, + }, + ]); + + // reanchor final dest (Penpal) to the view of hop (Asset Hub) + let mut dest = t.args.dest.clone(); + dest.reanchor(&asset_hub_location, &context).unwrap(); + // on Asset Hub, forward assets to Penpal + let xcm_on_hop = Xcm::<()>(vec![DepositReserveAsset { + assets: Wild(AllCounted(t.args.assets.len() as u32)), + dest, + xcm: xcm_on_final_dest, + }]); + + // First leg is a teleport, from there a local-reserve-transfer to final dest + ::XcmPallet::transfer_assets_using_type_and_then( + t.signed_origin, + bx!(asset_hub_location.into()), + bx!(t.args.assets.into()), + bx!(TransferType::Teleport), + bx!(fee.id.into()), + bx!(TransferType::Teleport), + bx!(VersionedXcm::from(xcm_on_hop)), + t.args.weight_limit, + ) + } + + // Set assertions and dispatchables + test.set_assertion::(relay_assertions); + test.set_assertion::(asset_hub_assertions); + test.set_assertion::(penpal_assertions); + test.set_dispatchable::(transfer_assets_dispatchable); + test.assert(); + + // Query final balances + let sender_balance_after = test.sender.balance; + let sov_penpal_on_ah_after = AssetHubRococo::execute_with(|| { + ::Balances::free_balance(sov_penpal_on_ah) + }); + let receiver_assets_after = PenpalA::execute_with(|| { + type ForeignAssets = ::ForeignAssets; + >::balance(relay_native_asset_location, &receiver) + }); + + // Sender's balance is reduced by amount sent plus delivery fees + assert!(sender_balance_after < sender_balance_before - amount_to_send); + // SA on AH balance is increased + assert!(sov_penpal_on_ah_after > sov_penpal_on_ah_before); + // Receiver's asset balance is increased + assert!(receiver_assets_after > receiver_assets_before); + // Receiver's asset balance increased by `amount_to_send - delivery_fees - bought_execution`; + // `delivery_fees` might be paid from transfer or JIT, also `bought_execution` is unknown but + // should be non-zero + assert!(receiver_assets_after < receiver_assets_before + amount_to_send); +} diff --git a/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-rococo/src/tests/mod.rs b/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-rococo/src/tests/mod.rs index 2402989225af2a6b3d03c7f353c8b0e7266b9fb1..138ce419757b98b03d4e9a6b26259d81ca779d69 100644 --- a/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-rococo/src/tests/mod.rs +++ b/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-rococo/src/tests/mod.rs @@ -13,9 +13,10 @@ // See the License for the specific language governing permissions and // limitations under the License. -mod foreign_assets_transfers; +mod hybrid_transfers; mod reserve_transfer; mod send; mod set_xcm_versions; mod swap; mod teleport; +mod treasury; 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 5aef70f5cbfc08522a5693d38bb2c774209a2469..8b9fedcd4947cf5aaef5db0233166c6bc7cbcf21 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 @@ -574,7 +574,7 @@ fn reserve_transfer_native_asset_from_relay_to_para() { let sender = RococoSender::get(); let amount_to_send: Balance = ROCOCO_ED * 1000; - // Init values fot Parachain + // Init values for Parachain let relay_native_asset_location = RelayLocation::get(); let receiver = PenpalAReceiver::get(); diff --git a/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-rococo/src/tests/send.rs b/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-rococo/src/tests/send.rs index 1d120f1dc4c7ed4f923514e0692f3a4beb48103a..364fbd0d439f62ed1fce356d1935331ec8e0d90b 100644 --- a/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-rococo/src/tests/send.rs +++ b/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-rococo/src/tests/send.rs @@ -75,10 +75,10 @@ fn send_xcm_from_para_to_system_para_paying_fee_with_system_assets_works() { )]); PenpalA::execute_with(|| { - assert_ok!(::PolkadotXcm::send_blob( + assert_ok!(::PolkadotXcm::send( root_origin, bx!(system_para_destination), - xcm.encode().try_into().unwrap(), + bx!(xcm), )); PenpalA::assert_xcm_pallet_sent(); @@ -159,10 +159,10 @@ fn send_xcm_from_para_to_system_para_paying_fee_with_assets_works() { )]); PenpalA::execute_with(|| { - assert_ok!(::PolkadotXcm::send_blob( + assert_ok!(::PolkadotXcm::send( root_origin, bx!(system_para_destination), - xcm.encode().try_into().unwrap(), + bx!(xcm), )); PenpalA::assert_xcm_pallet_sent(); diff --git a/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-rococo/src/tests/swap.rs b/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-rococo/src/tests/swap.rs index 919e0080ba62d90a78a3738c4c8f141c01979feb..ec48e400ff545686fe728025eacc7ea5cd783d6f 100644 --- a/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-rococo/src/tests/swap.rs +++ b/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-rococo/src/tests/swap.rs @@ -372,10 +372,10 @@ fn pay_xcm_fee_with_some_asset_swapped_for_native() { penpal.clone(), ); - assert_ok!(::PolkadotXcm::send_blob( + assert_ok!(::PolkadotXcm::send( penpal_root, bx!(asset_hub_location), - xcm.encode().try_into().unwrap(), + bx!(xcm), )); PenpalA::assert_xcm_pallet_sent(); diff --git a/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-rococo/src/tests/treasury.rs b/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-rococo/src/tests/treasury.rs new file mode 100644 index 0000000000000000000000000000000000000000..01bf40ae8fdf2cf87092c83ef604ef25427e2939 --- /dev/null +++ b/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-rococo/src/tests/treasury.rs @@ -0,0 +1,270 @@ +// Copyright (C) Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +use crate::imports::*; +use emulated_integration_tests_common::accounts::{ALICE, BOB}; +use frame_support::{ + dispatch::RawOrigin, + sp_runtime::traits::Dispatchable, + traits::{ + fungible::Inspect, + fungibles::{Create, Inspect as FungiblesInspect, Mutate}, + }, +}; +use parachains_common::AccountId; +use polkadot_runtime_common::impls::VersionedLocatableAsset; +use rococo_runtime::OriginCaller; +use rococo_runtime_constants::currency::GRAND; +use xcm_executor::traits::ConvertLocation; + +// Fund Treasury account on Asset Hub from Treasury account on Relay Chain with ROCs. +#[test] +fn spend_roc_on_asset_hub() { + // initial treasury balance on Asset Hub in ROCs. + let treasury_balance = 9_000 * GRAND; + // the balance spend on Asset Hub. + let treasury_spend_balance = 1_000 * GRAND; + + let init_alice_balance = AssetHubRococo::execute_with(|| { + <::Balances as Inspect<_>>::balance( + &AssetHubRococo::account_id_of(ALICE), + ) + }); + + Rococo::execute_with(|| { + type RuntimeEvent = ::RuntimeEvent; + type RuntimeCall = ::RuntimeCall; + type Runtime = ::Runtime; + type Balances = ::Balances; + type Treasury = ::Treasury; + + // Fund Treasury account on Asset Hub with ROCs. + + let root = ::RuntimeOrigin::root(); + let treasury_account = Treasury::account_id(); + + // Mint assets to Treasury account on Relay Chain. + assert_ok!(Balances::force_set_balance( + root.clone(), + treasury_account.clone().into(), + treasury_balance * 2, + )); + + let native_asset = Location::here(); + let asset_hub_location: Location = [Parachain(1000)].into(); + let treasury_location: Location = (Parent, PalletInstance(18)).into(); + + let teleport_call = RuntimeCall::Utility(pallet_utility::Call::::dispatch_as { + as_origin: bx!(OriginCaller::system(RawOrigin::Signed(treasury_account))), + call: bx!(RuntimeCall::XcmPallet(pallet_xcm::Call::::teleport_assets { + dest: bx!(VersionedLocation::V4(asset_hub_location.clone())), + beneficiary: bx!(VersionedLocation::V4(treasury_location)), + assets: bx!(VersionedAssets::V4( + Asset { id: native_asset.clone().into(), fun: treasury_balance.into() }.into() + )), + fee_asset_item: 0, + })), + }); + + // Dispatched from Root to `despatch_as` `Signed(treasury_account)`. + assert_ok!(teleport_call.dispatch(root)); + + assert_expected_events!( + Rococo, + vec![ + RuntimeEvent::XcmPallet(pallet_xcm::Event::Sent { .. }) => {}, + ] + ); + }); + + Rococo::execute_with(|| { + type RuntimeEvent = ::RuntimeEvent; + type RuntimeCall = ::RuntimeCall; + type RuntimeOrigin = ::RuntimeOrigin; + type Runtime = ::Runtime; + type Treasury = ::Treasury; + + // Fund Alice account from Rococo Treasury account on Asset Hub. + + let treasury_origin: RuntimeOrigin = + rococo_runtime::governance::pallet_custom_origins::Origin::Treasurer.into(); + + let alice_location: Location = + [Junction::AccountId32 { network: None, id: Rococo::account_id_of(ALICE).into() }] + .into(); + let asset_hub_location: Location = [Parachain(1000)].into(); + let native_asset = Location::parent(); + + let treasury_spend_call = RuntimeCall::Treasury(pallet_treasury::Call::::spend { + asset_kind: bx!(VersionedLocatableAsset::V4 { + location: asset_hub_location.clone(), + asset_id: native_asset.into(), + }), + amount: treasury_spend_balance, + beneficiary: bx!(VersionedLocation::V4(alice_location)), + valid_from: None, + }); + + assert_ok!(treasury_spend_call.dispatch(treasury_origin)); + + // Claim the spend. + + let bob_signed = RuntimeOrigin::signed(Rococo::account_id_of(BOB)); + assert_ok!(Treasury::payout(bob_signed.clone(), 0)); + + assert_expected_events!( + Rococo, + vec![ + RuntimeEvent::Treasury(pallet_treasury::Event::AssetSpendApproved { .. }) => {}, + RuntimeEvent::Treasury(pallet_treasury::Event::Paid { .. }) => {}, + ] + ); + }); + + AssetHubRococo::execute_with(|| { + type RuntimeEvent = ::RuntimeEvent; + type Balances = ::Balances; + + // Ensure that the funds deposited to Alice account. + + let alice_account = AssetHubRococo::account_id_of(ALICE); + assert_eq!( + >::balance(&alice_account), + treasury_spend_balance + init_alice_balance + ); + + // Assert events triggered by xcm pay program: + // 1. treasury asset transferred to spend beneficiary; + // 2. response to Relay Chain Treasury pallet instance sent back; + // 3. XCM program completed; + assert_expected_events!( + AssetHubRococo, + vec![ + RuntimeEvent::Balances(pallet_balances::Event::Transfer { .. }) => {}, + RuntimeEvent::ParachainSystem(cumulus_pallet_parachain_system::Event::UpwardMessageSent { .. }) => {}, + RuntimeEvent::MessageQueue(pallet_message_queue::Event::Processed { success: true ,.. }) => {}, + ] + ); + }); +} + +#[test] +fn create_and_claim_treasury_spend_in_usdt() { + const ASSET_ID: u32 = 1984; + const SPEND_AMOUNT: u128 = 1_000_000; + // treasury location from a sibling parachain. + let treasury_location: Location = Location::new(1, PalletInstance(18)); + // treasury account on a sibling parachain. + let treasury_account = + asset_hub_rococo_runtime::xcm_config::LocationToAccountId::convert_location( + &treasury_location, + ) + .unwrap(); + let asset_hub_location = + v3::Location::new(0, v3::Junction::Parachain(AssetHubRococo::para_id().into())); + let root = ::RuntimeOrigin::root(); + // asset kind to be spend from the treasury. + let asset_kind = VersionedLocatableAsset::V3 { + location: asset_hub_location, + asset_id: v3::AssetId::Concrete( + (v3::Junction::PalletInstance(50), v3::Junction::GeneralIndex(ASSET_ID.into())).into(), + ), + }; + // treasury spend beneficiary. + let alice: AccountId = Rococo::account_id_of(ALICE); + let bob: AccountId = Rococo::account_id_of(BOB); + let bob_signed = ::RuntimeOrigin::signed(bob.clone()); + + AssetHubRococo::execute_with(|| { + type Assets = ::Assets; + + // create an asset class and mint some assets to the treasury account. + assert_ok!(>::create( + ASSET_ID, + treasury_account.clone(), + true, + SPEND_AMOUNT / 2 + )); + assert_ok!(>::mint_into(ASSET_ID, &treasury_account, SPEND_AMOUNT * 4)); + // beneficiary has zero balance. + assert_eq!(>::balance(ASSET_ID, &alice,), 0u128,); + }); + + Rococo::execute_with(|| { + type RuntimeEvent = ::RuntimeEvent; + type Treasury = ::Treasury; + type AssetRate = ::AssetRate; + + // create a conversion rate from `asset_kind` to the native currency. + assert_ok!(AssetRate::create(root.clone(), Box::new(asset_kind.clone()), 2.into())); + + // create and approve a treasury spend. + assert_ok!(Treasury::spend( + root, + Box::new(asset_kind), + SPEND_AMOUNT, + Box::new(Location::new(0, Into::<[u8; 32]>::into(alice.clone())).into()), + None, + )); + // claim the spend. + assert_ok!(Treasury::payout(bob_signed.clone(), 0)); + + assert_expected_events!( + Rococo, + vec![ + RuntimeEvent::Treasury(pallet_treasury::Event::Paid { .. }) => {}, + ] + ); + }); + + AssetHubRococo::execute_with(|| { + type RuntimeEvent = ::RuntimeEvent; + type Assets = ::Assets; + + // assert events triggered by xcm pay program + // 1. treasury asset transferred to spend beneficiary + // 2. response to Relay Chain treasury pallet instance sent back + // 3. XCM program completed + assert_expected_events!( + AssetHubRococo, + vec![ + RuntimeEvent::Assets(pallet_assets::Event::Transferred { asset_id: id, from, to, amount }) => { + id: id == &ASSET_ID, + from: from == &treasury_account, + to: to == &alice, + amount: amount == &SPEND_AMOUNT, + }, + RuntimeEvent::ParachainSystem(cumulus_pallet_parachain_system::Event::UpwardMessageSent { .. }) => {}, + RuntimeEvent::MessageQueue(pallet_message_queue::Event::Processed { success: true ,.. }) => {}, + ] + ); + // beneficiary received the assets from the treasury. + assert_eq!(>::balance(ASSET_ID, &alice,), SPEND_AMOUNT,); + }); + + Rococo::execute_with(|| { + type RuntimeEvent = ::RuntimeEvent; + type Treasury = ::Treasury; + + // check the payment status to ensure the response from the AssetHub was received. + assert_ok!(Treasury::check_status(bob_signed, 0)); + assert_expected_events!( + Rococo, + vec![ + RuntimeEvent::Treasury(pallet_treasury::Event::SpendProcessed { .. }) => {}, + ] + ); + }); +} diff --git a/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-westend/Cargo.toml b/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-westend/Cargo.toml index 00f4308324a96734afac879cafd1e51300407a26..4fd7b5bfdf2de44a63d55a7db1e3994ed2328fdc 100644 --- a/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-westend/Cargo.toml +++ b/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-westend/Cargo.toml @@ -11,23 +11,29 @@ publish = false workspace = true [dependencies] -codec = { package = "parity-scale-codec", version = "3.4.0", default-features = false } +codec = { package = "parity-scale-codec", version = "3.6.12", default-features = false } assert_matches = "1.5.0" # Substrate sp-runtime = { path = "../../../../../../../substrate/primitives/runtime", default-features = false } +sp-keyring = { path = "../../../../../../../substrate/primitives/keyring", default-features = false } +sp-core = { path = "../../../../../../../substrate/primitives/core", default-features = false } frame-support = { path = "../../../../../../../substrate/frame/support", default-features = false } +frame-system = { path = "../../../../../../../substrate/frame/system", default-features = false } pallet-balances = { path = "../../../../../../../substrate/frame/balances", default-features = false } pallet-assets = { path = "../../../../../../../substrate/frame/assets", default-features = false } pallet-asset-conversion = { path = "../../../../../../../substrate/frame/asset-conversion", default-features = false } pallet-treasury = { path = "../../../../../../../substrate/frame/treasury", default-features = false } pallet-message-queue = { path = "../../../../../../../substrate/frame/message-queue", default-features = false } +pallet-transaction-payment = { path = "../../../../../../../substrate/frame/transaction-payment", default-features = false } +pallet-asset-tx-payment = { path = "../../../../../../../substrate/frame/transaction-payment/asset-tx-payment", default-features = false } # Polkadot polkadot-runtime-common = { path = "../../../../../../../polkadot/runtime/common" } xcm = { package = "staging-xcm", path = "../../../../../../../polkadot/xcm", default-features = false } xcm-executor = { package = "staging-xcm-executor", path = "../../../../../../../polkadot/xcm/xcm-executor", default-features = false } pallet-xcm = { path = "../../../../../../../polkadot/xcm/pallet-xcm", default-features = false } +xcm-fee-payment-runtime-api = { path = "../../../../../../../polkadot/xcm/xcm-fee-payment-runtime-api", default-features = false } westend-runtime = { path = "../../../../../../../polkadot/runtime/westend" } # Cumulus diff --git a/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-westend/src/lib.rs b/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-westend/src/lib.rs index e687251c14f9e2059787e817f6f480c738881e7b..1c4a0ef4c8d2af7f773fbb6916391012ec9fdfc2 100644 --- a/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-westend/src/lib.rs +++ b/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-westend/src/lib.rs @@ -74,7 +74,9 @@ mod imports { LocalReservableFromAssetHub as PenpalLocalReservableFromAssetHub, LocalTeleportableToAssetHub as PenpalLocalTeleportableToAssetHub, }; - pub use westend_runtime::xcm_config::XcmConfig as WestendXcmConfig; + pub use westend_runtime::xcm_config::{ + UniversalLocation as WestendUniversalLocation, XcmConfig as WestendXcmConfig, + }; pub const ASSET_ID: u32 = 3; pub const ASSET_MIN_BALANCE: u128 = 1000; @@ -87,6 +89,7 @@ mod imports { pub type ParaToSystemParaTest = Test; pub type ParaToParaThroughRelayTest = Test; pub type ParaToParaThroughAHTest = Test; + pub type RelayToParaThroughAHTest = Test; } #[cfg(test)] diff --git a/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-westend/src/tests/foreign_assets_transfers.rs b/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-westend/src/tests/hybrid_transfers.rs similarity index 76% rename from cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-westend/src/tests/foreign_assets_transfers.rs rename to cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-westend/src/tests/hybrid_transfers.rs index 8cfda37c84c9495acce070bad7a42ad8ef058277..d39c72c7c5f0d21815ca0091e9fd888b5ab54924 100644 --- a/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-westend/src/tests/foreign_assets_transfers.rs +++ b/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-westend/src/tests/hybrid_transfers.rs @@ -54,14 +54,18 @@ fn para_to_para_assethub_hop_assertions(t: ParaToParaThroughAHTest) { fn ah_to_para_transfer_assets(t: SystemParaToParaTest) -> DispatchResult { let fee_idx = t.args.fee_asset_item as usize; let fee: Asset = t.args.assets.inner().get(fee_idx).cloned().unwrap(); - ::PolkadotXcm::transfer_assets_using_type( + let custom_xcm_on_dest = Xcm::<()>(vec![DepositAsset { + assets: Wild(AllCounted(t.args.assets.len() as u32)), + beneficiary: t.args.beneficiary, + }]); + ::PolkadotXcm::transfer_assets_using_type_and_then( t.signed_origin, bx!(t.args.dest.into()), - bx!(t.args.beneficiary.into()), bx!(t.args.assets.into()), bx!(TransferType::LocalReserve), bx!(fee.id.into()), bx!(TransferType::LocalReserve), + bx!(VersionedXcm::from(custom_xcm_on_dest)), t.args.weight_limit, ) } @@ -69,14 +73,18 @@ fn ah_to_para_transfer_assets(t: SystemParaToParaTest) -> DispatchResult { fn para_to_ah_transfer_assets(t: ParaToSystemParaTest) -> DispatchResult { let fee_idx = t.args.fee_asset_item as usize; let fee: Asset = t.args.assets.inner().get(fee_idx).cloned().unwrap(); - ::PolkadotXcm::transfer_assets_using_type( + let custom_xcm_on_dest = Xcm::<()>(vec![DepositAsset { + assets: Wild(AllCounted(t.args.assets.len() as u32)), + beneficiary: t.args.beneficiary, + }]); + ::PolkadotXcm::transfer_assets_using_type_and_then( t.signed_origin, bx!(t.args.dest.into()), - bx!(t.args.beneficiary.into()), bx!(t.args.assets.into()), bx!(TransferType::DestinationReserve), bx!(fee.id.into()), bx!(TransferType::DestinationReserve), + bx!(VersionedXcm::from(custom_xcm_on_dest)), t.args.weight_limit, ) } @@ -85,14 +93,18 @@ fn para_to_para_transfer_assets_through_ah(t: ParaToParaThroughAHTest) -> Dispat let fee_idx = t.args.fee_asset_item as usize; let fee: Asset = t.args.assets.inner().get(fee_idx).cloned().unwrap(); let asset_hub_location: Location = PenpalA::sibling_location_of(AssetHubWestend::para_id()); - ::PolkadotXcm::transfer_assets_using_type( + let custom_xcm_on_dest = Xcm::<()>(vec![DepositAsset { + assets: Wild(AllCounted(t.args.assets.len() as u32)), + beneficiary: t.args.beneficiary, + }]); + ::PolkadotXcm::transfer_assets_using_type_and_then( t.signed_origin, bx!(t.args.dest.into()), - bx!(t.args.beneficiary.into()), bx!(t.args.assets.into()), bx!(TransferType::RemoteReserve(asset_hub_location.clone().into())), bx!(fee.id.into()), bx!(TransferType::RemoteReserve(asset_hub_location.into())), + bx!(VersionedXcm::from(custom_xcm_on_dest)), t.args.weight_limit, ) } @@ -100,14 +112,18 @@ fn para_to_para_transfer_assets_through_ah(t: ParaToParaThroughAHTest) -> Dispat fn para_to_asset_hub_teleport_foreign_assets(t: ParaToSystemParaTest) -> DispatchResult { let fee_idx = t.args.fee_asset_item as usize; let fee: Asset = t.args.assets.inner().get(fee_idx).cloned().unwrap(); - ::PolkadotXcm::transfer_assets_using_type( + let custom_xcm_on_dest = Xcm::<()>(vec![DepositAsset { + assets: Wild(AllCounted(t.args.assets.len() as u32)), + beneficiary: t.args.beneficiary, + }]); + ::PolkadotXcm::transfer_assets_using_type_and_then( t.signed_origin, bx!(t.args.dest.into()), - bx!(t.args.beneficiary.into()), bx!(t.args.assets.into()), bx!(TransferType::Teleport), bx!(fee.id.into()), bx!(TransferType::DestinationReserve), + bx!(VersionedXcm::from(custom_xcm_on_dest)), t.args.weight_limit, ) } @@ -115,14 +131,18 @@ fn para_to_asset_hub_teleport_foreign_assets(t: ParaToSystemParaTest) -> Dispatc fn asset_hub_to_para_teleport_foreign_assets(t: SystemParaToParaTest) -> DispatchResult { let fee_idx = t.args.fee_asset_item as usize; let fee: Asset = t.args.assets.inner().get(fee_idx).cloned().unwrap(); - ::PolkadotXcm::transfer_assets_using_type( + let custom_xcm_on_dest = Xcm::<()>(vec![DepositAsset { + assets: Wild(AllCounted(t.args.assets.len() as u32)), + beneficiary: t.args.beneficiary, + }]); + ::PolkadotXcm::transfer_assets_using_type_and_then( t.signed_origin, bx!(t.args.dest.into()), - bx!(t.args.beneficiary.into()), bx!(t.args.assets.into()), bx!(TransferType::Teleport), bx!(fee.id.into()), bx!(TransferType::LocalReserve), + bx!(VersionedXcm::from(custom_xcm_on_dest)), t.args.weight_limit, ) } @@ -627,3 +647,166 @@ fn bidirectional_teleport_foreign_asset_between_para_and_asset_hub_using_explici asset_hub_to_para_teleport_foreign_assets, ); } + +// =============================================================== +// ===== Transfer - Native Asset - Relay->AssetHub->Parachain ==== +// =============================================================== +/// Transfers of native asset Relay to Parachain (using AssetHub reserve). Parachains want to avoid +/// managing SAs on all system chains, thus want all their DOT-in-reserve to be held in their +/// Sovereign Account on Asset Hub. +#[test] +fn transfer_native_asset_from_relay_to_para_through_asset_hub() { + // Init values for Relay + let destination = Westend::child_location_of(PenpalA::para_id()); + let sender = WestendSender::get(); + let amount_to_send: Balance = WESTEND_ED * 1000; + + // Init values for Parachain + let relay_native_asset_location = RelayLocation::get(); + let receiver = PenpalAReceiver::get(); + + // Init Test + let test_args = TestContext { + sender, + receiver: receiver.clone(), + args: TestArgs::new_relay(destination.clone(), receiver.clone(), amount_to_send), + }; + let mut test = RelayToParaThroughAHTest::new(test_args); + + let sov_penpal_on_ah = AssetHubWestend::sovereign_account_id_of( + AssetHubWestend::sibling_location_of(PenpalA::para_id()), + ); + // Query initial balances + let sender_balance_before = test.sender.balance; + let sov_penpal_on_ah_before = AssetHubWestend::execute_with(|| { + ::Balances::free_balance(sov_penpal_on_ah.clone()) + }); + let receiver_assets_before = PenpalA::execute_with(|| { + type ForeignAssets = ::ForeignAssets; + >::balance(relay_native_asset_location.clone(), &receiver) + }); + + fn relay_assertions(t: RelayToParaThroughAHTest) { + type RuntimeEvent = ::RuntimeEvent; + Westend::assert_xcm_pallet_attempted_complete(None); + assert_expected_events!( + Westend, + vec![ + // Amount to teleport is withdrawn from Sender + 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::Minted { who, amount }) => { + who: *who == ::XcmPallet::check_account(), + amount: *amount == t.args.amount, + }, + ] + ); + } + fn asset_hub_assertions(_: RelayToParaThroughAHTest) { + type RuntimeEvent = ::RuntimeEvent; + let sov_penpal_on_ah = AssetHubWestend::sovereign_account_id_of( + AssetHubWestend::sibling_location_of(PenpalA::para_id()), + ); + assert_expected_events!( + AssetHubWestend, + vec![ + // Deposited to receiver parachain SA + RuntimeEvent::Balances( + pallet_balances::Event::Minted { who, .. } + ) => { + who: *who == sov_penpal_on_ah, + }, + RuntimeEvent::MessageQueue( + pallet_message_queue::Event::Processed { success: true, .. } + ) => {}, + ] + ); + } + fn penpal_assertions(t: RelayToParaThroughAHTest) { + type RuntimeEvent = ::RuntimeEvent; + let expected_id = + t.args.assets.into_inner().first().unwrap().id.0.clone().try_into().unwrap(); + assert_expected_events!( + PenpalA, + vec![ + RuntimeEvent::ForeignAssets(pallet_assets::Event::Issued { asset_id, owner, .. }) => { + asset_id: *asset_id == expected_id, + owner: *owner == t.receiver.account_id, + }, + ] + ); + } + fn transfer_assets_dispatchable(t: RelayToParaThroughAHTest) -> DispatchResult { + let fee_idx = t.args.fee_asset_item as usize; + let fee: Asset = t.args.assets.inner().get(fee_idx).cloned().unwrap(); + let asset_hub_location = Westend::child_location_of(AssetHubWestend::para_id()); + let context = WestendUniversalLocation::get(); + + // reanchor fees to the view of destination (Penpal) + let mut remote_fees = fee.clone().reanchored(&t.args.dest, &context).unwrap(); + if let Fungible(ref mut amount) = remote_fees.fun { + // we already spent some fees along the way, just use half of what we started with + *amount = *amount / 2; + } + let xcm_on_final_dest = Xcm::<()>(vec![ + BuyExecution { fees: remote_fees, weight_limit: t.args.weight_limit.clone() }, + DepositAsset { + assets: Wild(AllCounted(t.args.assets.len() as u32)), + beneficiary: t.args.beneficiary, + }, + ]); + + // reanchor final dest (Penpal) to the view of hop (Asset Hub) + let mut dest = t.args.dest.clone(); + dest.reanchor(&asset_hub_location, &context).unwrap(); + // on Asset Hub, forward assets to Penpal + let xcm_on_hop = Xcm::<()>(vec![DepositReserveAsset { + assets: Wild(AllCounted(t.args.assets.len() as u32)), + dest, + xcm: xcm_on_final_dest, + }]); + + // First leg is a teleport, from there a local-reserve-transfer to final dest + ::XcmPallet::transfer_assets_using_type_and_then( + t.signed_origin, + bx!(asset_hub_location.into()), + bx!(t.args.assets.into()), + bx!(TransferType::Teleport), + bx!(fee.id.into()), + bx!(TransferType::Teleport), + bx!(VersionedXcm::from(xcm_on_hop)), + t.args.weight_limit, + ) + } + + // Set assertions and dispatchables + test.set_assertion::(relay_assertions); + test.set_assertion::(asset_hub_assertions); + test.set_assertion::(penpal_assertions); + test.set_dispatchable::(transfer_assets_dispatchable); + test.assert(); + + // Query final balances + let sender_balance_after = test.sender.balance; + let sov_penpal_on_ah_after = AssetHubWestend::execute_with(|| { + ::Balances::free_balance(sov_penpal_on_ah) + }); + let receiver_assets_after = PenpalA::execute_with(|| { + type ForeignAssets = ::ForeignAssets; + >::balance(relay_native_asset_location, &receiver) + }); + + // Sender's balance is reduced by amount sent plus delivery fees + assert!(sender_balance_after < sender_balance_before - amount_to_send); + // SA on AH balance is increased + assert!(sov_penpal_on_ah_after > sov_penpal_on_ah_before); + // Receiver's asset balance is increased + assert!(receiver_assets_after > receiver_assets_before); + // Receiver's asset balance increased by `amount_to_send - delivery_fees - bought_execution`; + // `delivery_fees` might be paid from transfer or JIT, also `bought_execution` is unknown but + // should be non-zero + assert!(receiver_assets_after < receiver_assets_before + amount_to_send); +} diff --git a/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-westend/src/tests/mod.rs b/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-westend/src/tests/mod.rs index e463e21e9e5295a7c33efc30006299ee2a801902..61eb70524fc9ae2a23e5061400c57ca719bae4e1 100644 --- a/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-westend/src/tests/mod.rs +++ b/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-westend/src/tests/mod.rs @@ -14,10 +14,11 @@ // limitations under the License. mod fellowship_treasury; -mod foreign_assets_transfers; +mod hybrid_transfers; mod reserve_transfer; mod send; mod set_xcm_versions; mod swap; mod teleport; mod treasury; +mod xcm_fee_estimation; 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 df01eb0d48ad929194e81808e36cf77528b54a21..65d013a0eec40aa90b42a475f40dca9197f318e9 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 @@ -574,7 +574,7 @@ fn reserve_transfer_native_asset_from_relay_to_para() { let sender = WestendSender::get(); let amount_to_send: Balance = WESTEND_ED * 1000; - // Init values fot Parachain + // Init values for Parachain let relay_native_asset_location = RelayLocation::get(); let receiver = PenpalAReceiver::get(); diff --git a/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-westend/src/tests/send.rs b/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-westend/src/tests/send.rs index f218b539c387988f70314eff41c2e1ce4e97092b..eb0e985cc0ce6f84318f763cb37e707beaeca718 100644 --- a/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-westend/src/tests/send.rs +++ b/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-westend/src/tests/send.rs @@ -75,10 +75,10 @@ fn send_xcm_from_para_to_system_para_paying_fee_with_system_assets_works() { )]); PenpalA::execute_with(|| { - assert_ok!(::PolkadotXcm::send_blob( + assert_ok!(::PolkadotXcm::send( root_origin, bx!(system_para_destination), - xcm.encode().try_into().unwrap(), + bx!(xcm), )); PenpalA::assert_xcm_pallet_sent(); @@ -159,10 +159,10 @@ fn send_xcm_from_para_to_system_para_paying_fee_with_assets_works() { )]); PenpalA::execute_with(|| { - assert_ok!(::PolkadotXcm::send_blob( + assert_ok!(::PolkadotXcm::send( root_origin, bx!(system_para_destination), - xcm.encode().try_into().unwrap(), + bx!(xcm), )); PenpalA::assert_xcm_pallet_sent(); diff --git a/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-westend/src/tests/swap.rs b/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-westend/src/tests/swap.rs index 31f763be637079292d3b1aa49bbbfe5668d86653..f6b6580988658f5fadead0250a6bcc886c9f125d 100644 --- a/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-westend/src/tests/swap.rs +++ b/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-westend/src/tests/swap.rs @@ -371,10 +371,10 @@ fn pay_xcm_fee_with_some_asset_swapped_for_native() { penpal.clone(), ); - assert_ok!(::PolkadotXcm::send_blob( + assert_ok!(::PolkadotXcm::send( penpal_root, bx!(asset_hub_location), - xcm.encode().try_into().unwrap(), + bx!(xcm), )); PenpalA::assert_xcm_pallet_sent(); diff --git a/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-westend/src/tests/xcm_fee_estimation.rs b/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-westend/src/tests/xcm_fee_estimation.rs new file mode 100644 index 0000000000000000000000000000000000000000..aeec9b44dab4ce7648e609e13136c381a5a50695 --- /dev/null +++ b/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-westend/src/tests/xcm_fee_estimation.rs @@ -0,0 +1,370 @@ +// Copyright (C) Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +//! Tests to ensure correct XCM fee estimation for cross-chain asset transfers. + +use crate::imports::*; + +use sp_keyring::AccountKeyring::Alice; +use sp_runtime::{generic, MultiSignature}; +use xcm_fee_payment_runtime_api::{ + dry_run::runtime_decl_for_xcm_dry_run_api::XcmDryRunApiV1, + fees::runtime_decl_for_xcm_payment_api::XcmPaymentApiV1, +}; + +/// We are able to dry-run and estimate the fees for a teleport between relay and system para. +/// Scenario: Alice on Westend relay chain wants to teleport WND to Asset Hub. +/// We want to know the fees using the `XcmDryRunApi` and `XcmPaymentApi`. +#[test] +fn teleport_relay_system_para_works() { + let destination: Location = Parachain(1000).into(); // Asset Hub. + let beneficiary_id = AssetHubWestendReceiver::get(); + let beneficiary: Location = AccountId32 { id: beneficiary_id.clone().into(), network: None } // Test doesn't allow specifying a network here. + .into(); // Beneficiary in Asset Hub. + let teleport_amount = 1_000_000_000_000; // One WND (12 decimals). + let assets: Assets = vec![(Here, teleport_amount).into()].into(); + + // We get them from the Westend closure. + let mut delivery_fees_amount = 0; + let mut remote_message = VersionedXcm::V4(Xcm(Vec::new())); + ::new_ext().execute_with(|| { + type Runtime = ::Runtime; + type RuntimeCall = ::RuntimeCall; + + let call = RuntimeCall::XcmPallet(pallet_xcm::Call::transfer_assets { + dest: Box::new(VersionedLocation::V4(destination.clone())), + beneficiary: Box::new(VersionedLocation::V4(beneficiary)), + assets: Box::new(VersionedAssets::V4(assets)), + fee_asset_item: 0, + weight_limit: Unlimited, + }); + let sender = Alice; // Is the same as `WestendSender`. + let extrinsic = construct_extrinsic_westend(sender, call); + let result = Runtime::dry_run_extrinsic(extrinsic).unwrap(); + assert_eq!(result.forwarded_xcms.len(), 1); + let (destination_to_query, messages_to_query) = &result.forwarded_xcms[0]; + assert_eq!(messages_to_query.len(), 1); + remote_message = messages_to_query[0].clone(); + let delivery_fees = + Runtime::query_delivery_fees(destination_to_query.clone(), remote_message.clone()) + .unwrap(); + delivery_fees_amount = get_amount_from_versioned_assets(delivery_fees); + }); + + // This is set in the AssetHubWestend closure. + let mut remote_execution_fees = 0; + ::execute_with(|| { + type Runtime = ::Runtime; + + let weight = Runtime::query_xcm_weight(remote_message.clone()).unwrap(); + remote_execution_fees = + Runtime::query_weight_to_asset_fee(weight, VersionedAssetId::V4(Parent.into())) + .unwrap(); + }); + + let test_args = TestContext { + sender: WestendSender::get(), // Alice. + receiver: AssetHubWestendReceiver::get(), // Bob in Asset Hub. + args: TestArgs::new_relay(destination, beneficiary_id, teleport_amount), + }; + let mut test = RelayToSystemParaTest::new(test_args); + + let sender_balance_before = test.sender.balance; + let receiver_balance_before = test.receiver.balance; + assert_eq!(sender_balance_before, 1_000_000_000_000_000_000); + assert_eq!(receiver_balance_before, 4_096_000_000_000); + + test.set_dispatchable::(transfer_assets); + test.assert(); + + let sender_balance_after = test.sender.balance; + let receiver_balance_after = test.receiver.balance; + + // We now know the exact fees. + assert_eq!( + sender_balance_after, + sender_balance_before - delivery_fees_amount - teleport_amount + ); + assert_eq!( + receiver_balance_after, + receiver_balance_before + teleport_amount - remote_execution_fees + ); +} + +/// We are able to dry-run and estimate the fees for a multi-hop XCM journey. +/// Scenario: Alice on PenpalA has some WND and wants to send them to PenpalB. +/// We want to know the fees using the `XcmDryRunApi` and `XcmPaymentApi`. +#[test] +fn multi_hop_works() { + let destination = PenpalA::sibling_location_of(PenpalB::para_id()); + let sender = PenpalASender::get(); + let amount_to_send = 1_000_000_000_000; // One WND (12 decimals). + let asset_owner = PenpalAssetOwner::get(); + let assets: Assets = (Parent, amount_to_send).into(); + let relay_native_asset_location = RelayLocation::get(); + let sender_as_seen_by_relay = Westend::child_location_of(PenpalA::para_id()); + let sov_of_sender_on_relay = Westend::sovereign_account_id_of(sender_as_seen_by_relay.clone()); + + // fund Parachain's sender account + PenpalA::mint_foreign_asset( + ::RuntimeOrigin::signed(asset_owner.clone()), + relay_native_asset_location.clone(), + sender.clone(), + amount_to_send * 2, + ); + + // fund the Parachain Origin's SA on Relay Chain with the native tokens held in reserve + Westend::fund_accounts(vec![(sov_of_sender_on_relay.clone().into(), amount_to_send * 2)]); + + // Init values for Parachain Destination + let beneficiary_id = PenpalBReceiver::get(); + let beneficiary: Location = AccountId32 { + id: beneficiary_id.clone().into(), + network: None, // Test doesn't allow specifying a network here. + } + .into(); + + // We get them from the PenpalA closure. + let mut delivery_fees_amount = 0; + let mut remote_message = VersionedXcm::V4(Xcm(Vec::new())); + ::execute_with(|| { + type Runtime = ::Runtime; + type RuntimeCall = ::RuntimeCall; + + let call = RuntimeCall::PolkadotXcm(pallet_xcm::Call::transfer_assets { + dest: Box::new(VersionedLocation::V4(destination.clone())), + beneficiary: Box::new(VersionedLocation::V4(beneficiary)), + assets: Box::new(VersionedAssets::V4(assets.clone())), + fee_asset_item: 0, + weight_limit: Unlimited, + }); + let sender = Alice; // Same as `PenpalASender`. + let extrinsic = construct_extrinsic_penpal(sender, call); + let result = Runtime::dry_run_extrinsic(extrinsic).unwrap(); + assert_eq!(result.forwarded_xcms.len(), 1); + let (destination_to_query, messages_to_query) = &result.forwarded_xcms[0]; + assert_eq!(messages_to_query.len(), 1); + remote_message = messages_to_query[0].clone(); + let delivery_fees = + Runtime::query_delivery_fees(destination_to_query.clone(), remote_message.clone()) + .unwrap(); + delivery_fees_amount = get_amount_from_versioned_assets(delivery_fees); + }); + + // This is set in the Westend closure. + let mut intermediate_execution_fees = 0; + let mut intermediate_delivery_fees_amount = 0; + let mut intermediate_remote_message = VersionedXcm::V4(Xcm::<()>(Vec::new())); + ::execute_with(|| { + type Runtime = ::Runtime; + type RuntimeCall = ::RuntimeCall; + + // First we get the execution fees. + let weight = Runtime::query_xcm_weight(remote_message.clone()).unwrap(); + intermediate_execution_fees = + Runtime::query_weight_to_asset_fee(weight, VersionedAssetId::V4(Here.into())).unwrap(); + + // We have to do this to turn `VersionedXcm<()>` into `VersionedXcm`. + let xcm_program = + VersionedXcm::V4(Xcm::::from(remote_message.clone().try_into().unwrap())); + + // Now we get the delivery fees to the final destination. + let result = + Runtime::dry_run_xcm(sender_as_seen_by_relay.clone().into(), xcm_program).unwrap(); + let (destination_to_query, messages_to_query) = &result.forwarded_xcms[0]; + // There's actually two messages here. + // One created when the message we sent from PenpalA arrived and was executed. + // The second one when we dry-run the xcm. + // We could've gotten the message from the queue without having to dry-run, but + // offchain applications would have to dry-run, so we do it here as well. + intermediate_remote_message = messages_to_query[0].clone(); + let delivery_fees = Runtime::query_delivery_fees( + destination_to_query.clone(), + intermediate_remote_message.clone(), + ) + .unwrap(); + intermediate_delivery_fees_amount = get_amount_from_versioned_assets(delivery_fees); + }); + + // Get the final execution fees in the destination. + let mut final_execution_fees = 0; + ::execute_with(|| { + type Runtime = ::Runtime; + + let weight = Runtime::query_xcm_weight(intermediate_remote_message.clone()).unwrap(); + final_execution_fees = + Runtime::query_weight_to_asset_fee(weight, VersionedAssetId::V4(Parent.into())) + .unwrap(); + }); + + // Dry-running is done. + PenpalA::reset_ext(); + Westend::reset_ext(); + PenpalB::reset_ext(); + + // Fund accounts again. + PenpalA::mint_foreign_asset( + ::RuntimeOrigin::signed(asset_owner), + relay_native_asset_location.clone(), + sender.clone(), + amount_to_send * 2, + ); + Westend::fund_accounts(vec![(sov_of_sender_on_relay.into(), amount_to_send * 2)]); + + // Actually run the extrinsic. + let test_args = TestContext { + sender: PenpalASender::get(), // Alice. + receiver: PenpalBReceiver::get(), // Bob in PenpalB. + args: TestArgs::new_para( + destination, + beneficiary_id.clone(), + amount_to_send, + assets, + None, + 0, + ), + }; + let mut test = ParaToParaThroughRelayTest::new(test_args); + + let sender_assets_before = PenpalA::execute_with(|| { + type ForeignAssets = ::ForeignAssets; + >::balance(relay_native_asset_location.clone(), &sender) + }); + let receiver_assets_before = PenpalB::execute_with(|| { + type ForeignAssets = ::ForeignAssets; + >::balance(relay_native_asset_location.clone(), &beneficiary_id) + }); + + test.set_dispatchable::(transfer_assets_para_to_para); + test.assert(); + + let sender_assets_after = PenpalA::execute_with(|| { + type ForeignAssets = ::ForeignAssets; + >::balance(relay_native_asset_location.clone(), &sender) + }); + let receiver_assets_after = PenpalB::execute_with(|| { + type ForeignAssets = ::ForeignAssets; + >::balance(relay_native_asset_location, &beneficiary_id) + }); + + // We know the exact fees on every hop. + assert_eq!( + sender_assets_after, + sender_assets_before - amount_to_send - delivery_fees_amount /* This is charged directly + * from the sender's + * account. */ + ); + assert_eq!( + receiver_assets_after, + receiver_assets_before + amount_to_send - + intermediate_execution_fees - + intermediate_delivery_fees_amount - + final_execution_fees + ); +} + +fn get_amount_from_versioned_assets(assets: VersionedAssets) -> u128 { + let latest_assets: Assets = assets.try_into().unwrap(); + let Fungible(amount) = latest_assets.inner()[0].fun else { + unreachable!("asset is fungible"); + }; + amount +} + +fn transfer_assets(test: RelayToSystemParaTest) -> DispatchResult { + ::XcmPallet::transfer_assets( + test.signed_origin, + bx!(test.args.dest.into()), + bx!(test.args.beneficiary.into()), + bx!(test.args.assets.into()), + test.args.fee_asset_item, + test.args.weight_limit, + ) +} + +fn transfer_assets_para_to_para(test: ParaToParaThroughRelayTest) -> DispatchResult { + ::PolkadotXcm::transfer_assets( + test.signed_origin, + bx!(test.args.dest.into()), + bx!(test.args.beneficiary.into()), + bx!(test.args.assets.into()), + test.args.fee_asset_item, + test.args.weight_limit, + ) +} + +// Constructs the SignedExtra component of an extrinsic for the Westend runtime. +fn construct_extrinsic_westend( + sender: sp_keyring::AccountKeyring, + call: westend_runtime::RuntimeCall, +) -> westend_runtime::UncheckedExtrinsic { + type Runtime = ::Runtime; + let account_id = ::AccountId::from(sender.public()); + let tip = 0; + let extra: westend_runtime::SignedExtra = ( + frame_system::CheckNonZeroSender::::new(), + frame_system::CheckSpecVersion::::new(), + frame_system::CheckTxVersion::::new(), + frame_system::CheckGenesis::::new(), + frame_system::CheckMortality::::from(sp_runtime::generic::Era::immortal()), + frame_system::CheckNonce::::from( + frame_system::Pallet::::account(&account_id).nonce, + ), + frame_system::CheckWeight::::new(), + pallet_transaction_payment::ChargeTransactionPayment::::from(tip), + ); + let raw_payload = westend_runtime::SignedPayload::new(call, extra).unwrap(); + let signature = raw_payload.using_encoded(|payload| sender.sign(payload)); + let (call, extra, _) = raw_payload.deconstruct(); + westend_runtime::UncheckedExtrinsic::new_signed( + call, + account_id.into(), + MultiSignature::Sr25519(signature), + extra, + ) +} + +// Constructs the SignedExtra component of an extrinsic for the Westend runtime. +fn construct_extrinsic_penpal( + sender: sp_keyring::AccountKeyring, + call: penpal_runtime::RuntimeCall, +) -> penpal_runtime::UncheckedExtrinsic { + type Runtime = ::Runtime; + let account_id = ::AccountId::from(sender.public()); + let tip = 0; + let extra: penpal_runtime::SignedExtra = ( + frame_system::CheckNonZeroSender::::new(), + frame_system::CheckSpecVersion::::new(), + frame_system::CheckTxVersion::::new(), + frame_system::CheckGenesis::::new(), + frame_system::CheckEra::::from(generic::Era::immortal()), + frame_system::CheckNonce::::from( + frame_system::Pallet::::account(&account_id).nonce, + ), + frame_system::CheckWeight::::new(), + pallet_asset_tx_payment::ChargeAssetTxPayment::::from(tip, None), + ); + type SignedPayload = + generic::SignedPayload; + let raw_payload = SignedPayload::new(call, extra).unwrap(); + let signature = raw_payload.using_encoded(|payload| sender.sign(payload)); + let (call, extra, _) = raw_payload.deconstruct(); + penpal_runtime::UncheckedExtrinsic::new_signed( + call, + account_id.into(), + MultiSignature::Sr25519(signature), + extra, + ) +} diff --git a/cumulus/parachains/integration-tests/emulated/tests/bridges/bridge-hub-rococo/Cargo.toml b/cumulus/parachains/integration-tests/emulated/tests/bridges/bridge-hub-rococo/Cargo.toml index bbe54c367baf41d183dd60f976a7951d20d8a6f2..bed5af92f6e55b37f7f12518dbe1ed1b290dd5aa 100644 --- a/cumulus/parachains/integration-tests/emulated/tests/bridges/bridge-hub-rococo/Cargo.toml +++ b/cumulus/parachains/integration-tests/emulated/tests/bridges/bridge-hub-rococo/Cargo.toml @@ -11,7 +11,7 @@ publish = false workspace = true [dependencies] -codec = { package = "parity-scale-codec", version = "3.4.0", default-features = false } +codec = { package = "parity-scale-codec", version = "3.6.12", default-features = false } scale-info = { version = "2.11.1", default-features = false, features = ["derive"] } hex-literal = "0.4.1" 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 69d625be280454c4368d223fb5092be8df9de39d..87fb70e4de23857bf929ed1a663fd2dcc3120e93 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 @@ -60,15 +60,19 @@ fn send_asset_from_penpal_rococo_through_local_asset_hub_to_westend_asset_hub( AccountId32Junction { network: None, id: AssetHubWestendReceiver::get().into() }.into(); let assets: Assets = (id.clone(), transfer_amount).into(); let fees_id: AssetId = id.into(); + let custom_xcm_on_dest = Xcm::<()>(vec![DepositAsset { + assets: Wild(AllCounted(assets.len() as u32)), + beneficiary, + }]); - ::PolkadotXcm::transfer_assets_using_type( + ::PolkadotXcm::transfer_assets_using_type_and_then( signed_origin, bx!(destination.into()), - bx!(beneficiary.into()), bx!(assets.clone().into()), bx!(TransferType::RemoteReserve(local_asset_hub.clone().into())), bx!(fees_id.into()), bx!(TransferType::RemoteReserve(local_asset_hub.into())), + bx!(VersionedXcm::from(custom_xcm_on_dest)), WeightLimit::Unlimited, ) })); diff --git a/cumulus/parachains/integration-tests/emulated/tests/bridges/bridge-hub-rococo/src/tests/send_xcm.rs b/cumulus/parachains/integration-tests/emulated/tests/bridges/bridge-hub-rococo/src/tests/send_xcm.rs index 4bd041dc03f4216c9eddf811d325e8262873e473..a1d871cdb618fdddfbbbc3e7812d0ec7f7ae7866 100644 --- a/cumulus/parachains/integration-tests/emulated/tests/bridges/bridge-hub-rococo/src/tests/send_xcm.rs +++ b/cumulus/parachains/integration-tests/emulated/tests/bridges/bridge-hub-rococo/src/tests/send_xcm.rs @@ -14,7 +14,6 @@ // limitations under the License. use crate::tests::*; -use codec::Encode; #[test] fn send_xcm_from_rococo_relay_to_westend_asset_hub_should_fail_on_not_applicable() { @@ -27,7 +26,7 @@ fn send_xcm_from_rococo_relay_to_westend_asset_hub_should_fail_on_not_applicable let remote_xcm = Xcm(vec![ClearOrigin]); - let xcm = VersionedXcm::from(Xcm::<()>(vec![ + let xcm = VersionedXcm::from(Xcm(vec![ UnpaidExecution { weight_limit, check_origin }, ExportMessage { network: WestendId.into(), @@ -39,10 +38,10 @@ fn send_xcm_from_rococo_relay_to_westend_asset_hub_should_fail_on_not_applicable // Rococo Global Consensus // Send XCM message from Relay Chain to Bridge Hub source Parachain Rococo::execute_with(|| { - assert_ok!(::XcmPallet::send_blob( + assert_ok!(::XcmPallet::send( sudo_origin, bx!(destination), - xcm.encode().try_into().unwrap(), + bx!(xcm), )); type RuntimeEvent = ::RuntimeEvent; 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 e332eb5bfda7c0a05f618c66e6b65cbf10e6bffc..1c1c51404aa48a78d110dbcc2e28fefa01ee94bb 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 @@ -27,7 +27,7 @@ use snowbridge_pallet_inbound_queue_fixtures::{ }; use snowbridge_pallet_system; use snowbridge_router_primitives::inbound::{ - Command, GlobalConsensusEthereumConvertsFor, MessageV1, VersionedMessage, + Command, Destination, GlobalConsensusEthereumConvertsFor, MessageV1, VersionedMessage, }; use sp_core::H256; use sp_runtime::{DispatchError::Token, TokenError::FundsUnavailable}; @@ -40,6 +40,7 @@ const TREASURY_ACCOUNT: [u8; 32] = const WETH: [u8; 20] = hex!("87d1f7fdfEe7f651FaBc8bFCB6E086C278b77A7d"); const ETHEREUM_DESTINATION_ADDRESS: [u8; 20] = hex!("44a57ee2f2FCcb85FDa2B0B18EBD0D8D2333700e"); const INSUFFICIENT_XCM_FEE: u128 = 1000; +const XCM_FEE: u128 = 4_000_000_000; #[derive(Encode, Decode, Debug, PartialEq, Eq, Clone, TypeInfo)] pub enum ControlCall { @@ -82,7 +83,7 @@ fn create_agent() { let create_agent_call = SnowbridgeControl::Control(ControlCall::CreateAgent {}); // Construct XCM to create an agent for para 1001 - let remote_xcm = VersionedXcm::from(Xcm::<()>(vec![ + let remote_xcm = VersionedXcm::from(Xcm(vec![ UnpaidExecution { weight_limit: Unlimited, check_origin: None }, DescendOrigin(Parachain(origin_para).into()), Transact { @@ -95,10 +96,10 @@ fn create_agent() { // Rococo Global Consensus // Send XCM message from Relay Chain to Bridge Hub source Parachain Rococo::execute_with(|| { - assert_ok!(::XcmPallet::send_blob( + assert_ok!(::XcmPallet::send( sudo_origin, bx!(destination), - remote_xcm.encode().try_into().unwrap(), + bx!(remote_xcm), )); type RuntimeEvent = ::RuntimeEvent; @@ -140,7 +141,7 @@ fn create_channel() { let create_agent_call = SnowbridgeControl::Control(ControlCall::CreateAgent {}); // Construct XCM to create an agent for para 1001 - let create_agent_xcm = VersionedXcm::from(Xcm::<()>(vec![ + let create_agent_xcm = VersionedXcm::from(Xcm(vec![ UnpaidExecution { weight_limit: Unlimited, check_origin: None }, DescendOrigin(Parachain(origin_para).into()), Transact { @@ -153,7 +154,7 @@ fn create_channel() { let create_channel_call = SnowbridgeControl::Control(ControlCall::CreateChannel { mode: OperatingMode::Normal }); // Construct XCM to create a channel for para 1001 - let create_channel_xcm = VersionedXcm::from(Xcm::<()>(vec![ + let create_channel_xcm = VersionedXcm::from(Xcm(vec![ UnpaidExecution { weight_limit: Unlimited, check_origin: None }, DescendOrigin(Parachain(origin_para).into()), Transact { @@ -166,16 +167,16 @@ fn create_channel() { // Rococo Global Consensus // Send XCM message from Relay Chain to Bridge Hub source Parachain Rococo::execute_with(|| { - assert_ok!(::XcmPallet::send_blob( + assert_ok!(::XcmPallet::send( sudo_origin.clone(), bx!(destination.clone()), - create_agent_xcm.encode().try_into().unwrap(), + bx!(create_agent_xcm), )); - assert_ok!(::XcmPallet::send_blob( + assert_ok!(::XcmPallet::send( sudo_origin, bx!(destination), - create_channel_xcm.encode().try_into().unwrap(), + bx!(create_channel_xcm), )); type RuntimeEvent = ::RuntimeEvent; @@ -555,3 +556,133 @@ fn register_weth_token_in_asset_hub_fail_for_insufficient_fee() { ); }); } + +fn send_token_from_ethereum_to_asset_hub_with_fee(account_id: [u8; 32], fee: u128) { + let weth_asset_location: Location = Location::new( + 2, + [EthereumNetwork::get().into(), AccountKey20 { network: None, key: WETH }], + ); + // (Parent, Parent, EthereumNetwork::get(), AccountKey20 { network: None, key: WETH }) + // Fund asset hub sovereign on bridge hub + let asset_hub_sovereign = BridgeHubRococo::sovereign_account_id_of(Location::new( + 1, + [Parachain(AssetHubRococo::para_id().into())], + )); + BridgeHubRococo::fund_accounts(vec![(asset_hub_sovereign.clone(), INITIAL_FUND)]); + + // Register WETH + AssetHubRococo::execute_with(|| { + type RuntimeOrigin = ::RuntimeOrigin; + + assert_ok!(::ForeignAssets::force_create( + RuntimeOrigin::root(), + weth_asset_location.clone().try_into().unwrap(), + asset_hub_sovereign.into(), + false, + 1, + )); + + assert!(::ForeignAssets::asset_exists( + weth_asset_location.clone().try_into().unwrap(), + )); + }); + + // Send WETH to an existent account on asset hub + BridgeHubRococo::execute_with(|| { + type RuntimeEvent = ::RuntimeEvent; + + type EthereumInboundQueue = + ::EthereumInboundQueue; + let message_id: H256 = [0; 32].into(); + let message = VersionedMessage::V1(MessageV1 { + chain_id: CHAIN_ID, + command: Command::SendToken { + token: WETH.into(), + destination: Destination::AccountId32 { id: account_id }, + amount: 1_000_000, + fee, + }, + }); + let (xcm, _) = EthereumInboundQueue::do_convert(message_id, message).unwrap(); + assert_ok!(EthereumInboundQueue::send_xcm(xcm, AssetHubRococo::para_id().into())); + + // Check that the message was sent + assert_expected_events!( + BridgeHubRococo, + vec![ + RuntimeEvent::XcmpQueue(cumulus_pallet_xcmp_queue::Event::XcmpMessageSent { .. }) => {}, + ] + ); + }); +} + +#[test] +fn send_token_from_ethereum_to_existent_account_on_asset_hub() { + send_token_from_ethereum_to_asset_hub_with_fee(AssetHubRococoSender::get().into(), XCM_FEE); + + AssetHubRococo::execute_with(|| { + type RuntimeEvent = ::RuntimeEvent; + + // Check that the token was received and issued as a foreign asset on AssetHub + assert_expected_events!( + AssetHubRococo, + vec![ + RuntimeEvent::ForeignAssets(pallet_assets::Event::Issued { .. }) => {}, + ] + ); + }); +} + +#[test] +fn send_token_from_ethereum_to_non_existent_account_on_asset_hub() { + send_token_from_ethereum_to_asset_hub_with_fee([1; 32], XCM_FEE); + + AssetHubRococo::execute_with(|| { + type RuntimeEvent = ::RuntimeEvent; + + // Check that the token was received and issued as a foreign asset on AssetHub + assert_expected_events!( + AssetHubRococo, + vec![ + RuntimeEvent::ForeignAssets(pallet_assets::Event::Issued { .. }) => {}, + ] + ); + }); +} + +#[test] +fn send_token_from_ethereum_to_non_existent_account_on_asset_hub_with_insufficient_fee() { + send_token_from_ethereum_to_asset_hub_with_fee([1; 32], INSUFFICIENT_XCM_FEE); + + AssetHubRococo::execute_with(|| { + type RuntimeEvent = ::RuntimeEvent; + + // Check that the message was not processed successfully due to insufficient fee + + assert_expected_events!( + AssetHubRococo, + vec![ + RuntimeEvent::MessageQueue(pallet_message_queue::Event::Processed { success:false, .. }) => {}, + ] + ); + }); +} + +#[test] +fn send_token_from_ethereum_to_non_existent_account_on_asset_hub_with_sufficient_fee_but_do_not_satisfy_ed( +) { + // On AH the xcm fee is 33_873_024 and the ED is 3_300_000 + send_token_from_ethereum_to_asset_hub_with_fee([1; 32], 36_000_000); + + AssetHubRococo::execute_with(|| { + type RuntimeEvent = ::RuntimeEvent; + + // Check that the message was not processed successfully due to insufficient ED + assert_expected_events!( + AssetHubRococo, + vec![ + RuntimeEvent::MessageQueue(pallet_message_queue::Event::Processed { success:false, .. }) => {}, + ] + ); + }); +} diff --git a/cumulus/parachains/integration-tests/emulated/tests/bridges/bridge-hub-westend/Cargo.toml b/cumulus/parachains/integration-tests/emulated/tests/bridges/bridge-hub-westend/Cargo.toml index 3aa2e2bcbe063c21603e0763eb8e490911177478..6aebf8862d62e794a24e6926ff487d1956ed792b 100644 --- a/cumulus/parachains/integration-tests/emulated/tests/bridges/bridge-hub-westend/Cargo.toml +++ b/cumulus/parachains/integration-tests/emulated/tests/bridges/bridge-hub-westend/Cargo.toml @@ -11,7 +11,6 @@ publish = false workspace = true [dependencies] -codec = { package = "parity-scale-codec", version = "3.6.0" } # Substrate frame-support = { path = "../../../../../../../substrate/frame/support", default-features = false } 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 3a8ce7d43f3e6da98fb2160a62c43c3964f0fe77..597e77d9049cf030fc2b0f0d8e986da53f1f08e2 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 @@ -59,15 +59,19 @@ fn send_asset_from_penpal_westend_through_local_asset_hub_to_rococo_asset_hub( AccountId32Junction { network: None, id: AssetHubRococoReceiver::get().into() }.into(); let assets: Assets = (id.clone(), transfer_amount).into(); let fees_id: AssetId = id.into(); + let custom_xcm_on_dest = Xcm::<()>(vec![DepositAsset { + assets: Wild(AllCounted(assets.len() as u32)), + beneficiary, + }]); - ::PolkadotXcm::transfer_assets_using_type( + ::PolkadotXcm::transfer_assets_using_type_and_then( signed_origin, bx!(destination.into()), - bx!(beneficiary.into()), bx!(assets.into()), bx!(TransferType::RemoteReserve(local_asset_hub.clone().into())), bx!(fees_id.into()), bx!(TransferType::RemoteReserve(local_asset_hub.into())), + bx!(VersionedXcm::from(custom_xcm_on_dest)), WeightLimit::Unlimited, ) })); diff --git a/cumulus/parachains/integration-tests/emulated/tests/bridges/bridge-hub-westend/src/tests/send_xcm.rs b/cumulus/parachains/integration-tests/emulated/tests/bridges/bridge-hub-westend/src/tests/send_xcm.rs index f69747c17704cb47e11ec00e2d8a08a413fab0a4..b01be5e8dc84b4edf35651d0388baa1462b54c9b 100644 --- a/cumulus/parachains/integration-tests/emulated/tests/bridges/bridge-hub-westend/src/tests/send_xcm.rs +++ b/cumulus/parachains/integration-tests/emulated/tests/bridges/bridge-hub-westend/src/tests/send_xcm.rs @@ -14,7 +14,6 @@ // limitations under the License. use crate::tests::*; -use codec::Encode; #[test] fn send_xcm_from_westend_relay_to_rococo_asset_hub_should_fail_on_not_applicable() { @@ -27,7 +26,7 @@ fn send_xcm_from_westend_relay_to_rococo_asset_hub_should_fail_on_not_applicable let remote_xcm = Xcm(vec![ClearOrigin]); - let xcm = VersionedXcm::from(Xcm::<()>(vec![ + let xcm = VersionedXcm::from(Xcm(vec![ UnpaidExecution { weight_limit, check_origin }, ExportMessage { network: RococoId, @@ -39,10 +38,10 @@ fn send_xcm_from_westend_relay_to_rococo_asset_hub_should_fail_on_not_applicable // Westend Global Consensus // Send XCM message from Relay Chain to Bridge Hub source Parachain Westend::execute_with(|| { - assert_ok!(::XcmPallet::send_blob( + assert_ok!(::XcmPallet::send( sudo_origin, bx!(destination), - xcm.encode().try_into().unwrap(), + bx!(xcm), )); type RuntimeEvent = ::RuntimeEvent; diff --git a/cumulus/parachains/integration-tests/emulated/tests/collectives/collectives-westend/Cargo.toml b/cumulus/parachains/integration-tests/emulated/tests/collectives/collectives-westend/Cargo.toml new file mode 100644 index 0000000000000000000000000000000000000000..297f68de6218317017a36c9535ad581aa86e2883 --- /dev/null +++ b/cumulus/parachains/integration-tests/emulated/tests/collectives/collectives-westend/Cargo.toml @@ -0,0 +1,43 @@ +[package] +name = "collectives-westend-integration-tests" +version = "1.0.0" +authors.workspace = true +edition.workspace = true +license = "Apache-2.0" +description = "Collectives Westend runtime integration tests with xcm-emulator" +publish = false + +[lints] +workspace = true + +[dependencies] +codec = { package = "parity-scale-codec", version = "3.6.12", default-features = false } +assert_matches = "1.5.0" + +# Substrate +sp-runtime = { path = "../../../../../../../substrate/primitives/runtime", default-features = false } +frame-support = { path = "../../../../../../../substrate/frame/support", default-features = false } +pallet-balances = { path = "../../../../../../../substrate/frame/balances", default-features = false } +pallet-asset-rate = { path = "../../../../../../../substrate/frame/asset-rate", default-features = false } +pallet-assets = { path = "../../../../../../../substrate/frame/assets", default-features = false } +pallet-treasury = { path = "../../../../../../../substrate/frame/treasury", default-features = false } +pallet-message-queue = { path = "../../../../../../../substrate/frame/message-queue", default-features = false } +pallet-utility = { path = "../../../../../../../substrate/frame/utility", default-features = false } + +# Polkadot +polkadot-runtime-common = { path = "../../../../../../../polkadot/runtime/common" } +xcm = { package = "staging-xcm", path = "../../../../../../../polkadot/xcm", default-features = false } +xcm-executor = { package = "staging-xcm-executor", path = "../../../../../../../polkadot/xcm/xcm-executor", default-features = false } +pallet-xcm = { path = "../../../../../../../polkadot/xcm/pallet-xcm", default-features = false } +westend-runtime = { path = "../../../../../../../polkadot/runtime/westend" } +westend-runtime-constants = { path = "../../../../../../../polkadot/runtime/westend/constants" } + +# Cumulus +parachains-common = { path = "../../../../../../parachains/common" } +testnet-parachains-constants = { path = "../../../../../runtimes/constants", features = ["westend"] } +asset-hub-westend-runtime = { path = "../../../../../runtimes/assets/asset-hub-westend" } +collectives-westend-runtime = { path = "../../../../../runtimes/collectives/collectives-westend" } +cumulus-pallet-xcmp-queue = { default-features = false, path = "../../../../../../pallets/xcmp-queue" } +cumulus-pallet-parachain-system = { default-features = false, path = "../../../../../../pallets/parachain-system" } +emulated-integration-tests-common = { path = "../../../common", default-features = false } +westend-system-emulated-network = { path = "../../../networks/westend-system" } diff --git a/cumulus/parachains/integration-tests/emulated/tests/collectives/collectives-westend/src/lib.rs b/cumulus/parachains/integration-tests/emulated/tests/collectives/collectives-westend/src/lib.rs new file mode 100644 index 0000000000000000000000000000000000000000..97239330216ac8f66a7684811d1de30b13f56f7e --- /dev/null +++ b/cumulus/parachains/integration-tests/emulated/tests/collectives/collectives-westend/src/lib.rs @@ -0,0 +1,30 @@ +// 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 use xcm::{prelude::*, v3}; + +pub use emulated_integration_tests_common::xcm_emulator::{ + assert_expected_events, bx, Chain, RelayChain as Relay, TestExt, +}; +pub use westend_system_emulated_network::{ + asset_hub_westend_emulated_chain::AssetHubWestendParaPallet as AssetHubWestendPallet, + collectives_westend_emulated_chain::CollectivesWestendParaPallet as CollectivesWestendPallet, + westend_emulated_chain::WestendRelayPallet as WestendPallet, + AssetHubWestendPara as AssetHubWestend, CollectivesWestendPara as CollectivesWestend, + WestendRelay as Westend, +}; + +#[cfg(test)] +mod tests; diff --git a/cumulus/parachains/integration-tests/emulated/tests/collectives/collectives-westend/src/tests/fellowship_treasury.rs b/cumulus/parachains/integration-tests/emulated/tests/collectives/collectives-westend/src/tests/fellowship_treasury.rs new file mode 100644 index 0000000000000000000000000000000000000000..bde1220e2495bc544e507be1a8b40d77fcbde894 --- /dev/null +++ b/cumulus/parachains/integration-tests/emulated/tests/collectives/collectives-westend/src/tests/fellowship_treasury.rs @@ -0,0 +1,236 @@ +// 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::*; +use asset_hub_westend_runtime::xcm_config::LocationToAccountId as AssetHubLocationToAccountId; +use emulated_integration_tests_common::accounts::ALICE; +use frame_support::{ + assert_ok, dispatch::RawOrigin, instances::Instance1, sp_runtime::traits::Dispatchable, + traits::fungible::Inspect, +}; +use polkadot_runtime_common::impls::VersionedLocatableAsset; +use westend_runtime::OriginCaller; +use westend_runtime_constants::currency::UNITS; +use xcm_executor::traits::ConvertLocation; + +// Fund Fellowship Treasury from Westend Treasury and spend from Fellowship Treasury. +#[test] +fn fellowship_treasury_spend() { + // initial treasury balance on Asset Hub in WNDs. + let treasury_balance = 20_000_000 * UNITS; + // target fellowship balance on Asset Hub in WNDs. + let fellowship_treasury_balance = 1_000_000 * UNITS; + // fellowship first spend balance in WNDs. + let fellowship_spend_balance = 10_000 * UNITS; + + let init_alice_balance = AssetHubWestend::execute_with(|| { + <::Balances as Inspect<_>>::balance( + &AssetHubWestend::account_id_of(ALICE), + ) + }); + + Westend::execute_with(|| { + type RuntimeEvent = ::RuntimeEvent; + type RuntimeCall = ::RuntimeCall; + type Runtime = ::Runtime; + type Balances = ::Balances; + type Treasury = ::Treasury; + + // Fund Treasury account on Asset Hub with WNDs. + + let root = ::RuntimeOrigin::root(); + let treasury_account = Treasury::account_id(); + + // Mist assets to Treasury account on Relay Chain. + assert_ok!(Balances::force_set_balance( + root.clone(), + treasury_account.clone().into(), + treasury_balance * 2, + )); + + let native_asset = Location::here(); + let asset_hub_location: Location = [Parachain(1000)].into(); + let treasury_location: Location = (Parent, PalletInstance(37)).into(); + + let teleport_call = RuntimeCall::Utility(pallet_utility::Call::::dispatch_as { + as_origin: bx!(OriginCaller::system(RawOrigin::Signed(treasury_account))), + call: bx!(RuntimeCall::XcmPallet(pallet_xcm::Call::::teleport_assets { + dest: bx!(VersionedLocation::V4(asset_hub_location.clone())), + beneficiary: bx!(VersionedLocation::V4(treasury_location)), + assets: bx!(VersionedAssets::V4( + Asset { id: native_asset.clone().into(), fun: treasury_balance.into() }.into() + )), + fee_asset_item: 0, + })), + }); + + // Dispatched from Root to `dispatch_as` `Signed(treasury_account)`. + assert_ok!(teleport_call.dispatch(root)); + + assert_expected_events!( + Westend, + vec![ + RuntimeEvent::XcmPallet(pallet_xcm::Event::Sent { .. }) => {}, + ] + ); + }); + + Westend::execute_with(|| { + type RuntimeEvent = ::RuntimeEvent; + type RuntimeCall = ::RuntimeCall; + type RuntimeOrigin = ::RuntimeOrigin; + type Runtime = ::Runtime; + type Treasury = ::Treasury; + + // Fund Fellowship Treasury from Westend Treasury. + + let treasury_origin: RuntimeOrigin = + westend_runtime::governance::pallet_custom_origins::Origin::Treasurer.into(); + let fellowship_treasury_location: Location = + Location::new(1, [Parachain(1001), PalletInstance(65)]); + let asset_hub_location: Location = [Parachain(1000)].into(); + let native_asset = Location::parent(); + + let treasury_spend_call = RuntimeCall::Treasury(pallet_treasury::Call::::spend { + asset_kind: bx!(VersionedLocatableAsset::V4 { + location: asset_hub_location.clone(), + asset_id: native_asset.into(), + }), + amount: fellowship_treasury_balance, + beneficiary: bx!(VersionedLocation::V4(fellowship_treasury_location)), + valid_from: None, + }); + + assert_ok!(treasury_spend_call.dispatch(treasury_origin)); + + // Claim the spend. + + let alice_signed = RuntimeOrigin::signed(Westend::account_id_of(ALICE)); + assert_ok!(Treasury::payout(alice_signed.clone(), 0)); + + assert_expected_events!( + Westend, + vec![ + RuntimeEvent::Treasury(pallet_treasury::Event::AssetSpendApproved { .. }) => {}, + RuntimeEvent::Treasury(pallet_treasury::Event::Paid { .. }) => {}, + ] + ); + }); + + AssetHubWestend::execute_with(|| { + type RuntimeEvent = ::RuntimeEvent; + type Balances = ::Balances; + + // Ensure that the funds deposited to the Fellowship Treasury account. + + let fellowship_treasury_location: Location = + Location::new(1, [Parachain(1001), PalletInstance(65)]); + let fellowship_treasury_account = + AssetHubLocationToAccountId::convert_location(&fellowship_treasury_location).unwrap(); + + assert_eq!( + >::balance(&fellowship_treasury_account), + fellowship_treasury_balance + ); + + // Assert events triggered by xcm pay program: + // 1. treasury asset transferred to spend beneficiary; + // 2. response to Relay Chain Treasury pallet instance sent back; + // 3. XCM program completed; + assert_expected_events!( + AssetHubWestend, + vec![ + RuntimeEvent::Balances(pallet_balances::Event::Transfer { .. }) => {}, + RuntimeEvent::ParachainSystem(cumulus_pallet_parachain_system::Event::UpwardMessageSent { .. }) => {}, + RuntimeEvent::MessageQueue(pallet_message_queue::Event::Processed { success: true ,.. }) => {}, + ] + ); + }); + + CollectivesWestend::execute_with(|| { + type RuntimeEvent = ::RuntimeEvent; + type RuntimeCall = ::RuntimeCall; + type RuntimeOrigin = ::RuntimeOrigin; + type Runtime = ::Runtime; + type FellowshipTreasury = + ::FellowshipTreasury; + + // Fund Alice account from Fellowship Treasury. + + let fellows_origin: RuntimeOrigin = + collectives_westend_runtime::fellowship::pallet_fellowship_origins::Origin::Fellows + .into(); + let asset_hub_location: Location = (Parent, Parachain(1000)).into(); + let native_asset = Location::parent(); + + let alice_location: Location = [Junction::AccountId32 { + network: None, + id: CollectivesWestend::account_id_of(ALICE).into(), + }] + .into(); + + let fellowship_treasury_spend_call = + RuntimeCall::FellowshipTreasury(pallet_treasury::Call::::spend { + asset_kind: bx!(VersionedLocatableAsset::V4 { + location: asset_hub_location, + asset_id: native_asset.into(), + }), + amount: fellowship_spend_balance, + beneficiary: bx!(VersionedLocation::V4(alice_location)), + valid_from: None, + }); + + assert_ok!(fellowship_treasury_spend_call.dispatch(fellows_origin)); + + // Claim the spend. + + let alice_signed = RuntimeOrigin::signed(CollectivesWestend::account_id_of(ALICE)); + assert_ok!(FellowshipTreasury::payout(alice_signed.clone(), 0)); + + assert_expected_events!( + CollectivesWestend, + vec![ + RuntimeEvent::FellowshipTreasury(pallet_treasury::Event::AssetSpendApproved { .. }) => {}, + RuntimeEvent::FellowshipTreasury(pallet_treasury::Event::Paid { .. }) => {}, + ] + ); + }); + + AssetHubWestend::execute_with(|| { + type RuntimeEvent = ::RuntimeEvent; + type Balances = ::Balances; + + // Ensure that the funds deposited to Alice account. + + let alice_account = AssetHubWestend::account_id_of(ALICE); + assert_eq!( + >::balance(&alice_account), + fellowship_spend_balance + init_alice_balance + ); + + // Assert events triggered by xcm pay program: + // 1. treasury asset transferred to spend beneficiary; + // 2. response to Relay Chain Treasury pallet instance sent back; + // 3. XCM program completed; + assert_expected_events!( + AssetHubWestend, + vec![ + RuntimeEvent::Balances(pallet_balances::Event::Transfer { .. }) => {}, + RuntimeEvent::XcmpQueue(cumulus_pallet_xcmp_queue::Event::XcmpMessageSent { .. }) => {}, + RuntimeEvent::MessageQueue(pallet_message_queue::Event::Processed { success: true ,.. }) => {}, + ] + ); + }); +} diff --git a/substrate/utils/frame/frame-utilities-cli/src/lib.rs b/cumulus/parachains/integration-tests/emulated/tests/collectives/collectives-westend/src/tests/mod.rs similarity index 84% rename from substrate/utils/frame/frame-utilities-cli/src/lib.rs rename to cumulus/parachains/integration-tests/emulated/tests/collectives/collectives-westend/src/tests/mod.rs index 97129e36f7e9c04664a793d75d00e8bf8a86a413..a9f65df34b647835b4ce5585be6b53b0489de578 100644 --- a/substrate/utils/frame/frame-utilities-cli/src/lib.rs +++ b/cumulus/parachains/integration-tests/emulated/tests/collectives/collectives-westend/src/tests/mod.rs @@ -1,5 +1,3 @@ -// This file is part of Substrate. - // Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 @@ -15,8 +13,4 @@ // See the License for the specific language governing permissions and // limitations under the License. -//! frame-system CLI utilities - -mod pallet_id; - -pub use pallet_id::PalletIdCmd; +mod fellowship_treasury; diff --git a/cumulus/parachains/integration-tests/emulated/tests/people/people-rococo/Cargo.toml b/cumulus/parachains/integration-tests/emulated/tests/people/people-rococo/Cargo.toml index 1570aa7662fcbbfe1b018251d2700ce2d653d165..29a939951e597a939de5ed9d244193ac8455e4d5 100644 --- a/cumulus/parachains/integration-tests/emulated/tests/people/people-rococo/Cargo.toml +++ b/cumulus/parachains/integration-tests/emulated/tests/people/people-rococo/Cargo.toml @@ -8,7 +8,7 @@ description = "People Rococo runtime integration tests with xcm-emulator" publish = false [dependencies] -codec = { package = "parity-scale-codec", version = "3.4.0", default-features = false } +codec = { package = "parity-scale-codec", version = "3.6.12", default-features = false } # Substrate sp-runtime = { path = "../../../../../../../substrate/primitives/runtime", default-features = false } diff --git a/cumulus/parachains/integration-tests/emulated/tests/people/people-westend/Cargo.toml b/cumulus/parachains/integration-tests/emulated/tests/people/people-westend/Cargo.toml index bc093dc0de6356d7cd98d20d12d63748ed248ff5..6eab6f52aa72172ecc19fa891109fc9df859ec3c 100644 --- a/cumulus/parachains/integration-tests/emulated/tests/people/people-westend/Cargo.toml +++ b/cumulus/parachains/integration-tests/emulated/tests/people/people-westend/Cargo.toml @@ -8,7 +8,7 @@ description = "People Westend runtime integration tests with xcm-emulator" publish = false [dependencies] -codec = { package = "parity-scale-codec", version = "3.4.0", default-features = false } +codec = { package = "parity-scale-codec", version = "3.6.12", default-features = false } # Substrate sp-runtime = { path = "../../../../../../../substrate/primitives/runtime", default-features = false } diff --git a/cumulus/parachains/pallets/collective-content/Cargo.toml b/cumulus/parachains/pallets/collective-content/Cargo.toml index b3fac47cb4ae2d78bdf7431d877a4a6edeb34ebb..92e0a54631394154634900829c708431b2931b67 100644 --- a/cumulus/parachains/pallets/collective-content/Cargo.toml +++ b/cumulus/parachains/pallets/collective-content/Cargo.toml @@ -2,7 +2,7 @@ name = "pallet-collective-content" version = "0.6.0" authors = ["Parity Technologies "] -edition = "2021" +edition.workspace = true description = "Managed content" license = "Apache-2.0" @@ -10,7 +10,7 @@ license = "Apache-2.0" workspace = true [dependencies] -codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = ["derive", "max-encoded-len"] } +codec = { package = "parity-scale-codec", version = "3.6.12", default-features = false, features = ["derive", "max-encoded-len"] } scale-info = { version = "2.11.1", default-features = false, features = ["derive"] } frame-benchmarking = { path = "../../../../substrate/frame/benchmarking", default-features = false, optional = true } diff --git a/cumulus/parachains/pallets/parachain-info/Cargo.toml b/cumulus/parachains/pallets/parachain-info/Cargo.toml index 17981d238fd1880e81ce04ebbe5b2a045ba27e41..01ee12bf4e719a9fde63fa4adb43bc6ff4e5c3ea 100644 --- a/cumulus/parachains/pallets/parachain-info/Cargo.toml +++ b/cumulus/parachains/pallets/parachain-info/Cargo.toml @@ -10,7 +10,7 @@ description = "Pallet to store the parachain ID" workspace = true [dependencies] -codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = ["derive"] } +codec = { package = "parity-scale-codec", version = "3.6.12", default-features = false, features = ["derive"] } scale-info = { version = "2.11.1", default-features = false, features = ["derive"] } frame-support = { path = "../../../../substrate/frame/support", default-features = false } diff --git a/cumulus/parachains/pallets/ping/Cargo.toml b/cumulus/parachains/pallets/ping/Cargo.toml index 15169b08b9108998d850f6333e458d73580d1b2a..f51946e9ebd5d2c5fd471683a217fe2dbe8f2f61 100644 --- a/cumulus/parachains/pallets/ping/Cargo.toml +++ b/cumulus/parachains/pallets/ping/Cargo.toml @@ -10,7 +10,7 @@ description = "Ping Pallet for Cumulus XCM/UMP testing." workspace = true [dependencies] -codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = ["derive"] } +codec = { package = "parity-scale-codec", version = "3.6.12", default-features = false, features = ["derive"] } scale-info = { version = "2.11.1", default-features = false, features = ["derive"] } sp-std = { path = "../../../../substrate/primitives/std", default-features = false } diff --git a/cumulus/parachains/runtimes/assets/asset-hub-rococo/Cargo.toml b/cumulus/parachains/runtimes/assets/asset-hub-rococo/Cargo.toml index 0733156716c11a6e1e50c9d921f059a2e2c1b193..95ce7efdf3fba7b67ac54c9542dc862f9f82f2ce 100644 --- a/cumulus/parachains/runtimes/assets/asset-hub-rococo/Cargo.toml +++ b/cumulus/parachains/runtimes/assets/asset-hub-rococo/Cargo.toml @@ -10,7 +10,7 @@ license = "Apache-2.0" workspace = true [dependencies] -codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = ["derive", "max-encoded-len"] } +codec = { package = "parity-scale-codec", version = "3.6.12", default-features = false, features = ["derive", "max-encoded-len"] } hex-literal = { version = "0.4.1" } log = { workspace = true } scale-info = { version = "2.11.1", default-features = false, features = ["derive"] } @@ -25,6 +25,7 @@ frame-system-rpc-runtime-api = { path = "../../../../../substrate/frame/system/r frame-try-runtime = { path = "../../../../../substrate/frame/try-runtime", default-features = false, optional = true } pallet-asset-conversion-tx-payment = { path = "../../../../../substrate/frame/transaction-payment/asset-conversion-tx-payment", default-features = false } pallet-assets = { path = "../../../../../substrate/frame/assets", default-features = false } +pallet-asset-conversion-ops = { path = "../../../../../substrate/frame/asset-conversion/ops", default-features = false } pallet-asset-conversion = { path = "../../../../../substrate/frame/asset-conversion", default-features = false } pallet-aura = { path = "../../../../../substrate/frame/aura", default-features = false } pallet-authorship = { path = "../../../../../substrate/frame/authorship", default-features = false } @@ -36,7 +37,6 @@ pallet-nfts = { path = "../../../../../substrate/frame/nfts", default-features = pallet-nfts-runtime-api = { path = "../../../../../substrate/frame/nfts/runtime-api", default-features = false } pallet-proxy = { path = "../../../../../substrate/frame/proxy", default-features = false } pallet-session = { path = "../../../../../substrate/frame/session", default-features = false } -pallet-state-trie-migration = { path = "../../../../../substrate/frame/state-trie-migration", default-features = false, optional = true } 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 } @@ -68,6 +68,7 @@ polkadot-runtime-common = { path = "../../../../../polkadot/runtime/common", def xcm = { package = "staging-xcm", path = "../../../../../polkadot/xcm", default-features = false } xcm-builder = { package = "staging-xcm-builder", path = "../../../../../polkadot/xcm/xcm-builder", default-features = false } xcm-executor = { package = "staging-xcm-executor", path = "../../../../../polkadot/xcm/xcm-executor", default-features = false } +xcm-fee-payment-runtime-api = { path = "../../../../../polkadot/xcm/xcm-fee-payment-runtime-api", default-features = false } # Cumulus cumulus-pallet-aura-ext = { path = "../../../../pallets/aura-ext", default-features = false } @@ -101,14 +102,6 @@ substrate-wasm-builder = { path = "../../../../../substrate/utils/wasm-builder", [features] default = ["std"] -# When enabled the `state_version` is set to `1`. -# This means that the chain will start using the new state format. The migration is lazy, so -# it requires to write a storage value to use the new state format. To migrate all the other -# storage values that aren't touched the state migration pallet is added as well. -# This pallet will migrate the entire state, controlled through some account. -# -# This feature should be removed when the main-net will be migrated. -state-trie-version-1 = ["pallet-state-trie-migration"] runtime-benchmarks = [ "assets-common/runtime-benchmarks", "cumulus-pallet-parachain-system/runtime-benchmarks", @@ -120,6 +113,7 @@ runtime-benchmarks = [ "frame-support/runtime-benchmarks", "frame-system-benchmarking/runtime-benchmarks", "frame-system/runtime-benchmarks", + "pallet-asset-conversion-ops/runtime-benchmarks", "pallet-asset-conversion/runtime-benchmarks", "pallet-assets/runtime-benchmarks", "pallet-balances/runtime-benchmarks", @@ -129,7 +123,6 @@ runtime-benchmarks = [ "pallet-nft-fractionalization/runtime-benchmarks", "pallet-nfts/runtime-benchmarks", "pallet-proxy/runtime-benchmarks", - "pallet-state-trie-migration/runtime-benchmarks", "pallet-timestamp/runtime-benchmarks", "pallet-uniques/runtime-benchmarks", "pallet-utility/runtime-benchmarks", @@ -143,6 +136,7 @@ runtime-benchmarks = [ "sp-runtime/runtime-benchmarks", "xcm-builder/runtime-benchmarks", "xcm-executor/runtime-benchmarks", + "xcm-fee-payment-runtime-api/runtime-benchmarks", ] try-runtime = [ "cumulus-pallet-aura-ext/try-runtime", @@ -153,6 +147,7 @@ try-runtime = [ "frame-support/try-runtime", "frame-system/try-runtime", "frame-try-runtime/try-runtime", + "pallet-asset-conversion-ops/try-runtime", "pallet-asset-conversion-tx-payment/try-runtime", "pallet-asset-conversion/try-runtime", "pallet-assets/try-runtime", @@ -166,7 +161,6 @@ try-runtime = [ "pallet-nfts/try-runtime", "pallet-proxy/try-runtime", "pallet-session/try-runtime", - "pallet-state-trie-migration/try-runtime", "pallet-timestamp/try-runtime", "pallet-transaction-payment/try-runtime", "pallet-uniques/try-runtime", @@ -201,6 +195,7 @@ std = [ "frame-system/std", "frame-try-runtime?/std", "log/std", + "pallet-asset-conversion-ops/std", "pallet-asset-conversion-tx-payment/std", "pallet-asset-conversion/std", "pallet-assets/std", @@ -215,7 +210,6 @@ std = [ "pallet-nfts/std", "pallet-proxy/std", "pallet-session/std", - "pallet-state-trie-migration/std", "pallet-timestamp/std", "pallet-transaction-payment-rpc-runtime-api/std", "pallet-transaction-payment/std", @@ -250,6 +244,7 @@ std = [ "testnet-parachains-constants/std", "xcm-builder/std", "xcm-executor/std", + "xcm-fee-payment-runtime-api/std", "xcm/std", ] diff --git a/cumulus/parachains/runtimes/assets/asset-hub-rococo/build.rs b/cumulus/parachains/runtimes/assets/asset-hub-rococo/build.rs index 60f8a125129ff1344a1799246e931acdb1d139d5..239ccac19ec7778039fb1ee56f4e772b3ddd3711 100644 --- a/cumulus/parachains/runtimes/assets/asset-hub-rococo/build.rs +++ b/cumulus/parachains/runtimes/assets/asset-hub-rococo/build.rs @@ -15,11 +15,7 @@ #[cfg(feature = "std")] fn main() { - substrate_wasm_builder::WasmBuilder::new() - .with_current_project() - .export_heap_base() - .import_memory() - .build() + substrate_wasm_builder::WasmBuilder::build_using_defaults(); } #[cfg(not(feature = "std"))] 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 23d8f9b667dd86ce3de7fd2a3a2159710ab68351..b0df11e1046a370721820911d238ea6af716b243 100644 --- a/cumulus/parachains/runtimes/assets/asset-hub-rococo/src/lib.rs +++ b/cumulus/parachains/runtimes/assets/asset-hub-rococo/src/lib.rs @@ -62,7 +62,7 @@ use frame_support::{ ConstU128, ConstU32, ConstU64, ConstU8, EitherOfDiverse, Equals, InstanceFilter, TransformOrigin, }, - weights::{ConstantMultiplier, Weight}, + weights::{ConstantMultiplier, Weight, WeightToFee as _}, BoundedVec, PalletId, }; use frame_system::{ @@ -91,13 +91,19 @@ pub use sp_runtime::BuildStorage; // Polkadot imports use pallet_xcm::{EnsureXcm, IsVoiceOfBody}; use polkadot_runtime_common::{BlockHashCount, SlowAdjustingFeeUpdate}; -// We exclude `Assets` since it's the name of a pallet #[cfg(feature = "runtime-benchmarks")] use xcm::latest::prelude::{ Asset, Fungible, Here, InteriorLocation, Junction, Junction::*, Location, NetworkId, NonFungible, Parent, ParentThen, Response, XCM_VERSION, }; -use xcm::latest::prelude::{AssetId, BodyId}; +use xcm::{ + latest::prelude::{AssetId, BodyId}, + IntoVersion, VersionedAssetId, VersionedAssets, VersionedLocation, VersionedXcm, +}; +use xcm_fee_payment_runtime_api::{ + dry_run::{Error as XcmDryRunApiError, ExtrinsicDryRunEffects, XcmDryRunEffects}, + fees::Error as XcmPaymentApiError, +}; use weights::{BlockExecutionWeight, ExtrinsicBaseWeight, RocksDbWeight}; @@ -107,32 +113,18 @@ impl_opaque_keys! { } } -#[cfg(feature = "state-trie-version-1")] #[sp_version::runtime_version] pub const VERSION: RuntimeVersion = RuntimeVersion { spec_name: create_runtime_str!("statemine"), impl_name: create_runtime_str!("statemine"), authoring_version: 1, - spec_version: 1_010_000, + spec_version: 1_011_000, impl_version: 0, apis: RUNTIME_API_VERSIONS, - transaction_version: 14, + transaction_version: 15, state_version: 1, }; -#[cfg(not(feature = "state-trie-version-1"))] -#[sp_version::runtime_version] -pub const VERSION: RuntimeVersion = RuntimeVersion { - spec_name: create_runtime_str!("statemine"), - impl_name: create_runtime_str!("statemine"), - authoring_version: 1, - spec_version: 1_010_000, - impl_version: 0, - apis: RUNTIME_API_VERSIONS, - transaction_version: 14, - state_version: 0, -}; - /// The version information used to identify this runtime when compiled natively. #[cfg(feature = "std")] pub fn native_version() -> NativeVersion { @@ -333,6 +325,11 @@ pub type NativeAndAssets = fungible::UnionOf< AccountId, >; +pub type PoolIdToAccountId = pallet_asset_conversion::AccountIdConverter< + AssetConversionPalletId, + (xcm::v3::Location, xcm::v3::Location), +>; + impl pallet_asset_conversion::Config for Runtime { type RuntimeEvent = RuntimeEvent; type Balance = Balance; @@ -340,8 +337,12 @@ impl pallet_asset_conversion::Config for Runtime { type AssetKind = xcm::v3::Location; type Assets = NativeAndAssets; type PoolId = (Self::AssetKind, Self::AssetKind); - type PoolLocator = - pallet_asset_conversion::WithFirstAsset; + type PoolLocator = pallet_asset_conversion::WithFirstAsset< + TokenLocationV3, + AccountId, + Self::AssetKind, + PoolIdToAccountId, + >; type PoolAssetId = u32; type PoolAssets = PoolAssets; type PoolSetupFee = ConstU128<0>; // Asset class deposit fees are sufficient to prevent spam @@ -362,6 +363,18 @@ impl pallet_asset_conversion::Config for Runtime { >; } +impl pallet_asset_conversion_ops::Config for Runtime { + type RuntimeEvent = RuntimeEvent; + type PriorAccountIdConverter = pallet_asset_conversion::AccountIdConverterNoSeed< + ::PoolId, + >; + type AssetsRefund = ::Assets; + type PoolAssetsRefund = ::PoolAssets; + type PoolAssetsTeam = ::PoolAssets; + type DepositAsset = Balances; + type WeightInfo = weights::pallet_asset_conversion_ops::WeightInfo; +} + parameter_types! { // we just reuse the same deposits pub const ForeignAssetsAssetDeposit: Balance = AssetDeposit::get(); @@ -657,7 +670,7 @@ impl pallet_message_queue::Config for Runtime { // The XCMP queue pallet is only ever able to handle the `Sibling(ParaId)` origin: type QueueChangeHandler = NarrowOriginToSibling; type QueuePausedQuery = NarrowOriginToSibling; - type HeapSize = sp_core::ConstU32<{ 64 * 1024 }>; + type HeapSize = sp_core::ConstU32<{ 103 * 1024 }>; type MaxStale = sp_core::ConstU32<8>; type ServiceWeight = MessageQueueServiceWeight; type IdleMaxServiceWeight = MessageQueueServiceWeight; @@ -687,12 +700,21 @@ impl cumulus_pallet_xcmp_queue::Config for Runtime { type ChannelInfo = ParachainSystem; type VersionWrapper = PolkadotXcm; type XcmpQueue = TransformOrigin; - type MaxInboundSuspended = sp_core::ConstU32<1_000>; + type MaxInboundSuspended = ConstU32<1_000>; + type MaxActiveOutboundChannels = ConstU32<128>; + // Most on-chain HRMP channels are configured to use 102400 bytes of max message size, so we + // need to set the page size larger than that until we reduce the channel size on-chain. + type MaxPageSize = ConstU32<{ 103 * 1024 }>; type ControllerOrigin = EnsureRoot; type ControllerOriginConverter = xcm_config::XcmOriginToTransactDispatchOrigin; type PriceForSiblingDelivery = PriceForSiblingParachainDelivery; } +impl cumulus_pallet_xcmp_queue::migration::v5::V5Config for Runtime { + // This must be the same as the `ChannelInfo` from the `Config`: + type ChannelList = ParachainSystem; +} + parameter_types! { pub const RelayOrigin: AggregateMessageOrigin = AggregateMessageOrigin::Parent; } @@ -932,8 +954,9 @@ construct_runtime!( PoolAssets: pallet_assets:: = 55, AssetConversion: pallet_asset_conversion = 56, - #[cfg(feature = "state-trie-version-1")] - StateTrieMigration: pallet_state_trie_migration = 70, + // TODO: the pallet instance should be removed once all pools have migrated + // to the new account IDs. + AssetConversionMigration: pallet_asset_conversion_ops = 200, } ); @@ -961,11 +984,13 @@ pub type SignedExtra = ( pub type UncheckedExtrinsic = generic::UncheckedExtrinsic; /// Migrations to apply on runtime upgrade. +#[allow(deprecated)] pub type Migrations = ( - pallet_collator_selection::migration::v1::MigrateToV1, InitStorageVersions, // unreleased cumulus_pallet_xcmp_queue::migration::v4::MigrationToV4, + cumulus_pallet_xcmp_queue::migration::v5::MigrateV4ToV5, + pallet_collator_selection::migration::v2::MigrationToV2, // permanent pallet_xcm::migration::MigrateToLatestXcmVersion, ); @@ -1054,6 +1079,7 @@ mod benches { [cumulus_pallet_parachain_system, ParachainSystem] [cumulus_pallet_xcmp_queue, XcmpQueue] [pallet_xcm_bridge_hub_router, ToWestend] + [pallet_asset_conversion_ops, AssetConversionMigration] // XCM [pallet_xcm, PalletXcmExtrinsicsBenchmark::] // NOTE: Make sure you point to the individual modules below. @@ -1266,6 +1292,109 @@ impl_runtime_apis! { } } + impl xcm_fee_payment_runtime_api::fees::XcmPaymentApi for Runtime { + fn query_acceptable_payment_assets(xcm_version: xcm::Version) -> Result, XcmPaymentApiError> { + let acceptable = vec![ + // native token + VersionedAssetId::from(AssetId(xcm_config::TokenLocation::get())) + ]; + + Ok(acceptable + .into_iter() + .filter_map(|asset| asset.into_version(xcm_version).ok()) + .collect()) + } + + fn query_weight_to_asset_fee(weight: Weight, asset: VersionedAssetId) -> Result { + match asset.try_as::() { + Ok(asset_id) if asset_id.0 == xcm_config::TokenLocation::get() => { + // for native token + Ok(WeightToFee::weight_to_fee(&weight)) + }, + Ok(asset_id) => { + log::trace!(target: "xcm::xcm_fee_payment_runtime_api", "query_weight_to_asset_fee - unhandled asset_id: {asset_id:?}!"); + Err(XcmPaymentApiError::AssetNotFound) + }, + Err(_) => { + log::trace!(target: "xcm::xcm_fee_payment_runtime_api", "query_weight_to_asset_fee - failed to convert asset: {asset:?}!"); + Err(XcmPaymentApiError::VersionedConversionFailed) + } + } + } + + fn query_xcm_weight(message: VersionedXcm<()>) -> Result { + PolkadotXcm::query_xcm_weight(message) + } + + fn query_delivery_fees(destination: VersionedLocation, message: VersionedXcm<()>) -> Result { + PolkadotXcm::query_delivery_fees(destination, message) + } + } + + impl xcm_fee_payment_runtime_api::dry_run::XcmDryRunApi for Runtime { + fn dry_run_extrinsic(extrinsic: ::Extrinsic) -> Result, XcmDryRunApiError> { + use xcm_builder::InspectMessageQueues; + use xcm_executor::RecordXcm; + use xcm::prelude::*; + + pallet_xcm::Pallet::::set_record_xcm(true); + let result = Executive::apply_extrinsic(extrinsic).map_err(|error| { + log::error!( + target: "xcm::XcmDryRunApi::dry_run_extrinsic", + "Applying extrinsic failed with error {:?}", + error, + ); + XcmDryRunApiError::InvalidExtrinsic + })?; + let local_xcm = pallet_xcm::Pallet::::recorded_xcm(); + let forwarded_xcms = xcm_config::XcmRouter::get_messages(); + let events: Vec = System::read_events_no_consensus().map(|record| record.event.clone()).collect(); + Ok(ExtrinsicDryRunEffects { + local_xcm: local_xcm.map(VersionedXcm::<()>::V4), + forwarded_xcms, + emitted_events: events, + execution_result: result, + }) + } + + fn dry_run_xcm(origin_location: VersionedLocation, program: VersionedXcm) -> Result, XcmDryRunApiError> { + use xcm_builder::InspectMessageQueues; + use xcm::prelude::*; + + let origin_location: Location = origin_location.try_into().map_err(|error| { + log::error!( + target: "xcm::XcmDryRunApi::dry_run_xcm", + "Location version conversion failed with error: {:?}", + error, + ); + XcmDryRunApiError::VersionedConversionFailed + })?; + let program: Xcm = program.try_into().map_err(|error| { + log::error!( + target: "xcm::XcmDryRunApi::dry_run_xcm", + "Xcm version conversion failed with error {:?}", + error, + ); + XcmDryRunApiError::VersionedConversionFailed + })?; + let mut hash = program.using_encoded(sp_core::hashing::blake2_256); + let result = xcm_executor::XcmExecutor::::prepare_and_execute( + origin_location, + program, + &mut hash, + Weight::MAX, // Max limit available for execution. + Weight::zero(), + ); + let forwarded_xcms = xcm_config::XcmRouter::get_messages(); + let events: Vec = System::read_events_no_consensus().map(|record| record.event.clone()).collect(); + Ok(XcmDryRunEffects { + forwarded_xcms, + emitted_events: events, + execution_result: result, + }) + } + } + impl cumulus_primitives_core::CollectCollationInfo for Runtime { fn collect_collation_info(header: &::Header) -> cumulus_primitives_core::CollationInfo { ParachainSystem::collect_collation_info(header) @@ -1507,27 +1636,23 @@ impl_runtime_apis! { fn worst_case_holding(depositable_count: u32) -> xcm::v4::Assets { // A mix of fungible, non-fungible, and concrete assets. let holding_non_fungibles = MaxAssetsIntoHolding::get() / 2 - depositable_count; - let holding_fungibles = holding_non_fungibles.saturating_sub(1); + let holding_fungibles = holding_non_fungibles.saturating_sub(2); // -2 for two `iter::once` bellow let fungibles_amount: u128 = 100; - let mut assets = (0..holding_fungibles) + (0..holding_fungibles) .map(|i| { Asset { id: GeneralIndex(i as u128).into(), - fun: Fungible(fungibles_amount * i as u128), + fun: Fungible(fungibles_amount * (i + 1) as u128), // non-zero amount } }) .chain(core::iter::once(Asset { id: Here.into(), fun: Fungible(u128::MAX) })) + .chain(core::iter::once(Asset { id: AssetId(TokenLocation::get()), fun: Fungible(1_000_000 * UNITS) })) .chain((0..holding_non_fungibles).map(|i| Asset { id: GeneralIndex(i as u128).into(), fun: NonFungible(asset_instance_from(i)), })) - .collect::>(); - - assets.push(Asset { - id: AssetId(TokenLocation::get()), - fun: Fungible(1_000_000 * UNITS), - }); - assets.into() + .collect::>() + .into() } } @@ -1668,53 +1793,6 @@ cumulus_pallet_parachain_system::register_validate_block! { BlockExecutor = cumulus_pallet_aura_ext::BlockExecutor::, } -#[cfg(feature = "state-trie-version-1")] -parameter_types! { - // The deposit configuration for the singed migration. Specially if you want to allow any signed account to do the migration (see `SignedFilter`, these deposits should be high) - pub const MigrationSignedDepositPerItem: Balance = CENTS; - pub const MigrationSignedDepositBase: Balance = 2_000 * CENTS; - pub const MigrationMaxKeyLen: u32 = 512; -} - -#[cfg(feature = "state-trie-version-1")] -impl pallet_state_trie_migration::Config for Runtime { - type RuntimeEvent = RuntimeEvent; - type Currency = Balances; - type RuntimeHoldReason = RuntimeHoldReason; - type SignedDepositPerItem = MigrationSignedDepositPerItem; - type SignedDepositBase = MigrationSignedDepositBase; - // An origin that can control the whole pallet: should be Root, or a part of your council. - type ControlOrigin = frame_system::EnsureSignedBy; - // specific account for the migration, can trigger the signed migrations. - type SignedFilter = frame_system::EnsureSignedBy; - - // Replace this with weight based on your runtime. - type WeightInfo = pallet_state_trie_migration::weights::SubstrateWeight; - - type MaxKeyLen = MigrationMaxKeyLen; -} - -#[cfg(feature = "state-trie-version-1")] -frame_support::ord_parameter_types! { - pub const MigController: AccountId = AccountId::from(hex_literal::hex!("8458ed39dc4b6f6c7255f7bc42be50c2967db126357c999d44e12ca7ac80dc52")); - pub const RootMigController: AccountId = AccountId::from(hex_literal::hex!("8458ed39dc4b6f6c7255f7bc42be50c2967db126357c999d44e12ca7ac80dc52")); -} - -#[cfg(feature = "state-trie-version-1")] -#[test] -fn ensure_key_ss58() { - use frame_support::traits::SortedMembers; - use sp_core::crypto::Ss58Codec; - let acc = - AccountId::from_ss58check("5F4EbSkZz18X36xhbsjvDNs6NuZ82HyYtq5UiJ1h9SBHJXZD").unwrap(); - //panic!("{:x?}", acc); - assert_eq!(acc, MigController::sorted_members()[0]); - let acc = - AccountId::from_ss58check("5F4EbSkZz18X36xhbsjvDNs6NuZ82HyYtq5UiJ1h9SBHJXZD").unwrap(); - assert_eq!(acc, RootMigController::sorted_members()[0]); - //panic!("{:x?}", acc); -} - #[cfg(test)] mod tests { use super::*; 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..f20790cde39ced67a7d51c8678441ad423ee888f 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 @@ -20,6 +20,7 @@ pub mod cumulus_pallet_xcmp_queue; pub mod extrinsic_weights; pub mod frame_system; pub mod pallet_asset_conversion; +pub mod pallet_asset_conversion_ops; pub mod pallet_assets_foreign; pub mod pallet_assets_local; pub mod pallet_assets_pool; diff --git a/cumulus/parachains/runtimes/assets/asset-hub-rococo/src/weights/pallet_asset_conversion.rs b/cumulus/parachains/runtimes/assets/asset-hub-rococo/src/weights/pallet_asset_conversion.rs index 0486932d1d6e44a7fe4a1c01640d6e3329577a2c..ec5a4084361f31b195b1acec747dd4e2fd34567a 100644 --- a/cumulus/parachains/runtimes/assets/asset-hub-rococo/src/weights/pallet_asset_conversion.rs +++ b/cumulus/parachains/runtimes/assets/asset-hub-rococo/src/weights/pallet_asset_conversion.rs @@ -154,4 +154,26 @@ impl pallet_asset_conversion::WeightInfo for WeightInfo .saturating_add(T::DbWeight::get().writes(4)) .saturating_add(Weight::from_parts(0, 393).saturating_mul(n.into())) } + /// Storage: `AssetConversion::Pools` (r:1 w:0) + /// Proof: `AssetConversion::Pools` (`max_values`: None, `max_size`: Some(30), added: 2505, mode: `MaxEncodedLen`) + /// Storage: `Assets::Asset` (r:2 w:2) + /// 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: `PoolAssets::Asset` (r:1 w:1) + /// Proof: `PoolAssets::Asset` (`max_values`: None, `max_size`: Some(210), added: 2685, mode: `MaxEncodedLen`) + /// Storage: `PoolAssets::Account` (r:1 w:1) + /// Proof: `PoolAssets::Account` (`max_values`: None, `max_size`: Some(134), added: 2609, mode: `MaxEncodedLen`) + /// The range of component `n` is `[0, 3]`. + fn touch(n: u32, ) -> Weight { + // Proof Size summary in bytes: + // Measured: `1571` + // Estimated: `6360` + // Minimum execution time: 381_000_000 picoseconds. + Weight::from_parts(398_540_909, 6360) + // Standard Error: 1_330_283 + .saturating_add(Weight::from_parts(209_463_636, 0).saturating_mul(n.into())) + .saturating_add(T::DbWeight::get().reads(7_u64)) + .saturating_add(T::DbWeight::get().writes((2_u64).saturating_mul(n.into()))) + } } diff --git a/cumulus/parachains/runtimes/assets/asset-hub-rococo/src/weights/pallet_asset_conversion_ops.rs b/cumulus/parachains/runtimes/assets/asset-hub-rococo/src/weights/pallet_asset_conversion_ops.rs new file mode 100644 index 0000000000000000000000000000000000000000..e85420d32d9c28b3cc781cab6e5ac92bedc8af13 --- /dev/null +++ b/cumulus/parachains/runtimes/assets/asset-hub-rococo/src/weights/pallet_asset_conversion_ops.rs @@ -0,0 +1,71 @@ +// 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_ops` +//! +//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 32.0.0 +//! DATE: 2024-02-15, STEPS: `10`, REPEAT: `2`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! WORST CASE MAP SIZE: `1000000` +//! HOSTNAME: `cob`, CPU: `` +//! WASM-EXECUTION: `Compiled`, CHAIN: `Some("asset-hub-rococo-dev")`, DB CACHE: 1024 + +// Executed Command: +// ./target/debug/polkadot-parachain +// benchmark +// pallet +// --chain=asset-hub-rococo-dev +// --steps=10 +// --repeat=2 +// --pallet=pallet-asset-conversion-ops +// --extrinsic=* +// --wasm-execution=compiled +// --heap-pages=4096 +// --output=./cumulus/parachains/runtimes/assets/asset-hub-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_asset_conversion_ops`. +pub struct WeightInfo(PhantomData); +impl pallet_asset_conversion_ops::WeightInfo for WeightInfo { + /// Storage: `AssetConversion::Pools` (r:1 w:0) + /// Proof: `AssetConversion::Pools` (`max_values`: None, `max_size`: Some(1224), added: 3699, mode: `MaxEncodedLen`) + /// Storage: `System::Account` (r:2 w:2) + /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) + /// Storage: `ForeignAssets::Account` (r:2 w:2) + /// Proof: `ForeignAssets::Account` (`max_values`: None, `max_size`: Some(732), added: 3207, mode: `MaxEncodedLen`) + /// Storage: `PoolAssets::Account` (r:2 w:2) + /// Proof: `PoolAssets::Account` (`max_values`: None, `max_size`: Some(134), added: 2609, mode: `MaxEncodedLen`) + /// Storage: `PoolAssets::Asset` (r:1 w:1) + /// Proof: `PoolAssets::Asset` (`max_values`: None, `max_size`: Some(210), added: 2685, mode: `MaxEncodedLen`) + /// Storage: `ForeignAssets::Asset` (r:1 w:1) + /// Proof: `ForeignAssets::Asset` (`max_values`: None, `max_size`: Some(808), added: 3283, mode: `MaxEncodedLen`) + fn migrate_to_new_account() -> Weight { + // Proof Size summary in bytes: + // Measured: `1105` + // Estimated: `7404` + // Minimum execution time: 2_323_000_000 picoseconds. + Weight::from_parts(2_404_000_000, 0) + .saturating_add(Weight::from_parts(0, 7404)) + .saturating_add(T::DbWeight::get().reads(9)) + .saturating_add(T::DbWeight::get().writes(8)) + } +} diff --git a/cumulus/parachains/runtimes/assets/asset-hub-rococo/src/weights/pallet_balances.rs b/cumulus/parachains/runtimes/assets/asset-hub-rococo/src/weights/pallet_balances.rs index 299a801ebd5964829271d6575a60a123f156b7e3..35d7e1985c515879e210ab4ee6cd56c276fbbac2 100644 --- a/cumulus/parachains/runtimes/assets/asset-hub-rococo/src/weights/pallet_balances.rs +++ b/cumulus/parachains/runtimes/assets/asset-hub-rococo/src/weights/pallet_balances.rs @@ -17,9 +17,9 @@ //! 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-05-06, 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-unxyhko3-project-674-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` //! WASM-EXECUTION: `Compiled`, CHAIN: `Some("asset-hub-rococo-dev")`, DB CACHE: 1024 // Executed Command: @@ -54,8 +54,8 @@ impl pallet_balances::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `0` // Estimated: `3593` - // Minimum execution time: 42_706_000 picoseconds. - Weight::from_parts(43_378_000, 0) + // Minimum execution time: 43_472_000 picoseconds. + Weight::from_parts(44_389_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 +66,8 @@ impl pallet_balances::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `0` // Estimated: `3593` - // Minimum execution time: 33_090_000 picoseconds. - Weight::from_parts(33_703_000, 0) + // Minimum execution time: 34_211_000 picoseconds. + Weight::from_parts(35_075_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 +78,8 @@ impl pallet_balances::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `103` // Estimated: `3593` - // Minimum execution time: 12_678_000 picoseconds. - Weight::from_parts(13_068_000, 0) + // Minimum execution time: 12_751_000 picoseconds. + Weight::from_parts(13_221_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 +90,8 @@ impl pallet_balances::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `103` // Estimated: `3593` - // Minimum execution time: 17_336_000 picoseconds. - Weight::from_parts(17_824_000, 0) + // Minimum execution time: 17_530_000 picoseconds. + Weight::from_parts(17_979_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 +102,8 @@ impl pallet_balances::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `103` // Estimated: `6196` - // Minimum execution time: 44_817_000 picoseconds. - Weight::from_parts(45_453_000, 0) + // Minimum execution time: 45_913_000 picoseconds. + Weight::from_parts(47_447_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 +114,8 @@ impl pallet_balances::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `0` // Estimated: `3593` - // Minimum execution time: 41_468_000 picoseconds. - Weight::from_parts(42_093_000, 0) + // Minimum execution time: 42_435_000 picoseconds. + Weight::from_parts(44_712_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 +126,8 @@ impl pallet_balances::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `103` // Estimated: `3593` - // Minimum execution time: 15_344_000 picoseconds. - Weight::from_parts(15_878_000, 0) + // Minimum execution time: 15_407_000 picoseconds. + Weight::from_parts(16_104_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 +139,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: 15_067_000 picoseconds. - Weight::from_parts(15_281_000, 0) + // Minimum execution time: 15_494_000 picoseconds. + Weight::from_parts(15_793_000, 0) .saturating_add(Weight::from_parts(0, 990)) - // Standard Error: 11_009 - .saturating_add(Weight::from_parts(13_050_024, 0).saturating_mul(u.into())) + // Standard Error: 11_778 + .saturating_add(Weight::from_parts(13_198_951, 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,9 +154,25 @@ impl pallet_balances::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `0` // Estimated: `1501` - // Minimum execution time: 5_139_000 picoseconds. - Weight::from_parts(5_511_000, 0) + // Minimum execution time: 5_368_000 picoseconds. + Weight::from_parts(5_674_000, 0) .saturating_add(Weight::from_parts(0, 1501)) .saturating_add(T::DbWeight::get().reads(1)) } + fn burn_allow_death() -> Weight { + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 27_491_000 picoseconds. + Weight::from_parts(28_444_000, 0) + .saturating_add(Weight::from_parts(0, 0)) + } + fn burn_keep_alive() -> Weight { + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 18_290_000 picoseconds. + Weight::from_parts(19_227_000, 0) + .saturating_add(Weight::from_parts(0, 0)) + } } 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 e0e231d7da279022293d42aa5e3b3fc1b8ad12d5..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 @@ -17,9 +17,9 @@ //! Autogenerated weights for `pallet_xcm` //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 32.0.0 -//! DATE: 2024-03-21, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! DATE: 2024-02-20, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` //! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `runner-h2rr8wx7-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,30 +64,8 @@ impl pallet_xcm::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `145` // Estimated: `3610` - // Minimum execution time: 21_224_000 picoseconds. - Weight::from_parts(21_821_000, 0) - .saturating_add(Weight::from_parts(0, 3610)) - .saturating_add(T::DbWeight::get().reads(6)) - .saturating_add(T::DbWeight::get().writes(2)) - } - /// Storage: `ParachainSystem::UpwardDeliveryFeeFactor` (r:1 w:0) - /// Proof: `ParachainSystem::UpwardDeliveryFeeFactor` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - /// Storage: `PolkadotXcm::SupportedVersion` (r:1 w:0) - /// Proof: `PolkadotXcm::SupportedVersion` (`max_values`: None, `max_size`: None, mode: `Measured`) - /// Storage: `PolkadotXcm::VersionDiscoveryQueue` (r:1 w:1) - /// Proof: `PolkadotXcm::VersionDiscoveryQueue` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - /// Storage: `PolkadotXcm::SafeXcmVersion` (r:1 w:0) - /// Proof: `PolkadotXcm::SafeXcmVersion` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - /// Storage: `ParachainSystem::HostConfiguration` (r:1 w:0) - /// Proof: `ParachainSystem::HostConfiguration` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - /// Storage: `ParachainSystem::PendingUpwardMessages` (r:1 w:1) - /// Proof: `ParachainSystem::PendingUpwardMessages` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - fn send_blob() -> Weight { - // Proof Size summary in bytes: - // Measured: `145` - // Estimated: `3610` - // Minimum execution time: 21_474_000 picoseconds. - Weight::from_parts(22_072_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)) @@ -112,8 +90,8 @@ impl pallet_xcm::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `145` // Estimated: `3610` - // Minimum execution time: 90_677_000 picoseconds. - Weight::from_parts(93_658_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)) @@ -140,8 +118,8 @@ impl pallet_xcm::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `400` // Estimated: `6196` - // Minimum execution time: 116_767_000 picoseconds. - Weight::from_parts(118_843_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)) @@ -170,8 +148,8 @@ impl pallet_xcm::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `496` // Estimated: `6208` - // Minimum execution time: 137_983_000 picoseconds. - Weight::from_parts(141_396_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)) @@ -186,24 +164,14 @@ 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 execute_blob() -> 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: `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: 6_232_000 picoseconds. - Weight::from_parts(6_507_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)) } @@ -213,8 +181,8 @@ impl pallet_xcm::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_884_000 picoseconds. - Weight::from_parts(2_016_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)) } @@ -240,8 +208,8 @@ impl pallet_xcm::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `145` // Estimated: `3610` - // Minimum execution time: 26_637_000 picoseconds. - Weight::from_parts(27_616_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)) @@ -266,8 +234,8 @@ impl pallet_xcm::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `363` // Estimated: `3828` - // Minimum execution time: 28_668_000 picoseconds. - Weight::from_parts(29_413_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)) @@ -278,8 +246,8 @@ 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_114_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)) } @@ -289,8 +257,8 @@ impl pallet_xcm::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `159` // Estimated: `13524` - // Minimum execution time: 18_856_000 picoseconds. - Weight::from_parts(19_430_000, 0) + // 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)) @@ -301,8 +269,8 @@ impl pallet_xcm::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `163` // Estimated: `13528` - // Minimum execution time: 19_068_000 picoseconds. - Weight::from_parts(19_434_000, 0) + // 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)) @@ -313,8 +281,8 @@ impl pallet_xcm::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `173` // Estimated: `16013` - // Minimum execution time: 21_055_000 picoseconds. - Weight::from_parts(21_379_000, 0) + // 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)) } @@ -336,8 +304,8 @@ impl pallet_xcm::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `212` // Estimated: `6152` - // Minimum execution time: 25_736_000 picoseconds. - Weight::from_parts(26_423_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)) @@ -348,8 +316,8 @@ impl pallet_xcm::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `206` // Estimated: `11096` - // Minimum execution time: 11_853_000 picoseconds. - Weight::from_parts(12_215_000, 0) + // 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)) } @@ -359,8 +327,8 @@ impl pallet_xcm::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `170` // Estimated: `13535` - // Minimum execution time: 19_418_000 picoseconds. - Weight::from_parts(19_794_000, 0) + // 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)) @@ -383,8 +351,8 @@ impl pallet_xcm::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `212` // Estimated: `13577` - // Minimum execution time: 34_719_000 picoseconds. - Weight::from_parts(35_260_000, 0) + // 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)) @@ -397,8 +365,8 @@ impl pallet_xcm::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `103` // Estimated: `1588` - // Minimum execution time: 4_937_000 picoseconds. - Weight::from_parts(5_203_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)) @@ -409,8 +377,8 @@ impl pallet_xcm::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `7740` // Estimated: `11205` - // Minimum execution time: 26_064_000 picoseconds. - Weight::from_parts(26_497_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)) @@ -421,8 +389,8 @@ impl pallet_xcm::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `160` // Estimated: `3625` - // Minimum execution time: 37_132_000 picoseconds. - Weight::from_parts(37_868_000, 0) + // 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 fceb82b6b06b1ee60a439003534f2120f7333398..664d2b9c9dd593536404f02d895a414e6c232bfa 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,19 @@ use testnet_parachains_constants::rococo::snowbridge::{ }; use xcm::latest::prelude::*; use xcm_builder::{ - AccountId32Aliases, AllowExplicitUnpaidExecutionFrom, AllowKnownQueryResponses, - AllowSubscriptionsFrom, AllowTopLevelPaidExecutionFrom, DenyReserveTransferToRelayChain, - DenyThenTry, DescribeAllTerminal, DescribeFamily, EnsureXcmOrigin, FrameTransactionalProcessor, - 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, + AccountId32Aliases, AllowExplicitUnpaidExecutionFrom, AllowHrmpNotificationsFromRelayChain, + AllowKnownQueryResponses, AllowSubscriptionsFrom, AllowTopLevelPaidExecutionFrom, + DenyReserveTransferToRelayChain, DenyThenTry, DescribeAllTerminal, DescribeFamily, + EnsureXcmOrigin, FrameTransactionalProcessor, 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}; +use xcm_executor::XcmExecutor; parameter_types! { pub const TokenLocation: Location = Location::parent(); @@ -263,223 +263,6 @@ impl Contains for ParentOrParentsPlurality { } } -/// A call filter for the XCM Transact instruction. This is a temporary measure until we properly -/// account for proof size weights. -/// -/// Calls that are allowed through this filter must: -/// 1. Have a fixed weight; -/// 2. Cannot lead to another call being made; -/// 3. Have a defined proof size weight, e.g. no unbounded vecs in call parameters. -pub struct SafeCallFilter; -impl Contains for SafeCallFilter { - fn contains(call: &RuntimeCall) -> bool { - #[cfg(feature = "runtime-benchmarks")] - { - if matches!(call, RuntimeCall::System(frame_system::Call::remark_with_event { .. })) { - return true - } - } - - // Allow to change dedicated storage items (called by governance-like) - match call { - RuntimeCall::System(frame_system::Call::set_storage { items }) - if items.iter().all(|(k, _)| { - k.eq(&bridging::XcmBridgeHubRouterByteFee::key()) || - k.eq(&bridging::XcmBridgeHubRouterBaseFee::key()) || - k.eq(&bridging::to_ethereum::BridgeHubEthereumBaseFee::key()) - }) => - return true, - _ => (), - }; - - matches!( - call, - RuntimeCall::PolkadotXcm( - pallet_xcm::Call::force_xcm_version { .. } | - 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 { .. }, - ) | RuntimeCall::ParachainSystem(..) | - RuntimeCall::Timestamp(..) | - RuntimeCall::Balances(..) | - RuntimeCall::CollatorSelection(..) | - RuntimeCall::Session(pallet_session::Call::purge_keys { .. }) | - RuntimeCall::XcmpQueue(..) | - RuntimeCall::MessageQueue(..) | - RuntimeCall::Assets( - pallet_assets::Call::create { .. } | - pallet_assets::Call::force_create { .. } | - pallet_assets::Call::start_destroy { .. } | - pallet_assets::Call::destroy_accounts { .. } | - pallet_assets::Call::destroy_approvals { .. } | - pallet_assets::Call::finish_destroy { .. } | - pallet_assets::Call::block { .. } | - pallet_assets::Call::mint { .. } | - pallet_assets::Call::burn { .. } | - pallet_assets::Call::transfer { .. } | - pallet_assets::Call::transfer_keep_alive { .. } | - pallet_assets::Call::force_transfer { .. } | - pallet_assets::Call::freeze { .. } | - pallet_assets::Call::thaw { .. } | - pallet_assets::Call::freeze_asset { .. } | - pallet_assets::Call::thaw_asset { .. } | - pallet_assets::Call::transfer_ownership { .. } | - pallet_assets::Call::set_team { .. } | - pallet_assets::Call::set_metadata { .. } | - pallet_assets::Call::clear_metadata { .. } | - pallet_assets::Call::force_set_metadata { .. } | - pallet_assets::Call::force_clear_metadata { .. } | - pallet_assets::Call::force_asset_status { .. } | - pallet_assets::Call::approve_transfer { .. } | - pallet_assets::Call::cancel_approval { .. } | - pallet_assets::Call::force_cancel_approval { .. } | - pallet_assets::Call::transfer_approved { .. } | - pallet_assets::Call::touch { .. } | - pallet_assets::Call::touch_other { .. } | - pallet_assets::Call::refund { .. } | - pallet_assets::Call::refund_other { .. }, - ) | RuntimeCall::ForeignAssets( - pallet_assets::Call::create { .. } | - pallet_assets::Call::force_create { .. } | - pallet_assets::Call::start_destroy { .. } | - pallet_assets::Call::destroy_accounts { .. } | - pallet_assets::Call::destroy_approvals { .. } | - pallet_assets::Call::finish_destroy { .. } | - pallet_assets::Call::block { .. } | - pallet_assets::Call::mint { .. } | - pallet_assets::Call::burn { .. } | - pallet_assets::Call::transfer { .. } | - pallet_assets::Call::transfer_keep_alive { .. } | - pallet_assets::Call::force_transfer { .. } | - pallet_assets::Call::freeze { .. } | - pallet_assets::Call::thaw { .. } | - pallet_assets::Call::freeze_asset { .. } | - pallet_assets::Call::thaw_asset { .. } | - pallet_assets::Call::transfer_ownership { .. } | - pallet_assets::Call::set_team { .. } | - pallet_assets::Call::set_metadata { .. } | - pallet_assets::Call::clear_metadata { .. } | - pallet_assets::Call::force_set_metadata { .. } | - pallet_assets::Call::force_clear_metadata { .. } | - pallet_assets::Call::force_asset_status { .. } | - pallet_assets::Call::approve_transfer { .. } | - pallet_assets::Call::cancel_approval { .. } | - pallet_assets::Call::force_cancel_approval { .. } | - pallet_assets::Call::transfer_approved { .. } | - pallet_assets::Call::touch { .. } | - pallet_assets::Call::touch_other { .. } | - pallet_assets::Call::refund { .. } | - pallet_assets::Call::refund_other { .. }, - ) | RuntimeCall::PoolAssets( - pallet_assets::Call::force_create { .. } | - pallet_assets::Call::block { .. } | - pallet_assets::Call::burn { .. } | - pallet_assets::Call::transfer { .. } | - pallet_assets::Call::transfer_keep_alive { .. } | - pallet_assets::Call::force_transfer { .. } | - pallet_assets::Call::freeze { .. } | - pallet_assets::Call::thaw { .. } | - pallet_assets::Call::freeze_asset { .. } | - pallet_assets::Call::thaw_asset { .. } | - pallet_assets::Call::transfer_ownership { .. } | - pallet_assets::Call::set_team { .. } | - pallet_assets::Call::set_metadata { .. } | - pallet_assets::Call::clear_metadata { .. } | - pallet_assets::Call::force_set_metadata { .. } | - pallet_assets::Call::force_clear_metadata { .. } | - pallet_assets::Call::force_asset_status { .. } | - pallet_assets::Call::approve_transfer { .. } | - pallet_assets::Call::cancel_approval { .. } | - pallet_assets::Call::force_cancel_approval { .. } | - pallet_assets::Call::transfer_approved { .. } | - pallet_assets::Call::touch { .. } | - pallet_assets::Call::touch_other { .. } | - pallet_assets::Call::refund { .. } | - pallet_assets::Call::refund_other { .. }, - ) | RuntimeCall::AssetConversion( - pallet_asset_conversion::Call::create_pool { .. } | - pallet_asset_conversion::Call::add_liquidity { .. } | - pallet_asset_conversion::Call::remove_liquidity { .. } | - pallet_asset_conversion::Call::swap_tokens_for_exact_tokens { .. } | - pallet_asset_conversion::Call::swap_exact_tokens_for_tokens { .. }, - ) | RuntimeCall::NftFractionalization( - pallet_nft_fractionalization::Call::fractionalize { .. } | - pallet_nft_fractionalization::Call::unify { .. }, - ) | RuntimeCall::Nfts( - pallet_nfts::Call::create { .. } | - pallet_nfts::Call::force_create { .. } | - pallet_nfts::Call::destroy { .. } | - pallet_nfts::Call::mint { .. } | - pallet_nfts::Call::force_mint { .. } | - pallet_nfts::Call::burn { .. } | - pallet_nfts::Call::transfer { .. } | - pallet_nfts::Call::lock_item_transfer { .. } | - pallet_nfts::Call::unlock_item_transfer { .. } | - pallet_nfts::Call::lock_collection { .. } | - pallet_nfts::Call::transfer_ownership { .. } | - pallet_nfts::Call::set_team { .. } | - pallet_nfts::Call::force_collection_owner { .. } | - pallet_nfts::Call::force_collection_config { .. } | - pallet_nfts::Call::approve_transfer { .. } | - pallet_nfts::Call::cancel_approval { .. } | - pallet_nfts::Call::clear_all_transfer_approvals { .. } | - pallet_nfts::Call::lock_item_properties { .. } | - pallet_nfts::Call::set_attribute { .. } | - pallet_nfts::Call::force_set_attribute { .. } | - pallet_nfts::Call::clear_attribute { .. } | - pallet_nfts::Call::approve_item_attributes { .. } | - pallet_nfts::Call::cancel_item_attributes_approval { .. } | - pallet_nfts::Call::set_metadata { .. } | - pallet_nfts::Call::clear_metadata { .. } | - pallet_nfts::Call::set_collection_metadata { .. } | - pallet_nfts::Call::clear_collection_metadata { .. } | - pallet_nfts::Call::set_accept_ownership { .. } | - pallet_nfts::Call::set_collection_max_supply { .. } | - pallet_nfts::Call::update_mint_settings { .. } | - pallet_nfts::Call::set_price { .. } | - pallet_nfts::Call::buy_item { .. } | - pallet_nfts::Call::pay_tips { .. } | - pallet_nfts::Call::create_swap { .. } | - pallet_nfts::Call::cancel_swap { .. } | - pallet_nfts::Call::claim_swap { .. }, - ) | RuntimeCall::Uniques( - pallet_uniques::Call::create { .. } | - pallet_uniques::Call::force_create { .. } | - pallet_uniques::Call::destroy { .. } | - pallet_uniques::Call::mint { .. } | - pallet_uniques::Call::burn { .. } | - pallet_uniques::Call::transfer { .. } | - pallet_uniques::Call::freeze { .. } | - pallet_uniques::Call::thaw { .. } | - pallet_uniques::Call::freeze_collection { .. } | - pallet_uniques::Call::thaw_collection { .. } | - pallet_uniques::Call::transfer_ownership { .. } | - pallet_uniques::Call::set_team { .. } | - pallet_uniques::Call::approve_transfer { .. } | - pallet_uniques::Call::cancel_approval { .. } | - pallet_uniques::Call::force_item_status { .. } | - pallet_uniques::Call::set_attribute { .. } | - pallet_uniques::Call::clear_attribute { .. } | - pallet_uniques::Call::set_metadata { .. } | - pallet_uniques::Call::clear_metadata { .. } | - pallet_uniques::Call::set_collection_metadata { .. } | - pallet_uniques::Call::clear_collection_metadata { .. } | - pallet_uniques::Call::set_accept_ownership { .. } | - pallet_uniques::Call::set_collection_max_supply { .. } | - pallet_uniques::Call::set_price { .. } | - pallet_uniques::Call::buy_item { .. } - ) | RuntimeCall::ToWestendXcmRouter( - pallet_xcm_bridge_hub_router::Call::report_bridge_status { .. } - ) - ) - } -} - pub type Barrier = TrailingSetTopicAsId< DenyThenTry< DenyReserveTransferToRelayChain, @@ -502,6 +285,8 @@ pub type Barrier = TrailingSetTopicAsId< )>, // Subscriptions for version tracking are OK. AllowSubscriptionsFrom, + // HRMP notifications from the relay chain are OK. + AllowHrmpNotificationsFromRelayChain, ), UniversalLocation, ConstU32<8>, @@ -632,13 +417,14 @@ impl xcm_executor::Config for XcmConfig { type MessageExporter = (); type UniversalAliases = (bridging::to_westend::UniversalAliases, bridging::to_ethereum::UniversalAliases); - type CallDispatcher = WithOriginFilter; - type SafeCallFilter = SafeCallFilter; + type CallDispatcher = RuntimeCall; + type SafeCallFilter = Everything; type Aliasers = Nothing; type TransactionalProcessor = FrameTransactionalProcessor; type HrmpNewChannelOpenRequestHandler = (); type HrmpChannelAcceptedHandler = (); type HrmpChannelClosingHandler = (); + type XcmRecorder = PolkadotXcm; } /// Converts a local signed origin into an XCM location. diff --git a/cumulus/parachains/runtimes/assets/asset-hub-westend/Cargo.toml b/cumulus/parachains/runtimes/assets/asset-hub-westend/Cargo.toml index e25554ec0a5f1af99b86bce2c3c1f60f256aa53c..3d27f52d0d5c3a1849c84f433de267c400b92dd1 100644 --- a/cumulus/parachains/runtimes/assets/asset-hub-westend/Cargo.toml +++ b/cumulus/parachains/runtimes/assets/asset-hub-westend/Cargo.toml @@ -10,8 +10,8 @@ license = "Apache-2.0" 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 } +codec = { package = "parity-scale-codec", version = "3.6.12", default-features = false, features = ["derive", "max-encoded-len"] } +hex-literal = { version = "0.4.1" } log = { workspace = true } scale-info = { version = "2.11.1", default-features = false, features = ["derive"] } @@ -23,6 +23,7 @@ frame-system = { path = "../../../../../substrate/frame/system", default-feature 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 } +pallet-asset-conversion-ops = { path = "../../../../../substrate/frame/asset-conversion/ops", default-features = false } pallet-asset-conversion-tx-payment = { path = "../../../../../substrate/frame/transaction-payment/asset-conversion-tx-payment", default-features = false } pallet-assets = { path = "../../../../../substrate/frame/assets", default-features = false } pallet-asset-conversion = { path = "../../../../../substrate/frame/asset-conversion", default-features = false } @@ -35,6 +36,7 @@ pallet-nfts = { path = "../../../../../substrate/frame/nfts", default-features = pallet-nfts-runtime-api = { path = "../../../../../substrate/frame/nfts/runtime-api", default-features = false } pallet-proxy = { path = "../../../../../substrate/frame/proxy", default-features = false } pallet-session = { path = "../../../../../substrate/frame/session", default-features = false } +pallet-state-trie-migration = { path = "../../../../../substrate/frame/state-trie-migration", 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 } @@ -65,6 +67,7 @@ westend-runtime-constants = { path = "../../../../../polkadot/runtime/westend/co xcm = { package = "staging-xcm", path = "../../../../../polkadot/xcm", default-features = false } xcm-builder = { package = "staging-xcm-builder", path = "../../../../../polkadot/xcm/xcm-builder", default-features = false } xcm-executor = { package = "staging-xcm-executor", path = "../../../../../polkadot/xcm/xcm-executor", default-features = false } +xcm-fee-payment-runtime-api = { path = "../../../../../polkadot/xcm/xcm-fee-payment-runtime-api", default-features = false } # Cumulus cumulus-pallet-aura-ext = { path = "../../../../pallets/aura-ext", default-features = false } @@ -91,7 +94,6 @@ bp-bridge-hub-rococo = { path = "../../../../../bridges/chains/chain-bridge-hub- bp-bridge-hub-westend = { path = "../../../../../bridges/chains/chain-bridge-hub-westend", default-features = false } [dev-dependencies] -hex-literal = "0.4.1" asset-test-utils = { path = "../test-utils" } [build-dependencies] @@ -110,7 +112,7 @@ runtime-benchmarks = [ "frame-support/runtime-benchmarks", "frame-system-benchmarking/runtime-benchmarks", "frame-system/runtime-benchmarks", - "hex-literal", + "pallet-asset-conversion-ops/runtime-benchmarks", "pallet-asset-conversion/runtime-benchmarks", "pallet-assets/runtime-benchmarks", "pallet-balances/runtime-benchmarks", @@ -120,6 +122,7 @@ runtime-benchmarks = [ "pallet-nft-fractionalization/runtime-benchmarks", "pallet-nfts/runtime-benchmarks", "pallet-proxy/runtime-benchmarks", + "pallet-state-trie-migration/runtime-benchmarks", "pallet-timestamp/runtime-benchmarks", "pallet-uniques/runtime-benchmarks", "pallet-utility/runtime-benchmarks", @@ -132,6 +135,7 @@ runtime-benchmarks = [ "sp-runtime/runtime-benchmarks", "xcm-builder/runtime-benchmarks", "xcm-executor/runtime-benchmarks", + "xcm-fee-payment-runtime-api/runtime-benchmarks", ] try-runtime = [ "cumulus-pallet-aura-ext/try-runtime", @@ -142,6 +146,7 @@ try-runtime = [ "frame-support/try-runtime", "frame-system/try-runtime", "frame-try-runtime/try-runtime", + "pallet-asset-conversion-ops/try-runtime", "pallet-asset-conversion-tx-payment/try-runtime", "pallet-asset-conversion/try-runtime", "pallet-assets/try-runtime", @@ -155,6 +160,7 @@ try-runtime = [ "pallet-nfts/try-runtime", "pallet-proxy/try-runtime", "pallet-session/try-runtime", + "pallet-state-trie-migration/try-runtime", "pallet-timestamp/try-runtime", "pallet-transaction-payment/try-runtime", "pallet-uniques/try-runtime", @@ -189,6 +195,7 @@ std = [ "frame-system/std", "frame-try-runtime?/std", "log/std", + "pallet-asset-conversion-ops/std", "pallet-asset-conversion-tx-payment/std", "pallet-asset-conversion/std", "pallet-assets/std", @@ -203,6 +210,7 @@ std = [ "pallet-nfts/std", "pallet-proxy/std", "pallet-session/std", + "pallet-state-trie-migration/std", "pallet-timestamp/std", "pallet-transaction-payment-rpc-runtime-api/std", "pallet-transaction-payment/std", @@ -235,6 +243,7 @@ std = [ "westend-runtime-constants/std", "xcm-builder/std", "xcm-executor/std", + "xcm-fee-payment-runtime-api/std", "xcm/std", ] diff --git a/cumulus/parachains/runtimes/assets/asset-hub-westend/build.rs b/cumulus/parachains/runtimes/assets/asset-hub-westend/build.rs index 60f8a125129ff1344a1799246e931acdb1d139d5..239ccac19ec7778039fb1ee56f4e772b3ddd3711 100644 --- a/cumulus/parachains/runtimes/assets/asset-hub-westend/build.rs +++ b/cumulus/parachains/runtimes/assets/asset-hub-westend/build.rs @@ -15,11 +15,7 @@ #[cfg(feature = "std")] fn main() { - substrate_wasm_builder::WasmBuilder::new() - .with_current_project() - .export_heap_base() - .import_memory() - .build() + substrate_wasm_builder::WasmBuilder::build_using_defaults(); } #[cfg(not(feature = "std"))] 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 cb2f11637187dceabd05d592ffff5b24b2c0eb6e..062babef18d366a52e946ca9ff36c5737d4e34d3 100644 --- a/cumulus/parachains/runtimes/assets/asset-hub-westend/src/lib.rs +++ b/cumulus/parachains/runtimes/assets/asset-hub-westend/src/lib.rs @@ -45,7 +45,7 @@ use frame_support::{ AsEnsureOriginWithArg, ConstBool, ConstU128, ConstU32, ConstU64, ConstU8, Equals, InstanceFilter, TransformOrigin, }, - weights::{ConstantMultiplier, Weight}, + weights::{ConstantMultiplier, Weight, WeightToFee as _}, BoundedVec, PalletId, }; use frame_system::{ @@ -74,9 +74,10 @@ use sp_version::NativeVersion; use sp_version::RuntimeVersion; use testnet_parachains_constants::westend::{consensus::*, currency::*, fee::WeightToFee, time::*}; use xcm_config::{ - ForeignAssetsConvertedConcreteId, PoolAssetsConvertedConcreteId, - TrustBackedAssetsConvertedConcreteId, TrustBackedAssetsPalletLocationV3, WestendLocation, - WestendLocationV3, XcmOriginToTransactDispatchOrigin, + ForeignAssetsConvertedConcreteId, ForeignCreatorsSovereignAccountOf, + PoolAssetsConvertedConcreteId, TrustBackedAssetsConvertedConcreteId, + TrustBackedAssetsPalletLocationV3, WestendLocation, WestendLocationV3, + XcmOriginToTransactDispatchOrigin, }; #[cfg(any(feature = "std", test))] @@ -84,6 +85,11 @@ pub use sp_runtime::BuildStorage; use assets_common::{foreign_creators::ForeignCreators, matching::FromSiblingParachain}; use polkadot_runtime_common::{BlockHashCount, SlowAdjustingFeeUpdate}; +use xcm::{ + prelude::{VersionedAssetId, VersionedAssets, VersionedLocation, VersionedXcm}, + IntoVersion, +}; + // We exclude `Assets` since it's the name of a pallet use xcm::latest::prelude::AssetId; @@ -93,7 +99,11 @@ use xcm::latest::prelude::{ NonFungible, Parent, ParentThen, Response, XCM_VERSION, }; -use crate::xcm_config::ForeignCreatorsSovereignAccountOf; +use xcm_fee_payment_runtime_api::{ + dry_run::{Error as XcmDryRunApiError, ExtrinsicDryRunEffects, XcmDryRunEffects}, + fees::Error as XcmPaymentApiError, +}; + use weights::{BlockExecutionWeight, ExtrinsicBaseWeight, RocksDbWeight}; impl_opaque_keys! { @@ -110,11 +120,11 @@ pub const VERSION: RuntimeVersion = RuntimeVersion { spec_name: create_runtime_str!("westmint"), impl_name: create_runtime_str!("westmint"), authoring_version: 1, - spec_version: 1_010_000, + spec_version: 1_011_000, impl_version: 0, apis: RUNTIME_API_VERSIONS, - transaction_version: 14, - state_version: 0, + transaction_version: 15, + state_version: 1, }; /// The version information used to identify this runtime when compiled natively. @@ -315,6 +325,11 @@ pub type NativeAndAssets = fungible::UnionOf< AccountId, >; +pub type PoolIdToAccountId = pallet_asset_conversion::AccountIdConverter< + AssetConversionPalletId, + (xcm::v3::Location, xcm::v3::Location), +>; + impl pallet_asset_conversion::Config for Runtime { type RuntimeEvent = RuntimeEvent; type Balance = Balance; @@ -322,8 +337,12 @@ impl pallet_asset_conversion::Config for Runtime { type AssetKind = xcm::v3::Location; type Assets = NativeAndAssets; type PoolId = (Self::AssetKind, Self::AssetKind); - type PoolLocator = - pallet_asset_conversion::WithFirstAsset; + type PoolLocator = pallet_asset_conversion::WithFirstAsset< + WestendLocationV3, + AccountId, + Self::AssetKind, + PoolIdToAccountId, + >; type PoolAssetId = u32; type PoolAssets = PoolAssets; type PoolSetupFee = ConstU128<0>; // Asset class deposit fees are sufficient to prevent spam @@ -344,6 +363,18 @@ impl pallet_asset_conversion::Config for Runtime { >; } +impl pallet_asset_conversion_ops::Config for Runtime { + type RuntimeEvent = RuntimeEvent; + type PriorAccountIdConverter = pallet_asset_conversion::AccountIdConverterNoSeed< + ::PoolId, + >; + type AssetsRefund = ::Assets; + type PoolAssetsRefund = ::PoolAssets; + type PoolAssetsTeam = ::PoolAssets; + type DepositAsset = Balances; + type WeightInfo = weights::pallet_asset_conversion_ops::WeightInfo; +} + parameter_types! { // we just reuse the same deposits pub const ForeignAssetsAssetDeposit: Balance = AssetDeposit::get(); @@ -638,7 +669,7 @@ impl pallet_message_queue::Config for Runtime { // The XCMP queue pallet is only ever able to handle the `Sibling(ParaId)` origin: type QueueChangeHandler = NarrowOriginToSibling; type QueuePausedQuery = NarrowOriginToSibling; - type HeapSize = sp_core::ConstU32<{ 64 * 1024 }>; + type HeapSize = sp_core::ConstU32<{ 103 * 1024 }>; type MaxStale = sp_core::ConstU32<8>; type ServiceWeight = MessageQueueServiceWeight; type IdleMaxServiceWeight = MessageQueueServiceWeight; @@ -666,13 +697,22 @@ impl cumulus_pallet_xcmp_queue::Config for Runtime { type VersionWrapper = PolkadotXcm; // Enqueue XCMP messages from siblings for later processing. type XcmpQueue = TransformOrigin; - type MaxInboundSuspended = sp_core::ConstU32<1_000>; + type MaxInboundSuspended = ConstU32<1_000>; + type MaxActiveOutboundChannels = ConstU32<128>; + // Most on-chain HRMP channels are configured to use 102400 bytes of max message size, so we + // need to set the page size larger than that until we reduce the channel size on-chain. + type MaxPageSize = ConstU32<{ 103 * 1024 }>; type ControllerOrigin = EnsureRoot; type ControllerOriginConverter = XcmOriginToTransactDispatchOrigin; type WeightInfo = weights::cumulus_pallet_xcmp_queue::WeightInfo; type PriceForSiblingDelivery = PriceForSiblingParachainDelivery; } +impl cumulus_pallet_xcmp_queue::migration::v5::V5Config for Runtime { + // This must be the same as the `ChannelInfo` from the `Config`: + type ChannelList = ParachainSystem; +} + parameter_types! { pub const RelayOrigin: AggregateMessageOrigin = AggregateMessageOrigin::Parent; } @@ -906,6 +946,12 @@ construct_runtime!( NftFractionalization: pallet_nft_fractionalization = 54, PoolAssets: pallet_assets:: = 55, AssetConversion: pallet_asset_conversion = 56, + + StateTrieMigration: pallet_state_trie_migration = 70, + + // TODO: the pallet instance should be removed once all pools have migrated + // to the new account IDs. + AssetConversionMigration: pallet_asset_conversion_ops = 200, } ); @@ -938,7 +984,7 @@ pub type Migrations = ( // v9420 pallet_nfts::migration::v1::MigrateToV1, // unreleased - pallet_collator_selection::migration::v1::MigrateToV1, + pallet_collator_selection::migration::v2::MigrationToV2, // unreleased pallet_multisig::migrations::v1::MigrateToV1, // unreleased @@ -947,6 +993,7 @@ pub type Migrations = ( DeleteUndecodableStorage, // unreleased cumulus_pallet_xcmp_queue::migration::v4::MigrationToV4, + cumulus_pallet_xcmp_queue::migration::v5::MigrateV4ToV5, // permanent pallet_xcm::migration::MigrateToLatestXcmVersion, ); @@ -1085,6 +1132,7 @@ mod benches { [cumulus_pallet_parachain_system, ParachainSystem] [cumulus_pallet_xcmp_queue, XcmpQueue] [pallet_xcm_bridge_hub_router, ToRococo] + [pallet_asset_conversion_ops, AssetConversionMigration] // XCM [pallet_xcm, PalletXcmExtrinsicsBenchmark::] // NOTE: Make sure you point to the individual modules below. @@ -1280,6 +1328,109 @@ impl_runtime_apis! { } } + impl xcm_fee_payment_runtime_api::fees::XcmPaymentApi for Runtime { + fn query_acceptable_payment_assets(xcm_version: xcm::Version) -> Result, XcmPaymentApiError> { + let acceptable = vec![ + // native token + VersionedAssetId::from(AssetId(xcm_config::WestendLocation::get())) + ]; + + Ok(acceptable + .into_iter() + .filter_map(|asset| asset.into_version(xcm_version).ok()) + .collect()) + } + + fn query_weight_to_asset_fee(weight: Weight, asset: VersionedAssetId) -> Result { + match asset.try_as::() { + Ok(asset_id) if asset_id.0 == xcm_config::WestendLocation::get() => { + // for native token + Ok(WeightToFee::weight_to_fee(&weight)) + }, + Ok(asset_id) => { + log::trace!(target: "xcm::xcm_fee_payment_runtime_api", "query_weight_to_asset_fee - unhandled asset_id: {asset_id:?}!"); + Err(XcmPaymentApiError::AssetNotFound) + }, + Err(_) => { + log::trace!(target: "xcm::xcm_fee_payment_runtime_api", "query_weight_to_asset_fee - failed to convert asset: {asset:?}!"); + Err(XcmPaymentApiError::VersionedConversionFailed) + } + } + } + + fn query_xcm_weight(message: VersionedXcm<()>) -> Result { + PolkadotXcm::query_xcm_weight(message) + } + + fn query_delivery_fees(destination: VersionedLocation, message: VersionedXcm<()>) -> Result { + PolkadotXcm::query_delivery_fees(destination, message) + } + } + + impl xcm_fee_payment_runtime_api::dry_run::XcmDryRunApi for Runtime { + fn dry_run_extrinsic(extrinsic: ::Extrinsic) -> Result, XcmDryRunApiError> { + use xcm_builder::InspectMessageQueues; + use xcm_executor::RecordXcm; + use xcm::prelude::*; + + pallet_xcm::Pallet::::set_record_xcm(true); + let result = Executive::apply_extrinsic(extrinsic).map_err(|error| { + log::error!( + target: "xcm::XcmDryRunApi::dry_run_extrinsic", + "Applying extrinsic failed with error {:?}", + error, + ); + XcmDryRunApiError::InvalidExtrinsic + })?; + let local_xcm = pallet_xcm::Pallet::::recorded_xcm(); + let forwarded_xcms = xcm_config::XcmRouter::get_messages(); + let events: Vec = System::read_events_no_consensus().map(|record| record.event.clone()).collect(); + Ok(ExtrinsicDryRunEffects { + local_xcm: local_xcm.map(VersionedXcm::<()>::V4), + forwarded_xcms, + emitted_events: events, + execution_result: result, + }) + } + + fn dry_run_xcm(origin_location: VersionedLocation, program: VersionedXcm) -> Result, XcmDryRunApiError> { + use xcm_builder::InspectMessageQueues; + use xcm::prelude::*; + + let origin_location: Location = origin_location.try_into().map_err(|error| { + log::error!( + target: "xcm::XcmDryRunApi::dry_run_xcm", + "Location version conversion failed with error: {:?}", + error, + ); + XcmDryRunApiError::VersionedConversionFailed + })?; + let program: Xcm = program.try_into().map_err(|error| { + log::error!( + target: "xcm::XcmDryRunApi::dry_run_xcm", + "Xcm version conversion failed with error {:?}", + error, + ); + XcmDryRunApiError::VersionedConversionFailed + })?; + let mut hash = program.using_encoded(sp_core::hashing::blake2_256); + let result = xcm_executor::XcmExecutor::::prepare_and_execute( + origin_location, + program, + &mut hash, + Weight::MAX, // Max limit available for execution. + Weight::zero(), + ); + let forwarded_xcms = xcm_config::XcmRouter::get_messages(); + let events: Vec = System::read_events_no_consensus().map(|record| record.event.clone()).collect(); + Ok(XcmDryRunEffects { + forwarded_xcms, + emitted_events: events, + execution_result: result, + }) + } + } + impl pallet_transaction_payment_rpc_runtime_api::TransactionPaymentCallApi for Runtime { @@ -1584,27 +1735,23 @@ impl_runtime_apis! { fn worst_case_holding(depositable_count: u32) -> xcm::v4::Assets { // A mix of fungible, non-fungible, and concrete assets. let holding_non_fungibles = MaxAssetsIntoHolding::get() / 2 - depositable_count; - let holding_fungibles = holding_non_fungibles - 1; + let holding_fungibles = holding_non_fungibles - 2; // -2 for two `iter::once` bellow let fungibles_amount: u128 = 100; - let mut assets = (0..holding_fungibles) + (0..holding_fungibles) .map(|i| { Asset { id: AssetId(GeneralIndex(i as u128).into()), - fun: Fungible(fungibles_amount * i as u128), + fun: Fungible(fungibles_amount * (i + 1) as u128), // non-zero amount } }) .chain(core::iter::once(Asset { id: AssetId(Here.into()), fun: Fungible(u128::MAX) })) + .chain(core::iter::once(Asset { id: AssetId(WestendLocation::get()), fun: Fungible(1_000_000 * UNITS) })) .chain((0..holding_non_fungibles).map(|i| Asset { id: AssetId(GeneralIndex(i as u128).into()), fun: NonFungible(asset_instance_from(i)), })) - .collect::>(); - - assets.push(Asset { - id: AssetId(WestendLocation::get()), - fun: Fungible(1_000_000 * UNITS), - }); - assets.into() + .collect::>() + .into() } } @@ -1744,3 +1891,44 @@ cumulus_pallet_parachain_system::register_validate_block! { Runtime = Runtime, BlockExecutor = cumulus_pallet_aura_ext::BlockExecutor::, } + +parameter_types! { + // The deposit configuration for the singed migration. Specially if you want to allow any signed account to do the migration (see `SignedFilter`, these deposits should be high) + pub const MigrationSignedDepositPerItem: Balance = CENTS; + pub const MigrationSignedDepositBase: Balance = 2_000 * CENTS; + pub const MigrationMaxKeyLen: u32 = 512; +} + +impl pallet_state_trie_migration::Config for Runtime { + type RuntimeEvent = RuntimeEvent; + type Currency = Balances; + type RuntimeHoldReason = RuntimeHoldReason; + type SignedDepositPerItem = MigrationSignedDepositPerItem; + type SignedDepositBase = MigrationSignedDepositBase; + // An origin that can control the whole pallet: should be Root, or a part of your council. + type ControlOrigin = frame_system::EnsureSignedBy; + // specific account for the migration, can trigger the signed migrations. + type SignedFilter = frame_system::EnsureSignedBy; + + // Replace this with weight based on your runtime. + type WeightInfo = pallet_state_trie_migration::weights::SubstrateWeight; + + type MaxKeyLen = MigrationMaxKeyLen; +} + +frame_support::ord_parameter_types! { + pub const MigController: AccountId = AccountId::from(hex_literal::hex!("8458ed39dc4b6f6c7255f7bc42be50c2967db126357c999d44e12ca7ac80dc52")); + pub const RootMigController: AccountId = AccountId::from(hex_literal::hex!("8458ed39dc4b6f6c7255f7bc42be50c2967db126357c999d44e12ca7ac80dc52")); +} + +#[test] +fn ensure_key_ss58() { + use frame_support::traits::SortedMembers; + use sp_core::crypto::Ss58Codec; + let acc = + AccountId::from_ss58check("5F4EbSkZz18X36xhbsjvDNs6NuZ82HyYtq5UiJ1h9SBHJXZD").unwrap(); + assert_eq!(acc, MigController::sorted_members()[0]); + let acc = + AccountId::from_ss58check("5F4EbSkZz18X36xhbsjvDNs6NuZ82HyYtq5UiJ1h9SBHJXZD").unwrap(); + assert_eq!(acc, RootMigController::sorted_members()[0]); +} 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..4eebb1f8d78678b9f6a037e6fd3e4c5decfd8513 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 @@ -19,6 +19,7 @@ pub mod cumulus_pallet_xcmp_queue; pub mod extrinsic_weights; pub mod frame_system; pub mod pallet_asset_conversion; +pub mod pallet_asset_conversion_ops; pub mod pallet_assets_foreign; pub mod pallet_assets_local; pub mod pallet_assets_pool; diff --git a/cumulus/parachains/runtimes/assets/asset-hub-westend/src/weights/pallet_asset_conversion.rs b/cumulus/parachains/runtimes/assets/asset-hub-westend/src/weights/pallet_asset_conversion.rs index 7a5aed3d7c69ce54b229d859f56a6a2dd4881460..1c5b9be8f8e6f0067cd5373df23bf22c62215774 100644 --- a/cumulus/parachains/runtimes/assets/asset-hub-westend/src/weights/pallet_asset_conversion.rs +++ b/cumulus/parachains/runtimes/assets/asset-hub-westend/src/weights/pallet_asset_conversion.rs @@ -153,4 +153,26 @@ impl pallet_asset_conversion::WeightInfo for WeightInfo .saturating_add(T::DbWeight::get().writes(4)) .saturating_add(Weight::from_parts(0, 393).saturating_mul(n.into())) } + /// Storage: `AssetConversion::Pools` (r:1 w:0) + /// Proof: `AssetConversion::Pools` (`max_values`: None, `max_size`: Some(30), added: 2505, mode: `MaxEncodedLen`) + /// Storage: `Assets::Asset` (r:2 w:2) + /// 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: `PoolAssets::Asset` (r:1 w:1) + /// Proof: `PoolAssets::Asset` (`max_values`: None, `max_size`: Some(210), added: 2685, mode: `MaxEncodedLen`) + /// Storage: `PoolAssets::Account` (r:1 w:1) + /// Proof: `PoolAssets::Account` (`max_values`: None, `max_size`: Some(134), added: 2609, mode: `MaxEncodedLen`) + /// The range of component `n` is `[0, 3]`. + fn touch(n: u32, ) -> Weight { + // Proof Size summary in bytes: + // Measured: `1571` + // Estimated: `6360` + // Minimum execution time: 381_000_000 picoseconds. + Weight::from_parts(398_540_909, 6360) + // Standard Error: 1_330_283 + .saturating_add(Weight::from_parts(209_463_636, 0).saturating_mul(n.into())) + .saturating_add(T::DbWeight::get().reads(7_u64)) + .saturating_add(T::DbWeight::get().writes((2_u64).saturating_mul(n.into()))) + } } diff --git a/cumulus/parachains/runtimes/assets/asset-hub-westend/src/weights/pallet_asset_conversion_ops.rs b/cumulus/parachains/runtimes/assets/asset-hub-westend/src/weights/pallet_asset_conversion_ops.rs new file mode 100644 index 0000000000000000000000000000000000000000..dfe4092c3f023512e54464e3a1ba8443326e5bfc --- /dev/null +++ b/cumulus/parachains/runtimes/assets/asset-hub-westend/src/weights/pallet_asset_conversion_ops.rs @@ -0,0 +1,71 @@ +// 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_ops` +//! +//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 32.0.0 +//! DATE: 2024-02-15, STEPS: `10`, REPEAT: `2`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! WORST CASE MAP SIZE: `1000000` +//! HOSTNAME: `cob`, CPU: `` +//! WASM-EXECUTION: `Compiled`, CHAIN: `Some("asset-hub-westend-dev")`, DB CACHE: 1024 + +// Executed Command: +// ./target/debug/polkadot-parachain +// benchmark +// pallet +// --chain=asset-hub-westend-dev +// --steps=10 +// --repeat=2 +// --pallet=pallet-asset-conversion-ops +// --extrinsic=* +// --wasm-execution=compiled +// --heap-pages=4096 +// --output=./cumulus/parachains/runtimes/assets/asset-hub-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_asset_conversion_ops`. +pub struct WeightInfo(PhantomData); +impl pallet_asset_conversion_ops::WeightInfo for WeightInfo { + /// Storage: `AssetConversion::Pools` (r:1 w:0) + /// Proof: `AssetConversion::Pools` (`max_values`: None, `max_size`: Some(1224), added: 3699, mode: `MaxEncodedLen`) + /// Storage: `System::Account` (r:2 w:2) + /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) + /// Storage: `ForeignAssets::Account` (r:2 w:2) + /// Proof: `ForeignAssets::Account` (`max_values`: None, `max_size`: Some(732), added: 3207, mode: `MaxEncodedLen`) + /// Storage: `PoolAssets::Account` (r:2 w:2) + /// Proof: `PoolAssets::Account` (`max_values`: None, `max_size`: Some(134), added: 2609, mode: `MaxEncodedLen`) + /// Storage: `PoolAssets::Asset` (r:1 w:1) + /// Proof: `PoolAssets::Asset` (`max_values`: None, `max_size`: Some(210), added: 2685, mode: `MaxEncodedLen`) + /// Storage: `ForeignAssets::Asset` (r:1 w:1) + /// Proof: `ForeignAssets::Asset` (`max_values`: None, `max_size`: Some(808), added: 3283, mode: `MaxEncodedLen`) + fn migrate_to_new_account() -> Weight { + // Proof Size summary in bytes: + // Measured: `1105` + // Estimated: `7404` + // Minimum execution time: 2_216_000_000 picoseconds. + Weight::from_parts(2_379_000_000, 0) + .saturating_add(Weight::from_parts(0, 7404)) + .saturating_add(T::DbWeight::get().reads(9)) + .saturating_add(T::DbWeight::get().writes(8)) + } +} diff --git a/cumulus/parachains/runtimes/assets/asset-hub-westend/src/weights/pallet_balances.rs b/cumulus/parachains/runtimes/assets/asset-hub-westend/src/weights/pallet_balances.rs index 68aceca14c1589825e588e4a5491529120da01f5..bb8ae8e5f97e2792df79496a761c173bec6e0d95 100644 --- a/cumulus/parachains/runtimes/assets/asset-hub-westend/src/weights/pallet_balances.rs +++ b/cumulus/parachains/runtimes/assets/asset-hub-westend/src/weights/pallet_balances.rs @@ -17,9 +17,9 @@ //! 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-05-06, 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-unxyhko3-project-674-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` //! WASM-EXECUTION: `Compiled`, CHAIN: `Some("asset-hub-westend-dev")`, DB CACHE: 1024 // Executed Command: @@ -54,8 +54,8 @@ impl pallet_balances::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `0` // Estimated: `3593` - // Minimum execution time: 43_122_000 picoseconds. - Weight::from_parts(43_640_000, 0) + // Minimum execution time: 45_289_000 picoseconds. + Weight::from_parts(46_764_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 +66,8 @@ impl pallet_balances::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `0` // Estimated: `3593` - // Minimum execution time: 33_636_000 picoseconds. - Weight::from_parts(34_571_000, 0) + // Minimum execution time: 35_052_000 picoseconds. + Weight::from_parts(36_494_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 +78,8 @@ impl pallet_balances::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `103` // Estimated: `3593` - // Minimum execution time: 12_101_000 picoseconds. - Weight::from_parts(12_511_000, 0) + // Minimum execution time: 12_361_000 picoseconds. + Weight::from_parts(12_668_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 +90,8 @@ impl pallet_balances::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `103` // Estimated: `3593` - // Minimum execution time: 17_077_000 picoseconds. - Weight::from_parts(17_362_000, 0) + // Minimum execution time: 17_253_000 picoseconds. + Weight::from_parts(17_733_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 +102,8 @@ impl pallet_balances::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `103` // Estimated: `6196` - // Minimum execution time: 44_352_000 picoseconds. - Weight::from_parts(45_045_000, 0) + // Minimum execution time: 45_674_000 picoseconds. + Weight::from_parts(47_981_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 +114,8 @@ impl pallet_balances::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `0` // Estimated: `3593` - // Minimum execution time: 41_836_000 picoseconds. - Weight::from_parts(43_201_000, 0) + // Minimum execution time: 45_021_000 picoseconds. + Weight::from_parts(46_292_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 +126,8 @@ impl pallet_balances::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `103` // Estimated: `3593` - // Minimum execution time: 14_413_000 picoseconds. - Weight::from_parts(14_743_000, 0) + // Minimum execution time: 15_071_000 picoseconds. + Weight::from_parts(15_406_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 +139,11 @@ impl pallet_balances::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `0 + u * (136 ±0)` // Estimated: `990 + u * (2603 ±0)` - // Minimum execution time: 14_542_000 picoseconds. - Weight::from_parts(14_731_000, 0) + // Minimum execution time: 14_779_000 picoseconds. + Weight::from_parts(15_129_000, 0) .saturating_add(Weight::from_parts(0, 990)) - // Standard Error: 11_213 - .saturating_add(Weight::from_parts(13_160_721, 0).saturating_mul(u.into())) + // Standard Error: 10_629 + .saturating_add(Weight::from_parts(13_558_995, 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,9 +154,25 @@ impl pallet_balances::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `0` // Estimated: `1501` - // Minimum execution time: 5_208_000 picoseconds. - Weight::from_parts(5_619_000, 0) + // Minimum execution time: 5_274_000 picoseconds. + Weight::from_parts(5_727_000, 0) .saturating_add(Weight::from_parts(0, 1501)) .saturating_add(T::DbWeight::get().reads(1)) } + fn burn_allow_death() -> Weight { + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 28_088_000 picoseconds. + Weight::from_parts(28_980_000, 0) + .saturating_add(Weight::from_parts(0, 0)) + } + fn burn_keep_alive() -> Weight { + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 19_002_000 picoseconds. + Weight::from_parts(19_480_000, 0) + .saturating_add(Weight::from_parts(0, 0)) + } } 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 a36c25f96043dd9d2b183ff45c3030315bd5bd19..be3d7661ab3cde8d94cf7e22eeed0a48ffa1cd5c 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 @@ -70,28 +70,6 @@ impl pallet_xcm::WeightInfo for WeightInfo { .saturating_add(T::DbWeight::get().reads(6)) .saturating_add(T::DbWeight::get().writes(2)) } - /// Storage: `ParachainSystem::UpwardDeliveryFeeFactor` (r:1 w:0) - /// Proof: `ParachainSystem::UpwardDeliveryFeeFactor` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - /// Storage: `PolkadotXcm::SupportedVersion` (r:1 w:0) - /// Proof: `PolkadotXcm::SupportedVersion` (`max_values`: None, `max_size`: None, mode: `Measured`) - /// Storage: `PolkadotXcm::VersionDiscoveryQueue` (r:1 w:1) - /// Proof: `PolkadotXcm::VersionDiscoveryQueue` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - /// Storage: `PolkadotXcm::SafeXcmVersion` (r:1 w:0) - /// Proof: `PolkadotXcm::SafeXcmVersion` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - /// Storage: `ParachainSystem::HostConfiguration` (r:1 w:0) - /// Proof: `ParachainSystem::HostConfiguration` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - /// Storage: `ParachainSystem::PendingUpwardMessages` (r:1 w:1) - /// Proof: `ParachainSystem::PendingUpwardMessages` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - fn send_blob() -> Weight { - // Proof Size summary in bytes: - // Measured: `145` - // Estimated: `3610` - // Minimum execution time: 21_164_000 picoseconds. - Weight::from_parts(21_656_000, 0) - .saturating_add(Weight::from_parts(0, 3610)) - .saturating_add(T::DbWeight::get().reads(6)) - .saturating_add(T::DbWeight::get().writes(2)) - } /// Storage: `ParachainInfo::ParachainId` (r:1 w:0) /// Proof: `ParachainInfo::ParachainId` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) /// Storage: `ParachainSystem::UpwardDeliveryFeeFactor` (r:1 w:0) @@ -184,14 +162,6 @@ impl pallet_xcm::WeightInfo for WeightInfo { Weight::from_parts(7_791_000, 0) .saturating_add(Weight::from_parts(0, 0)) } - fn execute_blob() -> Weight { - // Proof Size summary in bytes: - // Measured: `0` - // Estimated: `0` - // Minimum execution time: 7_585_000 picoseconds. - Weight::from_parts(7_897_000, 0) - .saturating_add(Weight::from_parts(0, 0)) - } /// Storage: `PolkadotXcm::SupportedVersion` (r:0 w:1) /// Proof: `PolkadotXcm::SupportedVersion` (`max_values`: None, `max_size`: None, mode: `Measured`) fn force_xcm_version() -> Weight { 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 41e941ee9a2b10f2a3e7fdbe723489e4cc6c4497..35a42627ad71004642b278bba1ff1a564929061f 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,10 +45,10 @@ use polkadot_runtime_common::xcm_sender::ExponentialPrice; use sp_runtime::traits::{AccountIdConversion, ConvertInto}; use xcm::latest::prelude::*; use xcm_builder::{ - AccountId32Aliases, AllowExplicitUnpaidExecutionFrom, AllowKnownQueryResponses, - AllowSubscriptionsFrom, AllowTopLevelPaidExecutionFrom, DenyReserveTransferToRelayChain, - DenyThenTry, DescribeFamily, DescribePalletTerminal, EnsureXcmOrigin, - FrameTransactionalProcessor, FungibleAdapter, FungiblesAdapter, + AccountId32Aliases, AllowExplicitUnpaidExecutionFrom, AllowHrmpNotificationsFromRelayChain, + AllowKnownQueryResponses, AllowSubscriptionsFrom, AllowTopLevelPaidExecutionFrom, + DenyReserveTransferToRelayChain, DenyThenTry, DescribeFamily, DescribePalletTerminal, + EnsureXcmOrigin, FrameTransactionalProcessor, FungibleAdapter, FungiblesAdapter, GlobalConsensusParachainConvertsFor, HashedDescription, IsConcrete, LocalMint, NetworkExportTableItem, NoChecking, NonFungiblesAdapter, ParentAsSuperuser, ParentIsPreset, RelayChainAsNative, SiblingParachainAsNative, SiblingParachainConvertsVia, @@ -57,7 +57,7 @@ use xcm_builder::{ WeightInfoBounds, WithComputedOrigin, WithUniqueTopic, XcmFeeManagerFromComponents, XcmFeeToAccount, }; -use xcm_executor::{traits::WithOriginFilter, XcmExecutor}; +use xcm_executor::XcmExecutor; parameter_types! { pub const WestendLocation: Location = Location::parent(); @@ -275,228 +275,6 @@ impl Contains for AmbassadorEntities { } } -/// A call filter for the XCM Transact instruction. This is a temporary measure until we properly -/// account for proof size weights. -/// -/// Calls that are allowed through this filter must: -/// 1. Have a fixed weight; -/// 2. Cannot lead to another call being made; -/// 3. Have a defined proof size weight, e.g. no unbounded vecs in call parameters. -pub struct SafeCallFilter; -impl Contains for SafeCallFilter { - fn contains(call: &RuntimeCall) -> bool { - #[cfg(feature = "runtime-benchmarks")] - { - if matches!(call, RuntimeCall::System(frame_system::Call::remark_with_event { .. })) { - return true - } - } - - // Allow to change dedicated storage items (called by governance-like) - match call { - RuntimeCall::System(frame_system::Call::set_storage { items }) - if items.iter().all(|(k, _)| k.eq(&bridging::XcmBridgeHubRouterByteFee::key())) || - items - .iter() - .all(|(k, _)| k.eq(&bridging::XcmBridgeHubRouterBaseFee::key())) => - return true, - _ => (), - }; - - matches!( - call, - RuntimeCall::PolkadotXcm( - pallet_xcm::Call::force_xcm_version { .. } | - 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 { .. }, - ) | RuntimeCall::ParachainSystem(..) | - RuntimeCall::Timestamp(..) | - RuntimeCall::Balances(..) | - RuntimeCall::CollatorSelection(..) | - RuntimeCall::Session(pallet_session::Call::purge_keys { .. }) | - RuntimeCall::XcmpQueue(..) | - RuntimeCall::MessageQueue(..) | - RuntimeCall::Assets( - pallet_assets::Call::create { .. } | - pallet_assets::Call::force_create { .. } | - pallet_assets::Call::start_destroy { .. } | - pallet_assets::Call::destroy_accounts { .. } | - pallet_assets::Call::destroy_approvals { .. } | - pallet_assets::Call::finish_destroy { .. } | - pallet_assets::Call::block { .. } | - pallet_assets::Call::mint { .. } | - pallet_assets::Call::burn { .. } | - pallet_assets::Call::transfer { .. } | - pallet_assets::Call::transfer_keep_alive { .. } | - pallet_assets::Call::force_transfer { .. } | - pallet_assets::Call::freeze { .. } | - pallet_assets::Call::thaw { .. } | - pallet_assets::Call::freeze_asset { .. } | - pallet_assets::Call::thaw_asset { .. } | - pallet_assets::Call::transfer_ownership { .. } | - pallet_assets::Call::set_team { .. } | - pallet_assets::Call::set_metadata { .. } | - pallet_assets::Call::clear_metadata { .. } | - pallet_assets::Call::force_set_metadata { .. } | - pallet_assets::Call::force_clear_metadata { .. } | - pallet_assets::Call::force_asset_status { .. } | - pallet_assets::Call::approve_transfer { .. } | - pallet_assets::Call::cancel_approval { .. } | - pallet_assets::Call::force_cancel_approval { .. } | - pallet_assets::Call::transfer_approved { .. } | - pallet_assets::Call::touch { .. } | - pallet_assets::Call::touch_other { .. } | - pallet_assets::Call::refund { .. } | - pallet_assets::Call::refund_other { .. }, - ) | RuntimeCall::ForeignAssets( - pallet_assets::Call::create { .. } | - pallet_assets::Call::force_create { .. } | - pallet_assets::Call::start_destroy { .. } | - pallet_assets::Call::destroy_accounts { .. } | - pallet_assets::Call::destroy_approvals { .. } | - pallet_assets::Call::finish_destroy { .. } | - pallet_assets::Call::block { .. } | - pallet_assets::Call::mint { .. } | - pallet_assets::Call::burn { .. } | - pallet_assets::Call::transfer { .. } | - pallet_assets::Call::transfer_keep_alive { .. } | - pallet_assets::Call::force_transfer { .. } | - pallet_assets::Call::freeze { .. } | - pallet_assets::Call::thaw { .. } | - pallet_assets::Call::freeze_asset { .. } | - pallet_assets::Call::thaw_asset { .. } | - pallet_assets::Call::transfer_ownership { .. } | - pallet_assets::Call::set_team { .. } | - pallet_assets::Call::set_metadata { .. } | - pallet_assets::Call::clear_metadata { .. } | - pallet_assets::Call::force_set_metadata { .. } | - pallet_assets::Call::force_clear_metadata { .. } | - pallet_assets::Call::force_asset_status { .. } | - pallet_assets::Call::approve_transfer { .. } | - pallet_assets::Call::cancel_approval { .. } | - pallet_assets::Call::force_cancel_approval { .. } | - pallet_assets::Call::transfer_approved { .. } | - pallet_assets::Call::touch { .. } | - pallet_assets::Call::touch_other { .. } | - pallet_assets::Call::refund { .. } | - pallet_assets::Call::refund_other { .. }, - ) | RuntimeCall::PoolAssets( - pallet_assets::Call::create { .. } | - pallet_assets::Call::force_create { .. } | - pallet_assets::Call::start_destroy { .. } | - pallet_assets::Call::destroy_accounts { .. } | - pallet_assets::Call::destroy_approvals { .. } | - pallet_assets::Call::finish_destroy { .. } | - pallet_assets::Call::block { .. } | - pallet_assets::Call::mint { .. } | - pallet_assets::Call::burn { .. } | - pallet_assets::Call::transfer { .. } | - pallet_assets::Call::transfer_keep_alive { .. } | - pallet_assets::Call::force_transfer { .. } | - pallet_assets::Call::freeze { .. } | - pallet_assets::Call::thaw { .. } | - pallet_assets::Call::freeze_asset { .. } | - pallet_assets::Call::thaw_asset { .. } | - pallet_assets::Call::transfer_ownership { .. } | - pallet_assets::Call::set_team { .. } | - pallet_assets::Call::set_metadata { .. } | - pallet_assets::Call::clear_metadata { .. } | - pallet_assets::Call::force_set_metadata { .. } | - pallet_assets::Call::force_clear_metadata { .. } | - pallet_assets::Call::force_asset_status { .. } | - pallet_assets::Call::approve_transfer { .. } | - pallet_assets::Call::cancel_approval { .. } | - pallet_assets::Call::force_cancel_approval { .. } | - pallet_assets::Call::transfer_approved { .. } | - pallet_assets::Call::touch { .. } | - pallet_assets::Call::touch_other { .. } | - pallet_assets::Call::refund { .. } | - pallet_assets::Call::refund_other { .. }, - ) | RuntimeCall::AssetConversion( - pallet_asset_conversion::Call::create_pool { .. } | - pallet_asset_conversion::Call::add_liquidity { .. } | - pallet_asset_conversion::Call::remove_liquidity { .. } | - pallet_asset_conversion::Call::swap_tokens_for_exact_tokens { .. } | - pallet_asset_conversion::Call::swap_exact_tokens_for_tokens { .. }, - ) | RuntimeCall::NftFractionalization( - pallet_nft_fractionalization::Call::fractionalize { .. } | - pallet_nft_fractionalization::Call::unify { .. }, - ) | RuntimeCall::Nfts( - pallet_nfts::Call::create { .. } | - pallet_nfts::Call::force_create { .. } | - pallet_nfts::Call::destroy { .. } | - pallet_nfts::Call::mint { .. } | - pallet_nfts::Call::force_mint { .. } | - pallet_nfts::Call::burn { .. } | - pallet_nfts::Call::transfer { .. } | - pallet_nfts::Call::lock_item_transfer { .. } | - pallet_nfts::Call::unlock_item_transfer { .. } | - pallet_nfts::Call::lock_collection { .. } | - pallet_nfts::Call::transfer_ownership { .. } | - pallet_nfts::Call::set_team { .. } | - pallet_nfts::Call::force_collection_owner { .. } | - pallet_nfts::Call::force_collection_config { .. } | - pallet_nfts::Call::approve_transfer { .. } | - pallet_nfts::Call::cancel_approval { .. } | - pallet_nfts::Call::clear_all_transfer_approvals { .. } | - pallet_nfts::Call::lock_item_properties { .. } | - pallet_nfts::Call::set_attribute { .. } | - pallet_nfts::Call::force_set_attribute { .. } | - pallet_nfts::Call::clear_attribute { .. } | - pallet_nfts::Call::approve_item_attributes { .. } | - pallet_nfts::Call::cancel_item_attributes_approval { .. } | - pallet_nfts::Call::set_metadata { .. } | - pallet_nfts::Call::clear_metadata { .. } | - pallet_nfts::Call::set_collection_metadata { .. } | - pallet_nfts::Call::clear_collection_metadata { .. } | - pallet_nfts::Call::set_accept_ownership { .. } | - pallet_nfts::Call::set_collection_max_supply { .. } | - pallet_nfts::Call::update_mint_settings { .. } | - pallet_nfts::Call::set_price { .. } | - pallet_nfts::Call::buy_item { .. } | - pallet_nfts::Call::pay_tips { .. } | - pallet_nfts::Call::create_swap { .. } | - pallet_nfts::Call::cancel_swap { .. } | - pallet_nfts::Call::claim_swap { .. }, - ) | RuntimeCall::Uniques( - pallet_uniques::Call::create { .. } | - pallet_uniques::Call::force_create { .. } | - pallet_uniques::Call::destroy { .. } | - pallet_uniques::Call::mint { .. } | - pallet_uniques::Call::burn { .. } | - pallet_uniques::Call::transfer { .. } | - pallet_uniques::Call::freeze { .. } | - pallet_uniques::Call::thaw { .. } | - pallet_uniques::Call::freeze_collection { .. } | - pallet_uniques::Call::thaw_collection { .. } | - pallet_uniques::Call::transfer_ownership { .. } | - pallet_uniques::Call::set_team { .. } | - pallet_uniques::Call::approve_transfer { .. } | - pallet_uniques::Call::cancel_approval { .. } | - pallet_uniques::Call::force_item_status { .. } | - pallet_uniques::Call::set_attribute { .. } | - pallet_uniques::Call::clear_attribute { .. } | - pallet_uniques::Call::set_metadata { .. } | - pallet_uniques::Call::clear_metadata { .. } | - pallet_uniques::Call::set_collection_metadata { .. } | - pallet_uniques::Call::clear_collection_metadata { .. } | - pallet_uniques::Call::set_accept_ownership { .. } | - pallet_uniques::Call::set_collection_max_supply { .. } | - pallet_uniques::Call::set_price { .. } | - pallet_uniques::Call::buy_item { .. } - ) | RuntimeCall::ToRococoXcmRouter( - pallet_xcm_bridge_hub_router::Call::report_bridge_status { .. } - ) - ) - } -} - pub type Barrier = TrailingSetTopicAsId< DenyThenTry< DenyReserveTransferToRelayChain, @@ -521,6 +299,8 @@ pub type Barrier = TrailingSetTopicAsId< )>, // Subscriptions for version tracking are OK. AllowSubscriptionsFrom, + // HRMP notifications from the relay chain are OK. + AllowHrmpNotificationsFromRelayChain, ), UniversalLocation, ConstU32<8>, @@ -653,13 +433,14 @@ impl xcm_executor::Config for XcmConfig { >; type MessageExporter = (); type UniversalAliases = (bridging::to_rococo::UniversalAliases,); - type CallDispatcher = WithOriginFilter; - type SafeCallFilter = SafeCallFilter; + type CallDispatcher = RuntimeCall; + type SafeCallFilter = Everything; type Aliasers = Nothing; type TransactionalProcessor = FrameTransactionalProcessor; type HrmpNewChannelOpenRequestHandler = (); type HrmpChannelAcceptedHandler = (); type HrmpChannelClosingHandler = (); + type XcmRecorder = PolkadotXcm; } /// Local origins on this chain are allowed to dispatch XCM sends/executions. diff --git a/cumulus/parachains/runtimes/assets/common/Cargo.toml b/cumulus/parachains/runtimes/assets/common/Cargo.toml index 12dfd9da1fffbc6d1be0edc40ab6de3ebcc78e20..4664e0cb9a7f817ed419936dfa9e5d0ac52f599e 100644 --- a/cumulus/parachains/runtimes/assets/common/Cargo.toml +++ b/cumulus/parachains/runtimes/assets/common/Cargo.toml @@ -10,7 +10,7 @@ license = "Apache-2.0" workspace = true [dependencies] -codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = ["derive"] } +codec = { package = "parity-scale-codec", version = "3.6.12", default-features = false, features = ["derive"] } scale-info = { version = "2.11.1", default-features = false, features = ["derive"] } log = { workspace = true } impl-trait-for-tuples = "0.2.2" diff --git a/cumulus/parachains/runtimes/assets/test-utils/Cargo.toml b/cumulus/parachains/runtimes/assets/test-utils/Cargo.toml index 883c93c97b4de6774e86ee83b84d246dc1427f7f..776c7dce0b486d30fcf967bea01333df199789b1 100644 --- a/cumulus/parachains/runtimes/assets/test-utils/Cargo.toml +++ b/cumulus/parachains/runtimes/assets/test-utils/Cargo.toml @@ -10,7 +10,7 @@ license = "Apache-2.0" workspace = true [dependencies] -codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = ["derive", "max-encoded-len"] } +codec = { package = "parity-scale-codec", version = "3.6.12", default-features = false, features = ["derive", "max-encoded-len"] } # Substrate frame-support = { path = "../../../../../substrate/frame/support", default-features = false } 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 f5a75aa03acd01381666a30439789387ae699ac9..0fb12531b8ee8f3bed0cb3266f19a188150217e5 100644 --- a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/Cargo.toml +++ b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/Cargo.toml @@ -13,7 +13,7 @@ workspace = true substrate-wasm-builder = { path = "../../../../../substrate/utils/wasm-builder", optional = true } [dependencies] -codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = [ +codec = { package = "parity-scale-codec", version = "3.6.12", default-features = false, features = [ "derive", ] } hex-literal = { version = "0.4.1" } @@ -22,6 +22,7 @@ scale-info = { version = "2.11.1", default-features = false, features = [ "derive", ] } serde = { optional = true, features = ["derive"], workspace = true, default-features = true } +tuplex = { version = "0.1", default-features = false } # Substrate frame-benchmarking = { path = "../../../../../substrate/frame/benchmarking", default-features = false, optional = true } @@ -218,6 +219,7 @@ std = [ "sp-version/std", "substrate-wasm-builder", "testnet-parachains-constants/std", + "tuplex/std", "xcm-builder/std", "xcm-executor/std", "xcm/std", diff --git a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/bridge_common_config.rs b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/bridge_common_config.rs index 93ef9470363cd3dd41a92fe529226ad3fd7b2e00..5551b05e202547c99501b279e8839611efcc7f66 100644 --- a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/bridge_common_config.rs +++ b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/bridge_common_config.rs @@ -49,7 +49,8 @@ pub type BridgeGrandpaWestendInstance = pallet_bridge_grandpa::Instance3; impl pallet_bridge_grandpa::Config for Runtime { type RuntimeEvent = RuntimeEvent; type BridgedChain = bp_westend::Westend; - type MaxFreeMandatoryHeadersPerBlock = ConstU32<4>; + type MaxFreeHeadersPerBlock = ConstU32<4>; + type FreeHeadersInterval = ConstU32<5>; type HeadersToKeep = RelayChainHeadersToKeep; type WeightInfo = weights::pallet_bridge_grandpa::WeightInfo; } @@ -89,7 +90,8 @@ pub type BridgeGrandpaRococoBulletinInstance = pallet_bridge_grandpa::Instance4; impl pallet_bridge_grandpa::Config for Runtime { type RuntimeEvent = RuntimeEvent; type BridgedChain = bp_polkadot_bulletin::PolkadotBulletin; - type MaxFreeMandatoryHeadersPerBlock = ConstU32<4>; + type MaxFreeHeadersPerBlock = ConstU32<4>; + type FreeHeadersInterval = ConstU32<5>; type HeadersToKeep = RelayChainHeadersToKeep; // Technically this is incorrect - we have two pallet instances and ideally we shall // benchmark every instance separately. But the benchmarking engine has a flaw - it 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 8845f0538b5c828f459431f1a01b54fefc98e9dc..94b936889b77c4460f9921956d6f7abef1ecb52c 100644 --- a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/bridge_to_bulletin_config.rs +++ b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/bridge_to_bulletin_config.rs @@ -20,17 +20,15 @@ //! are reusing Polkadot Bulletin chain primitives everywhere here. use crate::{ - bridge_common_config::{BridgeGrandpaRococoBulletinInstance, BridgeHubRococo}, - weights, - xcm_config::UniversalLocation, - AccountId, BridgeRococoBulletinGrandpa, BridgeRococoBulletinMessages, PolkadotXcm, Runtime, - RuntimeEvent, XcmOverRococoBulletin, XcmRouter, + bridge_common_config::BridgeHubRococo, weights, xcm_config::UniversalLocation, AccountId, + BridgeRococoBulletinGrandpa, BridgeRococoBulletinMessages, PolkadotXcm, Runtime, RuntimeEvent, + XcmOverRococoBulletin, XcmRouter, }; use bp_messages::LaneId; use bp_runtime::Chain; use bridge_runtime_common::{ extensions::refund_relayer_extension::{ - ActualFeeRefund, RefundBridgedGrandpaMessages, RefundSignedExtensionAdapter, + ActualFeeRefund, RefundBridgedMessages, RefundSignedExtensionAdapter, RefundableMessagesLane, }, messages, @@ -83,6 +81,9 @@ parameter_types! { pub const RococoPeopleToRococoBulletinMessagesLane: bp_messages::LaneId = XCM_LANE_FOR_ROCOCO_PEOPLE_TO_ROCOCO_BULLETIN; + // see the `FEE_BOOST_PER_RELAY_HEADER` constant get the meaning of this value + pub PriorityBoostPerRelayHeader: u64 = 58_014_163_614_163; + /// Priority boost that the registered relayer receives for every additional message in the message /// delivery transaction. /// @@ -169,9 +170,8 @@ impl messages::BridgedChainWithMessages for RococoBulletin {} /// Signed extension that refunds relayers that are delivering messages from the Rococo Bulletin /// chain. pub type OnBridgeHubRococoRefundRococoBulletinMessages = RefundSignedExtensionAdapter< - RefundBridgedGrandpaMessages< + RefundBridgedMessages< Runtime, - BridgeGrandpaRococoBulletinInstance, RefundableMessagesLane< WithRococoBulletinMessagesInstance, RococoPeopleToRococoBulletinMessagesLane, @@ -244,6 +244,9 @@ mod tests { /// operational costs and a faster bridge), so this value should be significant. const FEE_BOOST_PER_MESSAGE: Balance = 2 * rococo::currency::UNITS; + // see `FEE_BOOST_PER_MESSAGE` comment + const FEE_BOOST_PER_RELAY_HEADER: Balance = 2 * rococo::currency::UNITS; + #[test] fn ensure_bridge_hub_rococo_message_lane_weights_are_correct() { check_message_lane_weights::< @@ -273,7 +276,13 @@ mod tests { // Bulletin chain - it has the same (almost) runtime for Polkadot Bulletin and Rococo // Bulletin, so we have to adhere Polkadot names here - bridge_runtime_common::extensions::priority_calculator::ensure_priority_boost_is_sane::< + bridge_runtime_common::extensions::priority_calculator::per_relay_header::ensure_priority_boost_is_sane::< + Runtime, + BridgeGrandpaRococoBulletinInstance, + PriorityBoostPerRelayHeader, + >(FEE_BOOST_PER_RELAY_HEADER); + + bridge_runtime_common::extensions::priority_calculator::per_message::ensure_priority_boost_is_sane::< Runtime, WithRococoBulletinMessagesInstance, PriorityBoostPerMessage, 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 e5a00073407f8f754f58ef88e825ca598b7bde94..1681ac7f4687493c82c0a3233439b2a9d47a1ad0 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 @@ -29,8 +29,8 @@ use bp_messages::LaneId; use bp_runtime::Chain; use bridge_runtime_common::{ extensions::refund_relayer_extension::{ - ActualFeeRefund, RefundBridgedParachainMessages, RefundSignedExtensionAdapter, - RefundableMessagesLane, RefundableParachain, + ActualFeeRefund, RefundBridgedMessages, RefundSignedExtensionAdapter, + RefundableMessagesLane, }, messages, messages::{ @@ -65,6 +65,10 @@ parameter_types! { 2, [GlobalConsensus(WestendGlobalConsensusNetwork::get())] ); + // see the `FEE_BOOST_PER_RELAY_HEADER` constant get the meaning of this value + pub PriorityBoostPerRelayHeader: u64 = 32_007_814_407_814; + // see the `FEE_BOOST_PER_PARACHAIN_HEADER` constant get the meaning of this value + pub PriorityBoostPerParachainHeader: u64 = 1_396_340_903_540_903; // see the `FEE_BOOST_PER_MESSAGE` constant to get the meaning of this value pub PriorityBoostPerMessage: u64 = 182_044_444_444_444; @@ -174,12 +178,8 @@ impl messages::BridgedChainWithMessages for BridgeHubWestend {} /// Signed extension that refunds relayers that are delivering messages from the Westend parachain. pub type OnBridgeHubRococoRefundBridgeHubWestendMessages = RefundSignedExtensionAdapter< - RefundBridgedParachainMessages< + RefundBridgedMessages< Runtime, - RefundableParachain< - BridgeParachainWestendInstance, - bp_bridge_hub_westend::BridgeHubWestend, - >, RefundableMessagesLane< WithBridgeHubWestendMessagesInstance, AssetHubRococoToAssetHubWestendMessagesLane, @@ -246,6 +246,7 @@ mod tests { use crate::bridge_common_config::BridgeGrandpaWestendInstance; use bridge_runtime_common::{ assert_complete_bridge_types, + extensions::refund_relayer_extension::RefundableParachain, integrity::{ assert_complete_bridge_constants, check_message_lane_weights, AssertBridgeMessagesPalletConstants, AssertBridgePalletNames, AssertChainConstants, @@ -266,6 +267,11 @@ mod tests { /// operational costs and a faster bridge), so this value should be significant. const FEE_BOOST_PER_MESSAGE: Balance = 2 * rococo::currency::UNITS; + // see `FEE_BOOST_PER_MESSAGE` comment + const FEE_BOOST_PER_RELAY_HEADER: Balance = 2 * rococo::currency::UNITS; + // see `FEE_BOOST_PER_MESSAGE` comment + const FEE_BOOST_PER_PARACHAIN_HEADER: Balance = 2 * rococo::currency::UNITS; + #[test] fn ensure_bridge_hub_rococo_message_lane_weights_are_correct() { check_message_lane_weights::< @@ -318,7 +324,19 @@ mod tests { }, }); - bridge_runtime_common::extensions::priority_calculator::ensure_priority_boost_is_sane::< + bridge_runtime_common::extensions::priority_calculator::per_relay_header::ensure_priority_boost_is_sane::< + Runtime, + BridgeGrandpaWestendInstance, + PriorityBoostPerRelayHeader, + >(FEE_BOOST_PER_RELAY_HEADER); + + bridge_runtime_common::extensions::priority_calculator::per_parachain_header::ensure_priority_boost_is_sane::< + Runtime, + RefundableParachain, + PriorityBoostPerParachainHeader, + >(FEE_BOOST_PER_PARACHAIN_HEADER); + + bridge_runtime_common::extensions::priority_calculator::per_message::ensure_priority_boost_is_sane::< Runtime, WithBridgeHubWestendMessagesInstance, PriorityBoostPerMessage, 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 1eac813b10cec7afb60312aea252f1a37cdfa986..9043175a701c75c1240ccd5904bf512ece68697f 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 @@ -35,6 +35,12 @@ pub mod bridge_to_westend_config; mod weights; pub mod xcm_config; +use bridge_runtime_common::extensions::{ + check_obsolete_extension::{ + CheckAndBoostBridgeGrandpaTransactions, CheckAndBoostBridgeParachainsTransactions, + }, + refund_relayer_extension::RefundableParachain, +}; use cumulus_pallet_parachain_system::RelayNumberMonotonicallyIncreases; use snowbridge_beacon_primitives::{Fork, ForkVersions}; use snowbridge_core::{ @@ -63,7 +69,7 @@ use frame_support::{ dispatch::DispatchClass, genesis_builder_helper::{build_state, get_preset}, parameter_types, - traits::{ConstBool, ConstU32, ConstU64, ConstU8, TransformOrigin}, + traits::{ConstBool, ConstU32, ConstU64, ConstU8, Get, TransformOrigin}, weights::{ConstantMultiplier, Weight}, PalletId, }; @@ -139,11 +145,12 @@ pub type UncheckedExtrinsic = /// Migrations to apply on runtime upgrade. pub type Migrations = ( - pallet_collator_selection::migration::v1::MigrateToV1, + pallet_collator_selection::migration::v2::MigrationToV2, pallet_multisig::migrations::v1::MigrateToV1, InitStorageVersions, - cumulus_pallet_xcmp_queue::migration::v4::MigrationToV4, // unreleased + cumulus_pallet_xcmp_queue::migration::v4::MigrationToV4, + cumulus_pallet_xcmp_queue::migration::v5::MigrateV4ToV5, snowbridge_pallet_system::migration::v0::InitializeOnUpgrade< Runtime, ConstU32, @@ -203,10 +210,10 @@ pub const VERSION: RuntimeVersion = RuntimeVersion { spec_name: create_runtime_str!("bridge-hub-rococo"), impl_name: create_runtime_str!("bridge-hub-rococo"), authoring_version: 1, - spec_version: 1_010_000, + spec_version: 1_011_000, impl_version: 0, apis: RUNTIME_API_VERSIONS, - transaction_version: 4, + transaction_version: 5, state_version: 1, }; @@ -383,7 +390,7 @@ impl pallet_message_queue::Config for Runtime { // The XCMP queue pallet is only ever able to handle the `Sibling(ParaId)` origin: type QueueChangeHandler = NarrowOriginToSibling; type QueuePausedQuery = NarrowOriginToSibling; - type HeapSize = sp_core::ConstU32<{ 64 * 1024 }>; + type HeapSize = sp_core::ConstU32<{ 103 * 1024 }>; type MaxStale = sp_core::ConstU32<8>; type ServiceWeight = MessageQueueServiceWeight; type IdleMaxServiceWeight = MessageQueueServiceWeight; @@ -411,13 +418,22 @@ impl cumulus_pallet_xcmp_queue::Config for Runtime { type VersionWrapper = PolkadotXcm; // Enqueue XCMP messages from siblings for later processing. type XcmpQueue = TransformOrigin; - type MaxInboundSuspended = sp_core::ConstU32<1_000>; + type MaxInboundSuspended = ConstU32<1_000>; + type MaxActiveOutboundChannels = ConstU32<128>; + // Most on-chain HRMP channels are configured to use 102400 bytes of max message size, so we + // need to set the page size larger than that until we reduce the channel size on-chain. + type MaxPageSize = ConstU32<{ 103 * 1024 }>; type ControllerOrigin = EnsureRoot; type ControllerOriginConverter = XcmOriginToTransactDispatchOrigin; type WeightInfo = weights::cumulus_pallet_xcmp_queue::WeightInfo; type PriceForSiblingDelivery = PriceForSiblingParachainDelivery; } +impl cumulus_pallet_xcmp_queue::migration::v5::V5Config for Runtime { + // This must be the same as the `ChannelInfo` from the `Config`: + type ChannelList = ParachainSystem; +} + parameter_types! { pub const RelayOrigin: AggregateMessageOrigin = AggregateMessageOrigin::Parent; } @@ -740,10 +756,28 @@ pub type XcmOverRococoBulletin = XcmOverPolkadotBulletin; bridge_runtime_common::generate_bridge_reject_obsolete_headers_and_messages! { RuntimeCall, AccountId, // Grandpa - BridgeWestendGrandpa, - BridgeRococoBulletinGrandpa, + CheckAndBoostBridgeGrandpaTransactions< + Runtime, + bridge_common_config::BridgeGrandpaWestendInstance, + bridge_to_westend_config::PriorityBoostPerRelayHeader, + xcm_config::TreasuryAccount, + >, + CheckAndBoostBridgeGrandpaTransactions< + Runtime, + bridge_common_config::BridgeGrandpaRococoBulletinInstance, + bridge_to_bulletin_config::PriorityBoostPerRelayHeader, + xcm_config::TreasuryAccount, + >, // Parachains - BridgeWestendParachains, + CheckAndBoostBridgeParachainsTransactions< + Runtime, + RefundableParachain< + bridge_common_config::BridgeParachainWestendInstance, + bp_bridge_hub_westend::BridgeHubWestend, + >, + bridge_to_westend_config::PriorityBoostPerParachainHeader, + xcm_config::TreasuryAccount, + >, // Messages BridgeWestendMessages, BridgeRococoBulletinMessages @@ -938,6 +972,11 @@ impl_runtime_apis! { fn best_finalized() -> Option> { BridgeWestendGrandpa::best_finalized() } + fn free_headers_interval() -> Option { + >::FreeHeadersInterval::get() + } fn synced_headers_grandpa_info( ) -> Vec> { BridgeWestendGrandpa::synced_headers_grandpa_info() @@ -950,6 +989,10 @@ impl_runtime_apis! { bp_bridge_hub_westend::BridgeHubWestend >().unwrap_or(None) } + fn free_headers_interval() -> Option { + // "free interval" is not currently used for parachains + None + } } // This is exposed by BridgeHubRococo @@ -984,6 +1027,12 @@ impl_runtime_apis! { BridgePolkadotBulletinGrandpa::best_finalized() } + fn free_headers_interval() -> Option { + >::FreeHeadersInterval::get() + } + fn synced_headers_grandpa_info( ) -> Vec> { BridgePolkadotBulletinGrandpa::synced_headers_grandpa_info() 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..942f243141da9c1dcfa47d2e3a1ac7906eb22706 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 @@ -17,8 +17,10 @@ //! Expose the auto generated weight files. +use ::pallet_bridge_grandpa::WeightInfoExt as GrandpaWeightInfoExt; use ::pallet_bridge_messages::WeightInfoExt as MessagesWeightInfoExt; use ::pallet_bridge_parachains::WeightInfoExt as ParachainsWeightInfoExt; +use ::pallet_bridge_relayers::WeightInfo as _; pub mod block_weights; pub mod cumulus_pallet_parachain_system; @@ -56,6 +58,16 @@ use frame_support::weights::Weight; // import trait from dependency module use ::pallet_bridge_relayers::WeightInfoExt as _; +impl GrandpaWeightInfoExt for pallet_bridge_grandpa::WeightInfo { + fn submit_finality_proof_overhead_from_runtime() -> Weight { + // our signed extension: + // 1) checks whether relayer registration is active from validate/pre_dispatch; + // 2) may slash and deregister relayer from post_dispatch + // (2) includes (1), so (2) is the worst case + pallet_bridge_relayers::WeightInfo::::slash_and_deregister() + } +} + impl MessagesWeightInfoExt for pallet_bridge_messages_rococo_to_rococo_bulletin::WeightInfo { @@ -94,4 +106,12 @@ impl ParachainsWeightInfoExt for pallet_bridge_parachains::WeightInfo u32 { bp_bridge_hub_westend::EXTRA_STORAGE_PROOF_SIZE } + + fn submit_parachain_heads_overhead_from_runtime() -> Weight { + // our signed extension: + // 1) checks whether relayer registration is active from validate/pre_dispatch; + // 2) may slash and deregister relayer from post_dispatch + // (2) includes (1), so (2) is the worst case + pallet_bridge_relayers::WeightInfo::::slash_and_deregister() + } } diff --git a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/weights/pallet_balances.rs b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/weights/pallet_balances.rs index 861ccfc51fd8e9f7bf8a1367d4ab4ddf459891a0..d67ae4dee92a8a9eec7ebefeda52fda7c08b6fab 100644 --- a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/weights/pallet_balances.rs +++ b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/weights/pallet_balances.rs @@ -17,9 +17,9 @@ //! 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-05-06, 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-unxyhko3-project-674-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` //! WASM-EXECUTION: `Compiled`, CHAIN: `Some("bridge-hub-rococo-dev")`, DB CACHE: 1024 // Executed Command: @@ -54,8 +54,8 @@ impl pallet_balances::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `0` // Estimated: `3593` - // Minimum execution time: 41_696_000 picoseconds. - Weight::from_parts(42_201_000, 0) + // Minimum execution time: 41_898_000 picoseconds. + Weight::from_parts(42_690_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 +66,8 @@ impl pallet_balances::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `0` // Estimated: `3593` - // Minimum execution time: 32_855_000 picoseconds. - Weight::from_parts(33_554_000, 0) + // Minimum execution time: 32_745_000 picoseconds. + Weight::from_parts(33_686_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 +78,8 @@ impl pallet_balances::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `174` // Estimated: `3593` - // Minimum execution time: 12_977_000 picoseconds. - Weight::from_parts(13_473_000, 0) + // Minimum execution time: 13_352_000 picoseconds. + Weight::from_parts(13_808_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 +90,8 @@ impl pallet_balances::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `174` // Estimated: `3593` - // Minimum execution time: 17_617_000 picoseconds. - Weight::from_parts(18_234_000, 0) + // Minimum execution time: 18_248_000 picoseconds. + Weight::from_parts(18_763_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 +102,8 @@ impl pallet_balances::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `103` // Estimated: `6196` - // Minimum execution time: 43_174_000 picoseconds. - Weight::from_parts(43_685_000, 0) + // Minimum execution time: 43_626_000 picoseconds. + Weight::from_parts(45_333_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 +114,8 @@ impl pallet_balances::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `0` // Estimated: `3593` - // Minimum execution time: 41_125_000 picoseconds. - Weight::from_parts(41_636_000, 0) + // Minimum execution time: 41_702_000 picoseconds. + Weight::from_parts(43_366_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 +126,8 @@ impl pallet_balances::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `174` // Estimated: `3593` - // Minimum execution time: 15_749_000 picoseconds. - Weight::from_parts(16_163_000, 0) + // Minimum execution time: 15_944_000 picoseconds. + Weight::from_parts(16_512_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 +139,11 @@ impl pallet_balances::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `0 + u * (136 ±0)` // Estimated: `990 + u * (2603 ±0)` - // Minimum execution time: 14_238_000 picoseconds. - Weight::from_parts(14_469_000, 0) + // Minimum execution time: 14_351_000 picoseconds. + Weight::from_parts(14_568_000, 0) .saturating_add(Weight::from_parts(0, 990)) - // Standard Error: 11_818 - .saturating_add(Weight::from_parts(12_621_051, 0).saturating_mul(u.into())) + // Standard Error: 11_289 + .saturating_add(Weight::from_parts(13_163_759, 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,9 +154,25 @@ impl pallet_balances::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `0` // Estimated: `1501` - // Minimum execution time: 4_904_000 picoseconds. - Weight::from_parts(5_459_000, 0) + // Minimum execution time: 5_174_000 picoseconds. + Weight::from_parts(5_490_000, 0) .saturating_add(Weight::from_parts(0, 1501)) .saturating_add(T::DbWeight::get().reads(1)) } + fn burn_allow_death() -> Weight { + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 26_681_000 picoseconds. + Weight::from_parts(27_705_000, 0) + .saturating_add(Weight::from_parts(0, 0)) + } + fn burn_keep_alive() -> Weight { + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 18_105_000 picoseconds. + Weight::from_parts(19_246_000, 0) + .saturating_add(Weight::from_parts(0, 0)) + } } 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 adfaa9ea2028e4b8880e17a1ccc471beb64c9a3c..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 @@ -17,9 +17,9 @@ //! Autogenerated weights for `pallet_xcm` //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 32.0.0 -//! DATE: 2024-03-21, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! DATE: 2024-02-20, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` //! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `runner-h2rr8wx7-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,30 +64,8 @@ impl pallet_xcm::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `38` // Estimated: `3503` - // Minimum execution time: 18_732_000 picoseconds. - Weight::from_parts(19_386_000, 0) - .saturating_add(Weight::from_parts(0, 3503)) - .saturating_add(T::DbWeight::get().reads(6)) - .saturating_add(T::DbWeight::get().writes(2)) - } - /// Storage: `ParachainSystem::UpwardDeliveryFeeFactor` (r:1 w:0) - /// Proof: `ParachainSystem::UpwardDeliveryFeeFactor` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - /// Storage: `PolkadotXcm::SupportedVersion` (r:1 w:0) - /// Proof: `PolkadotXcm::SupportedVersion` (`max_values`: None, `max_size`: None, mode: `Measured`) - /// Storage: `PolkadotXcm::VersionDiscoveryQueue` (r:1 w:1) - /// Proof: `PolkadotXcm::VersionDiscoveryQueue` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - /// Storage: `PolkadotXcm::SafeXcmVersion` (r:1 w:0) - /// Proof: `PolkadotXcm::SafeXcmVersion` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - /// Storage: `ParachainSystem::HostConfiguration` (r:1 w:0) - /// Proof: `ParachainSystem::HostConfiguration` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - /// Storage: `ParachainSystem::PendingUpwardMessages` (r:1 w:1) - /// Proof: `ParachainSystem::PendingUpwardMessages` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - fn send_blob() -> Weight { - // Proof Size summary in bytes: - // Measured: `38` - // Estimated: `3503` - // Minimum execution time: 18_943_000 picoseconds. - Weight::from_parts(19_455_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)) @@ -112,8 +90,8 @@ impl pallet_xcm::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `70` // Estimated: `3593` - // Minimum execution time: 88_917_000 picoseconds. - Weight::from_parts(91_611_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)) @@ -148,8 +126,8 @@ impl pallet_xcm::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `70` // Estimated: `3593` - // Minimum execution time: 88_587_000 picoseconds. - Weight::from_parts(90_303_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)) @@ -164,24 +142,14 @@ 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 execute_blob() -> 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: `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: 5_856_000 picoseconds. - Weight::from_parts(6_202_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)) } @@ -191,8 +159,8 @@ impl pallet_xcm::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_797_000 picoseconds. - Weight::from_parts(1_970_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)) } @@ -218,8 +186,8 @@ impl pallet_xcm::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `38` // Estimated: `3503` - // Minimum execution time: 24_479_000 picoseconds. - Weight::from_parts(25_058_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)) @@ -244,8 +212,8 @@ impl pallet_xcm::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `255` // Estimated: `3720` - // Minimum execution time: 27_282_000 picoseconds. - Weight::from_parts(27_924_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)) @@ -256,8 +224,8 @@ impl pallet_xcm::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_801_000 picoseconds. - Weight::from_parts(1_988_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)) } @@ -267,8 +235,8 @@ impl pallet_xcm::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `89` // Estimated: `13454` - // Minimum execution time: 16_509_000 picoseconds. - Weight::from_parts(16_939_000, 0) + // 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)) @@ -279,8 +247,8 @@ impl pallet_xcm::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `93` // Estimated: `13458` - // Minimum execution time: 16_140_000 picoseconds. - Weight::from_parts(16_843_000, 0) + // 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)) @@ -291,8 +259,8 @@ impl pallet_xcm::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `106` // Estimated: `15946` - // Minimum execution time: 18_160_000 picoseconds. - Weight::from_parts(18_948_000, 0) + // 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)) } @@ -314,8 +282,8 @@ impl pallet_xcm::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `106` // Estimated: `6046` - // Minimum execution time: 24_409_000 picoseconds. - Weight::from_parts(25_261_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)) @@ -326,8 +294,8 @@ impl pallet_xcm::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `136` // Estimated: `11026` - // Minimum execution time: 10_848_000 picoseconds. - Weight::from_parts(11_241_000, 0) + // 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)) } @@ -337,8 +305,8 @@ impl pallet_xcm::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `100` // Estimated: `13465` - // Minimum execution time: 16_609_000 picoseconds. - Weight::from_parts(17_044_000, 0) + // 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)) @@ -361,8 +329,8 @@ impl pallet_xcm::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `106` // Estimated: `13471` - // Minimum execution time: 32_500_000 picoseconds. - Weight::from_parts(33_475_000, 0) + // 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)) @@ -375,8 +343,8 @@ impl pallet_xcm::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `32` // Estimated: `1517` - // Minimum execution time: 3_484_000 picoseconds. - Weight::from_parts(3_673_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)) @@ -387,8 +355,8 @@ impl pallet_xcm::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `7669` // Estimated: `11134` - // Minimum execution time: 25_225_000 picoseconds. - Weight::from_parts(25_731_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)) @@ -399,8 +367,8 @@ impl pallet_xcm::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `90` // Estimated: `3555` - // Minimum execution time: 33_961_000 picoseconds. - Weight::from_parts(34_818_000, 0) + // 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 063c999aa7ad740fe225cc22ee62f685f1bb35aa..a0d2e91dffd2e9240ad9364e18ef52a7b3cab3b1 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 @@ -19,22 +19,12 @@ use super::{ ParachainSystem, PolkadotXcm, Runtime, RuntimeCall, RuntimeEvent, RuntimeOrigin, TransactionByteFee, WeightToFee, XcmpQueue, }; -use crate::{ - bridge_common_config::{ - BridgeGrandpaRococoBulletinInstance, BridgeGrandpaWestendInstance, - BridgeParachainWestendInstance, DeliveryRewardInBalance, RequiredStakeForStakeAndSlash, - }, - bridge_to_bulletin_config::WithRococoBulletinMessagesInstance, - bridge_to_westend_config::WithBridgeHubWestendMessagesInstance, - EthereumGatewayAddress, -}; use bp_messages::LaneId; use bp_relayers::{PayRewardFromAccount, RewardsAccountOwner, RewardsAccountParams}; use bp_runtime::ChainId; use frame_support::{ parameter_types, traits::{tokens::imbalance::ResolveTo, ConstU32, Contains, Equals, Everything, Nothing}, - StoragePrefixedMap, }; use frame_system::EnsureRoot; use pallet_collator_selection::StakingPotAccountId; @@ -56,15 +46,16 @@ use testnet_parachains_constants::rococo::snowbridge::EthereumNetwork; use xcm::latest::prelude::*; use xcm_builder::{ deposit_or_burn_fee, AccountId32Aliases, AllowExplicitUnpaidExecutionFrom, - AllowKnownQueryResponses, AllowSubscriptionsFrom, AllowTopLevelPaidExecutionFrom, - DenyReserveTransferToRelayChain, DenyThenTry, EnsureXcmOrigin, FrameTransactionalProcessor, - FungibleAdapter, HandleFee, IsConcrete, ParentAsSuperuser, ParentIsPreset, RelayChainAsNative, - SiblingParachainAsNative, SiblingParachainConvertsVia, SignedAccountId32AsNative, - SignedToAccountId32, SovereignSignedViaLocation, TakeWeightCredit, TrailingSetTopicAsId, - UsingComponents, WeightInfoBounds, WithComputedOrigin, WithUniqueTopic, XcmFeeToAccount, + AllowHrmpNotificationsFromRelayChain, AllowKnownQueryResponses, AllowSubscriptionsFrom, + AllowTopLevelPaidExecutionFrom, 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}, + traits::{FeeManager, FeeReason, FeeReason::Export, TransactAsset}, XcmExecutor, }; @@ -138,104 +129,6 @@ impl Contains for ParentOrParentsPlurality { } } -/// A call filter for the XCM Transact instruction. This is a temporary measure until we properly -/// account for proof size weights. -/// -/// Calls that are allowed through this filter must: -/// 1. Have a fixed weight; -/// 2. Cannot lead to another call being made; -/// 3. Have a defined proof size weight, e.g. no unbounded vecs in call parameters. -pub struct SafeCallFilter; -impl Contains for SafeCallFilter { - fn contains(call: &RuntimeCall) -> bool { - #[cfg(feature = "runtime-benchmarks")] - { - if matches!(call, RuntimeCall::System(frame_system::Call::remark_with_event { .. })) { - return true - } - } - - // Allow to change dedicated storage items (called by governance-like) - match call { - RuntimeCall::System(frame_system::Call::set_storage { items }) - if items.iter().all(|(k, _)| { - k.eq(&DeliveryRewardInBalance::key()) || - k.eq(&RequiredStakeForStakeAndSlash::key()) || - k.eq(&EthereumGatewayAddress::key()) || - // Allow resetting of Ethereum nonces in Rococo only. - k.starts_with(&snowbridge_pallet_inbound_queue::Nonce::::final_prefix()) || - k.starts_with(&snowbridge_pallet_outbound_queue::Nonce::::final_prefix()) - }) => - return true, - _ => (), - }; - - matches!( - call, - RuntimeCall::PolkadotXcm( - pallet_xcm::Call::force_xcm_version { .. } | - 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 { .. }, - ) | RuntimeCall::ParachainSystem(..) | - RuntimeCall::Timestamp(..) | - RuntimeCall::Balances(..) | - RuntimeCall::CollatorSelection(..) | - RuntimeCall::Session(pallet_session::Call::purge_keys { .. }) | - RuntimeCall::XcmpQueue(..) | - RuntimeCall::MessageQueue(..) | - RuntimeCall::BridgeWestendGrandpa(pallet_bridge_grandpa::Call::< - Runtime, - BridgeGrandpaWestendInstance, - >::initialize { .. }) | - RuntimeCall::BridgeWestendGrandpa(pallet_bridge_grandpa::Call::< - Runtime, - BridgeGrandpaWestendInstance, - >::set_operating_mode { .. }) | - RuntimeCall::BridgeWestendParachains(pallet_bridge_parachains::Call::< - Runtime, - BridgeParachainWestendInstance, - >::set_operating_mode { .. }) | - RuntimeCall::BridgeWestendMessages(pallet_bridge_messages::Call::< - Runtime, - WithBridgeHubWestendMessagesInstance, - >::set_operating_mode { .. }) | - RuntimeCall::BridgePolkadotBulletinGrandpa(pallet_bridge_grandpa::Call::< - Runtime, - BridgeGrandpaRococoBulletinInstance, - >::initialize { .. }) | - RuntimeCall::BridgePolkadotBulletinGrandpa(pallet_bridge_grandpa::Call::< - Runtime, - BridgeGrandpaRococoBulletinInstance, - >::set_operating_mode { .. }) | - RuntimeCall::BridgePolkadotBulletinMessages(pallet_bridge_messages::Call::< - Runtime, - WithRococoBulletinMessagesInstance, - >::set_operating_mode { .. }) | - RuntimeCall::EthereumBeaconClient( - snowbridge_pallet_ethereum_client::Call::force_checkpoint { .. } | - snowbridge_pallet_ethereum_client::Call::set_operating_mode { .. }, - ) | RuntimeCall::EthereumInboundQueue( - snowbridge_pallet_inbound_queue::Call::set_operating_mode { .. }, - ) | RuntimeCall::EthereumOutboundQueue( - snowbridge_pallet_outbound_queue::Call::set_operating_mode { .. }, - ) | RuntimeCall::EthereumSystem( - snowbridge_pallet_system::Call::upgrade { .. } | - snowbridge_pallet_system::Call::set_operating_mode { .. } | - snowbridge_pallet_system::Call::set_pricing_parameters { .. } | - snowbridge_pallet_system::Call::force_update_channel { .. } | - snowbridge_pallet_system::Call::force_transfer_native_from_agent { .. } | - snowbridge_pallet_system::Call::set_token_transfer_fees { .. }, - ) - ) - } -} - pub type Barrier = TrailingSetTopicAsId< DenyThenTry< DenyReserveTransferToRelayChain, @@ -258,6 +151,8 @@ pub type Barrier = TrailingSetTopicAsId< )>, // Subscriptions for version tracking are OK. AllowSubscriptionsFrom, + // HRMP notifications from the relay chain are OK. + AllowHrmpNotificationsFromRelayChain, ), UniversalLocation, ConstU32<8>, @@ -337,13 +232,14 @@ impl xcm_executor::Config for XcmConfig { crate::bridge_to_ethereum_config::SnowbridgeExporter, ); type UniversalAliases = Nothing; - type CallDispatcher = WithOriginFilter; - type SafeCallFilter = SafeCallFilter; + type CallDispatcher = RuntimeCall; + type SafeCallFilter = Everything; type Aliasers = Nothing; type TransactionalProcessor = FrameTransactionalProcessor; type HrmpNewChannelOpenRequestHandler = (); type HrmpChannelAcceptedHandler = (); type HrmpChannelClosingHandler = (); + type XcmRecorder = PolkadotXcm; } pub type PriceForParentDelivery = 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 776c505fa640fa956ae07e9928ccf2f9293e80dd..b309232825db3aa964b2fa1a1d8d739f06ec3153 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 @@ -80,11 +80,10 @@ fn construct_and_apply_extrinsic( r.unwrap() } -fn construct_and_estimate_extrinsic_fee(batch: pallet_utility::Call) -> Balance { - let batch_call = RuntimeCall::Utility(batch); - let batch_info = batch_call.get_dispatch_info(); - let xt = construct_extrinsic(Alice, batch_call); - TransactionPayment::compute_fee(xt.encoded_size() as _, &batch_info, 0) +fn construct_and_estimate_extrinsic_fee(call: RuntimeCall) -> Balance { + let info = call.get_dispatch_info(); + let xt = construct_extrinsic(Alice, call); + TransactionPayment::compute_fee(xt.encoded_size() as _, &info, 0) } fn collator_session_keys() -> bridge_hub_test_utils::CollatorSessionKeys { @@ -376,20 +375,20 @@ mod bridge_hub_westend_tests { } #[test] - pub fn complex_relay_extrinsic_works() { - // for Westend - from_parachain::complex_relay_extrinsic_works::( + fn free_relay_extrinsic_works() { + // from Westend + from_parachain::free_relay_extrinsic_works::( collator_session_keys(), slot_durations(), bp_bridge_hub_rococo::BRIDGE_HUB_ROCOCO_PARACHAIN_ID, bp_bridge_hub_westend::BRIDGE_HUB_WESTEND_PARACHAIN_ID, - SIBLING_PARACHAIN_ID, BridgeHubWestendChainId::get(), + SIBLING_PARACHAIN_ID, Rococo, XCM_LANE_FOR_ASSET_HUB_ROCOCO_TO_ASSET_HUB_WESTEND, || (), construct_and_apply_extrinsic, - ); + ) } #[test] @@ -414,12 +413,12 @@ mod bridge_hub_westend_tests { } #[test] - pub fn can_calculate_fee_for_complex_message_delivery_transaction() { + fn can_calculate_fee_for_standalone_message_delivery_transaction() { bridge_hub_test_utils::check_sane_fees_values( "bp_bridge_hub_rococo::BridgeHubRococoBaseDeliveryFeeInRocs", bp_bridge_hub_rococo::BridgeHubRococoBaseDeliveryFeeInRocs::get(), || { - from_parachain::can_calculate_fee_for_complex_message_delivery_transaction::< + from_parachain::can_calculate_fee_for_standalone_message_delivery_transaction::< RuntimeTestsAdapter, >(collator_session_keys(), construct_and_estimate_extrinsic_fee) }, @@ -433,12 +432,12 @@ mod bridge_hub_westend_tests { } #[test] - pub fn can_calculate_fee_for_complex_message_confirmation_transaction() { + fn can_calculate_fee_for_standalone_message_confirmation_transaction() { bridge_hub_test_utils::check_sane_fees_values( "bp_bridge_hub_rococo::BridgeHubRococoBaseConfirmationFeeInRocs", bp_bridge_hub_rococo::BridgeHubRococoBaseConfirmationFeeInRocs::get(), || { - from_parachain::can_calculate_fee_for_complex_message_confirmation_transaction::< + from_parachain::can_calculate_fee_for_standalone_message_confirmation_transaction::< RuntimeTestsAdapter, >(collator_session_keys(), construct_and_estimate_extrinsic_fee) }, @@ -581,28 +580,28 @@ mod bridge_hub_bulletin_tests { } #[test] - pub fn complex_relay_extrinsic_works() { - // for Bulletin - from_grandpa_chain::complex_relay_extrinsic_works::( + fn free_relay_extrinsic_works() { + // from Bulletin + from_grandpa_chain::free_relay_extrinsic_works::( collator_session_keys(), slot_durations(), bp_bridge_hub_rococo::BRIDGE_HUB_ROCOCO_PARACHAIN_ID, - SIBLING_PARACHAIN_ID, RococoBulletinChainId::get(), + SIBLING_PARACHAIN_ID, Rococo, XCM_LANE_FOR_ROCOCO_PEOPLE_TO_ROCOCO_BULLETIN, || (), construct_and_apply_extrinsic, - ); + ) } #[test] - pub fn can_calculate_fee_for_complex_message_delivery_transaction() { + pub fn can_calculate_fee_for_standalone_message_delivery_transaction() { bridge_hub_test_utils::check_sane_fees_values( "bp_bridge_hub_rococo::BridgeHubRococoBaseDeliveryFeeInRocs", bp_bridge_hub_rococo::BridgeHubRococoBaseDeliveryFeeInRocs::get(), || { - from_grandpa_chain::can_calculate_fee_for_complex_message_delivery_transaction::< + from_grandpa_chain::can_calculate_fee_for_standalone_message_delivery_transaction::< RuntimeTestsAdapter, >(collator_session_keys(), construct_and_estimate_extrinsic_fee) }, @@ -617,12 +616,12 @@ mod bridge_hub_bulletin_tests { } #[test] - pub fn can_calculate_fee_for_complex_message_confirmation_transaction() { + pub fn can_calculate_fee_for_standalone_message_confirmation_transaction() { bridge_hub_test_utils::check_sane_fees_values( "bp_bridge_hub_rococo::BridgeHubRococoBaseConfirmationFeeInRocs", bp_bridge_hub_rococo::BridgeHubRococoBaseConfirmationFeeInRocs::get(), || { - from_grandpa_chain::can_calculate_fee_for_complex_message_confirmation_transaction::< + from_grandpa_chain::can_calculate_fee_for_standalone_message_confirmation_transaction::< RuntimeTestsAdapter, >(collator_session_keys(), construct_and_estimate_extrinsic_fee) }, 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 86560caca99ca344065373330638c3232a417f21..3fbb95a17d04744c896047554c3ceb1b1e610676 100644 --- a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/Cargo.toml +++ b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/Cargo.toml @@ -13,11 +13,12 @@ workspace = true 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.6.12", default-features = false, features = ["derive"] } hex-literal = { version = "0.4.1" } log = { workspace = true } scale-info = { version = "2.11.1", default-features = false, features = ["derive"] } serde = { optional = true, features = ["derive"], workspace = true, default-features = true } +tuplex = { version = "0.1", default-features = false } # Substrate frame-benchmarking = { path = "../../../../../substrate/frame/benchmarking", default-features = false, optional = true } @@ -180,6 +181,7 @@ std = [ "sp-version/std", "substrate-wasm-builder", "testnet-parachains-constants/std", + "tuplex/std", "westend-runtime-constants/std", "xcm-builder/std", "xcm-executor/std", 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 d5da41cce2860c8b12db49f1defc5a6764bc6535..425b53da30fc8a176fcddfe145fab66a41b60f8a 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 @@ -26,8 +26,8 @@ use bp_parachains::SingleParaStoredHeaderDataBuilder; use bp_runtime::Chain; use bridge_runtime_common::{ extensions::refund_relayer_extension::{ - ActualFeeRefund, RefundBridgedParachainMessages, RefundSignedExtensionAdapter, - RefundableMessagesLane, RefundableParachain, + ActualFeeRefund, RefundBridgedMessages, RefundSignedExtensionAdapter, + RefundableMessagesLane, }, messages, messages::{ @@ -70,6 +70,10 @@ parameter_types! { 2, [GlobalConsensus(RococoGlobalConsensusNetwork::get())] ); + // see the `FEE_BOOST_PER_RELAY_HEADER` constant get the meaning of this value + pub PriorityBoostPerRelayHeader: u64 = 32_007_814_407_814; + // see the `FEE_BOOST_PER_PARACHAIN_HEADER` constant get the meaning of this value + pub PriorityBoostPerParachainHeader: u64 = 1_396_340_903_540_903; // see the `FEE_BOOST_PER_MESSAGE` constant to get the meaning of this value pub PriorityBoostPerMessage: u64 = 182_044_444_444_444; @@ -191,9 +195,8 @@ impl ThisChainWithMessages for BridgeHubWestend { /// Signed extension that refunds relayers that are delivering messages from the Rococo parachain. pub type OnBridgeHubWestendRefundBridgeHubRococoMessages = RefundSignedExtensionAdapter< - RefundBridgedParachainMessages< + RefundBridgedMessages< Runtime, - RefundableParachain, RefundableMessagesLane< WithBridgeHubRococoMessagesInstance, AssetHubWestendToAssetHubRococoMessagesLane, @@ -210,7 +213,8 @@ pub type BridgeGrandpaRococoInstance = pallet_bridge_grandpa::Instance1; impl pallet_bridge_grandpa::Config for Runtime { type RuntimeEvent = RuntimeEvent; type BridgedChain = bp_rococo::Rococo; - type MaxFreeMandatoryHeadersPerBlock = ConstU32<4>; + type MaxFreeHeadersPerBlock = ConstU32<4>; + type FreeHeadersInterval = ConstU32<5>; type HeadersToKeep = RelayChainHeadersToKeep; type WeightInfo = weights::pallet_bridge_grandpa::WeightInfo; } @@ -281,6 +285,7 @@ mod tests { use super::*; use bridge_runtime_common::{ assert_complete_bridge_types, + extensions::refund_relayer_extension::RefundableParachain, integrity::{ assert_complete_bridge_constants, check_message_lane_weights, AssertBridgeMessagesPalletConstants, AssertBridgePalletNames, AssertChainConstants, @@ -301,6 +306,11 @@ mod tests { /// operational costs and a faster bridge), so this value should be significant. const FEE_BOOST_PER_MESSAGE: Balance = 2 * westend::currency::UNITS; + // see `FEE_BOOST_PER_MESSAGE` comment + const FEE_BOOST_PER_RELAY_HEADER: Balance = 2 * westend::currency::UNITS; + // see `FEE_BOOST_PER_MESSAGE` comment + const FEE_BOOST_PER_PARACHAIN_HEADER: Balance = 2 * westend::currency::UNITS; + #[test] fn ensure_bridge_hub_westend_message_lane_weights_are_correct() { check_message_lane_weights::< @@ -352,7 +362,19 @@ mod tests { }, }); - bridge_runtime_common::extensions::priority_calculator::ensure_priority_boost_is_sane::< + bridge_runtime_common::extensions::priority_calculator::per_relay_header::ensure_priority_boost_is_sane::< + Runtime, + BridgeGrandpaRococoInstance, + PriorityBoostPerRelayHeader, + >(FEE_BOOST_PER_RELAY_HEADER); + + bridge_runtime_common::extensions::priority_calculator::per_parachain_header::ensure_priority_boost_is_sane::< + Runtime, + RefundableParachain, + PriorityBoostPerParachainHeader, + >(FEE_BOOST_PER_PARACHAIN_HEADER); + + bridge_runtime_common::extensions::priority_calculator::per_message::ensure_priority_boost_is_sane::< Runtime, WithBridgeHubRococoMessagesInstance, PriorityBoostPerMessage, 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 b4ea2c79f64f1d87de2747191759c9e9990db3ba..50911b4d780fd2a553c1f7eac2f3b7146765cb15 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 @@ -32,6 +32,12 @@ pub mod bridge_to_rococo_config; mod weights; pub mod xcm_config; +use bridge_runtime_common::extensions::{ + check_obsolete_extension::{ + CheckAndBoostBridgeGrandpaTransactions, CheckAndBoostBridgeParachainsTransactions, + }, + refund_relayer_extension::RefundableParachain, +}; use cumulus_pallet_parachain_system::RelayNumberMonotonicallyIncreases; use cumulus_primitives_core::ParaId; use sp_api::impl_runtime_apis; @@ -57,7 +63,7 @@ use frame_support::{ dispatch::DispatchClass, genesis_builder_helper::{build_state, get_preset}, parameter_types, - traits::{ConstBool, ConstU32, ConstU64, ConstU8, TransformOrigin}, + traits::{ConstBool, ConstU32, ConstU64, ConstU8, Get, TransformOrigin}, weights::{ConstantMultiplier, Weight}, PalletId, }; @@ -118,11 +124,12 @@ pub type UncheckedExtrinsic = /// Migrations to apply on runtime upgrade. pub type Migrations = ( - pallet_collator_selection::migration::v1::MigrateToV1, + pallet_collator_selection::migration::v2::MigrationToV2, pallet_multisig::migrations::v1::MigrateToV1, InitStorageVersions, // unreleased cumulus_pallet_xcmp_queue::migration::v4::MigrationToV4, + cumulus_pallet_xcmp_queue::migration::v5::MigrateV4ToV5, // permanent pallet_xcm::migration::MigrateToLatestXcmVersion, ); @@ -177,10 +184,10 @@ 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_010_000, + spec_version: 1_011_000, impl_version: 0, apis: RUNTIME_API_VERSIONS, - transaction_version: 4, + transaction_version: 5, state_version: 1, }; @@ -346,7 +353,7 @@ impl pallet_message_queue::Config for Runtime { // The XCMP queue pallet is only ever able to handle the `Sibling(ParaId)` origin: type QueueChangeHandler = NarrowOriginToSibling; type QueuePausedQuery = NarrowOriginToSibling; - type HeapSize = sp_core::ConstU32<{ 64 * 1024 }>; + type HeapSize = sp_core::ConstU32<{ 103 * 1024 }>; type MaxStale = sp_core::ConstU32<8>; type ServiceWeight = MessageQueueServiceWeight; type IdleMaxServiceWeight = MessageQueueServiceWeight; @@ -373,13 +380,22 @@ impl cumulus_pallet_xcmp_queue::Config for Runtime { type ChannelInfo = ParachainSystem; type VersionWrapper = PolkadotXcm; type XcmpQueue = TransformOrigin; - type MaxInboundSuspended = sp_core::ConstU32<1_000>; + type MaxInboundSuspended = ConstU32<1_000>; + type MaxActiveOutboundChannels = ConstU32<128>; + // Most on-chain HRMP channels are configured to use 102400 bytes of max message size, so we + // need to set the page size larger than that until we reduce the channel size on-chain. + type MaxPageSize = ConstU32<{ 103 * 1024 }>; type ControllerOrigin = EnsureRoot; type ControllerOriginConverter = XcmOriginToTransactDispatchOrigin; type WeightInfo = weights::cumulus_pallet_xcmp_queue::WeightInfo; type PriceForSiblingDelivery = PriceForSiblingParachainDelivery; } +impl cumulus_pallet_xcmp_queue::migration::v5::V5Config for Runtime { + // This must be the same as the `ChannelInfo` from the `Config`: + type ChannelList = ParachainSystem; +} + parameter_types! { pub const RelayOrigin: AggregateMessageOrigin = AggregateMessageOrigin::Parent; } @@ -502,9 +518,22 @@ construct_runtime!( bridge_runtime_common::generate_bridge_reject_obsolete_headers_and_messages! { RuntimeCall, AccountId, // Grandpa - BridgeRococoGrandpa, + CheckAndBoostBridgeGrandpaTransactions< + Runtime, + bridge_to_rococo_config::BridgeGrandpaRococoInstance, + bridge_to_rococo_config::PriorityBoostPerRelayHeader, + xcm_config::TreasuryAccount, + >, // Parachains - BridgeRococoParachains, + CheckAndBoostBridgeParachainsTransactions< + Runtime, + RefundableParachain< + bridge_to_rococo_config::BridgeParachainRococoInstance, + bp_bridge_hub_rococo::BridgeHubRococo, + >, + bridge_to_rococo_config::PriorityBoostPerParachainHeader, + xcm_config::TreasuryAccount, + >, // Messages BridgeRococoMessages } @@ -692,6 +721,11 @@ impl_runtime_apis! { fn best_finalized() -> Option> { BridgeRococoGrandpa::best_finalized() } + fn free_headers_interval() -> Option { + >::FreeHeadersInterval::get() + } fn synced_headers_grandpa_info( ) -> Vec> { BridgeRococoGrandpa::synced_headers_grandpa_info() @@ -704,6 +738,10 @@ impl_runtime_apis! { bp_bridge_hub_rococo::BridgeHubRococo >().unwrap_or(None) } + fn free_headers_interval() -> Option { + // "free interval" is not currently used for parachains + None + } } impl bp_bridge_hub_rococo::FromBridgeHubRococoInboundLaneApi for Runtime { 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..245daaf8ed91b69db2a604c51e394c2d768b1c26 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 @@ -17,8 +17,10 @@ //! Expose the auto generated weight files. +use ::pallet_bridge_grandpa::WeightInfoExt as GrandpaWeightInfoExt; use ::pallet_bridge_messages::WeightInfoExt as MessagesWeightInfoExt; use ::pallet_bridge_parachains::WeightInfoExt as ParachainsWeightInfoExt; +use ::pallet_bridge_relayers::WeightInfo as _; pub mod block_weights; pub mod cumulus_pallet_parachain_system; @@ -51,6 +53,16 @@ use frame_support::weights::Weight; // import trait from dependency module use ::pallet_bridge_relayers::WeightInfoExt as _; +impl GrandpaWeightInfoExt for pallet_bridge_grandpa::WeightInfo { + fn submit_finality_proof_overhead_from_runtime() -> Weight { + // our signed extension: + // 1) checks whether relayer registration is active from validate/pre_dispatch; + // 2) may slash and deregister relayer from post_dispatch + // (2) includes (1), so (2) is the worst case + pallet_bridge_relayers::WeightInfo::::slash_and_deregister() + } +} + impl MessagesWeightInfoExt for pallet_bridge_messages::WeightInfo { fn expected_extra_storage_proof_size() -> u32 { bp_bridge_hub_rococo::EXTRA_STORAGE_PROOF_SIZE @@ -70,4 +82,12 @@ impl ParachainsWeightInfoExt for pallet_bridge_parachains::WeightInfo u32 { bp_bridge_hub_rococo::EXTRA_STORAGE_PROOF_SIZE } + + fn submit_parachain_heads_overhead_from_runtime() -> Weight { + // our signed extension: + // 1) checks whether relayer registration is active from validate/pre_dispatch; + // 2) may slash and deregister relayer from post_dispatch + // (2) includes (1), so (2) is the worst case + pallet_bridge_relayers::WeightInfo::::slash_and_deregister() + } } diff --git a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/src/weights/pallet_balances.rs b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/src/weights/pallet_balances.rs index 3afef6564bdb8fec4e435948cf8cadb928bbf773..34ce487216f24f0a93ecec89610f298c4c9eae35 100644 --- a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/src/weights/pallet_balances.rs +++ b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/src/weights/pallet_balances.rs @@ -17,9 +17,9 @@ //! 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-05-06, 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-unxyhko3-project-674-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` //! WASM-EXECUTION: `Compiled`, CHAIN: `Some("bridge-hub-westend-dev")`, DB CACHE: 1024 // Executed Command: @@ -54,8 +54,8 @@ impl pallet_balances::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `0` // Estimated: `3593` - // Minimum execution time: 42_912_000 picoseconds. - Weight::from_parts(43_690_000, 0) + // Minimum execution time: 42_637_000 picoseconds. + Weight::from_parts(44_357_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 +66,8 @@ impl pallet_balances::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `0` // Estimated: `3593` - // Minimum execution time: 33_823_000 picoseconds. - Weight::from_parts(34_415_000, 0) + // Minimum execution time: 33_463_000 picoseconds. + Weight::from_parts(34_484_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 +78,8 @@ impl pallet_balances::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `174` // Estimated: `3593` - // Minimum execution time: 13_226_000 picoseconds. - Weight::from_parts(13_557_000, 0) + // Minimum execution time: 13_115_000 picoseconds. + Weight::from_parts(13_749_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 +90,8 @@ impl pallet_balances::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `174` // Estimated: `3593` - // Minimum execution time: 18_055_000 picoseconds. - Weight::from_parts(18_407_000, 0) + // Minimum execution time: 17_825_000 picoseconds. + Weight::from_parts(18_471_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 +102,8 @@ impl pallet_balances::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `103` // Estimated: `6196` - // Minimum execution time: 44_442_000 picoseconds. - Weight::from_parts(45_101_000, 0) + // Minimum execution time: 43_669_000 picoseconds. + Weight::from_parts(45_781_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 +114,8 @@ impl pallet_balances::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `0` // Estimated: `3593` - // Minimum execution time: 42_485_000 picoseconds. - Weight::from_parts(43_157_000, 0) + // Minimum execution time: 41_572_000 picoseconds. + Weight::from_parts(43_812_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 +126,8 @@ impl pallet_balances::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `174` // Estimated: `3593` - // Minimum execution time: 16_002_000 picoseconds. - Weight::from_parts(16_425_000, 0) + // Minimum execution time: 15_538_000 picoseconds. + Weight::from_parts(16_227_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 +139,11 @@ impl pallet_balances::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `0 + u * (136 ±0)` // Estimated: `990 + u * (2603 ±0)` - // Minimum execution time: 14_526_000 picoseconds. - Weight::from_parts(14_825_000, 0) + // Minimum execution time: 13_979_000 picoseconds. + Weight::from_parts(14_195_000, 0) .saturating_add(Weight::from_parts(0, 990)) - // Standard Error: 10_967 - .saturating_add(Weight::from_parts(13_376_293, 0).saturating_mul(u.into())) + // Standard Error: 11_039 + .saturating_add(Weight::from_parts(13_102_916, 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,9 +154,25 @@ impl pallet_balances::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `0` // Estimated: `1501` - // Minimum execution time: 5_151_000 picoseconds. - Weight::from_parts(5_419_000, 0) + // Minimum execution time: 4_959_000 picoseconds. + Weight::from_parts(5_377_000, 0) .saturating_add(Weight::from_parts(0, 1501)) .saturating_add(T::DbWeight::get().reads(1)) } + fn burn_allow_death() -> Weight { + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 26_604_000 picoseconds. + Weight::from_parts(27_641_000, 0) + .saturating_add(Weight::from_parts(0, 0)) + } + fn burn_keep_alive() -> Weight { + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 18_106_000 picoseconds. + Weight::from_parts(18_637_000, 0) + .saturating_add(Weight::from_parts(0, 0)) + } } 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 9cf4c61466a1bd37ffea56681648b2c2e2ce4555..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 @@ -17,9 +17,9 @@ //! Autogenerated weights for `pallet_xcm` //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 32.0.0 -//! DATE: 2024-03-22, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! DATE: 2024-02-20, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` //! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `runner-h2rr8wx7-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,30 +64,8 @@ impl pallet_xcm::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `38` // Estimated: `3503` - // Minimum execution time: 19_702_000 picoseconds. - Weight::from_parts(20_410_000, 0) - .saturating_add(Weight::from_parts(0, 3503)) - .saturating_add(T::DbWeight::get().reads(6)) - .saturating_add(T::DbWeight::get().writes(2)) - } - /// Storage: `ParachainSystem::UpwardDeliveryFeeFactor` (r:1 w:0) - /// Proof: `ParachainSystem::UpwardDeliveryFeeFactor` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - /// Storage: `PolkadotXcm::SupportedVersion` (r:1 w:0) - /// Proof: `PolkadotXcm::SupportedVersion` (`max_values`: None, `max_size`: None, mode: `Measured`) - /// Storage: `PolkadotXcm::VersionDiscoveryQueue` (r:1 w:1) - /// Proof: `PolkadotXcm::VersionDiscoveryQueue` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - /// Storage: `PolkadotXcm::SafeXcmVersion` (r:1 w:0) - /// Proof: `PolkadotXcm::SafeXcmVersion` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - /// Storage: `ParachainSystem::HostConfiguration` (r:1 w:0) - /// Proof: `ParachainSystem::HostConfiguration` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - /// Storage: `ParachainSystem::PendingUpwardMessages` (r:1 w:1) - /// Proof: `ParachainSystem::PendingUpwardMessages` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - fn send_blob() -> Weight { - // Proof Size summary in bytes: - // Measured: `38` - // Estimated: `3503` - // Minimum execution time: 19_525_000 picoseconds. - Weight::from_parts(20_071_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)) @@ -112,8 +90,8 @@ impl pallet_xcm::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `107` // Estimated: `3593` - // Minimum execution time: 91_793_000 picoseconds. - Weight::from_parts(93_761_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)) @@ -148,8 +126,8 @@ impl pallet_xcm::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `107` // Estimated: `3593` - // Minimum execution time: 91_819_000 picoseconds. - Weight::from_parts(93_198_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)) @@ -164,24 +142,14 @@ 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 execute_blob() -> 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: `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: 6_183_000 picoseconds. - Weight::from_parts(6_598_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)) } @@ -191,8 +159,8 @@ impl pallet_xcm::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_987_000 picoseconds. - Weight::from_parts(2_076_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)) } @@ -218,8 +186,8 @@ impl pallet_xcm::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `38` // Estimated: `3503` - // Minimum execution time: 25_375_000 picoseconds. - Weight::from_parts(26_165_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)) @@ -244,8 +212,8 @@ impl pallet_xcm::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `255` // Estimated: `3720` - // Minimum execution time: 28_167_000 picoseconds. - Weight::from_parts(28_792_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)) @@ -256,8 +224,8 @@ impl pallet_xcm::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 2_039_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)) } @@ -267,8 +235,8 @@ impl pallet_xcm::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `89` // Estimated: `13454` - // Minimum execution time: 17_127_000 picoseconds. - Weight::from_parts(17_519_000, 0) + // 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)) @@ -279,8 +247,8 @@ impl pallet_xcm::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `93` // Estimated: `13458` - // Minimum execution time: 16_701_000 picoseconds. - Weight::from_parts(17_250_000, 0) + // 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)) @@ -291,8 +259,8 @@ impl pallet_xcm::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `106` // Estimated: `15946` - // Minimum execution time: 18_795_000 picoseconds. - Weight::from_parts(19_302_000, 0) + // 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)) } @@ -314,8 +282,8 @@ impl pallet_xcm::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `106` // Estimated: `6046` - // Minimum execution time: 25_007_000 picoseconds. - Weight::from_parts(25_786_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)) @@ -326,8 +294,8 @@ impl pallet_xcm::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `136` // Estimated: `11026` - // Minimum execution time: 11_534_000 picoseconds. - Weight::from_parts(11_798_000, 0) + // 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)) } @@ -337,8 +305,8 @@ impl pallet_xcm::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `100` // Estimated: `13465` - // Minimum execution time: 17_357_000 picoseconds. - Weight::from_parts(17_629_000, 0) + // 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)) @@ -361,8 +329,8 @@ impl pallet_xcm::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `106` // Estimated: `13471` - // Minimum execution time: 33_487_000 picoseconds. - Weight::from_parts(34_033_000, 0) + // 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)) @@ -375,8 +343,8 @@ impl pallet_xcm::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `32` // Estimated: `1517` - // Minimum execution time: 3_688_000 picoseconds. - Weight::from_parts(3_854_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)) @@ -387,8 +355,8 @@ impl pallet_xcm::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `7669` // Estimated: `11134` - // Minimum execution time: 26_336_000 picoseconds. - Weight::from_parts(26_873_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)) @@ -399,8 +367,8 @@ impl pallet_xcm::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `90` // Estimated: `3555` - // Minimum execution time: 34_633_000 picoseconds. - Weight::from_parts(35_171_000, 0) + // 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 4870b4a52d7afb1bc303467b370f3cdd50114590..c2ca8e47f2a61cf6d66613daa205caddafe192b0 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 @@ -19,7 +19,6 @@ use super::{ ParachainSystem, PolkadotXcm, Runtime, RuntimeCall, RuntimeEvent, RuntimeOrigin, TransactionByteFee, WeightToFee, XcmpQueue, }; -use crate::bridge_common_config::{DeliveryRewardInBalance, RequiredStakeForStakeAndSlash}; use frame_support::{ parameter_types, traits::{tokens::imbalance::ResolveTo, ConstU32, Contains, Equals, Everything, Nothing}, @@ -39,16 +38,16 @@ use polkadot_runtime_common::xcm_sender::ExponentialPrice; use sp_runtime::traits::AccountIdConversion; use xcm::latest::prelude::*; use xcm_builder::{ - AccountId32Aliases, AllowExplicitUnpaidExecutionFrom, AllowKnownQueryResponses, - AllowSubscriptionsFrom, AllowTopLevelPaidExecutionFrom, DenyReserveTransferToRelayChain, - DenyThenTry, EnsureXcmOrigin, FrameTransactionalProcessor, FungibleAdapter, IsConcrete, - ParentAsSuperuser, ParentIsPreset, RelayChainAsNative, SiblingParachainAsNative, - SiblingParachainConvertsVia, SignedAccountId32AsNative, SignedToAccountId32, - SovereignSignedViaLocation, TakeWeightCredit, TrailingSetTopicAsId, UsingComponents, - WeightInfoBounds, WithComputedOrigin, WithUniqueTopic, XcmFeeManagerFromComponents, - XcmFeeToAccount, + AccountId32Aliases, AllowExplicitUnpaidExecutionFrom, AllowHrmpNotificationsFromRelayChain, + AllowKnownQueryResponses, AllowSubscriptionsFrom, AllowTopLevelPaidExecutionFrom, + DenyReserveTransferToRelayChain, 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}; +use xcm_executor::XcmExecutor; parameter_types! { pub const WestendLocation: Location = Location::parent(); @@ -119,73 +118,6 @@ impl Contains for ParentOrParentsPlurality { } } -/// A call filter for the XCM Transact instruction. This is a temporary measure until we properly -/// account for proof size weights. -/// -/// Calls that are allowed through this filter must: -/// 1. Have a fixed weight; -/// 2. Cannot lead to another call being made; -/// 3. Have a defined proof size weight, e.g. no unbounded vecs in call parameters. -pub struct SafeCallFilter; -impl Contains for SafeCallFilter { - fn contains(call: &RuntimeCall) -> bool { - #[cfg(feature = "runtime-benchmarks")] - { - if matches!(call, RuntimeCall::System(frame_system::Call::remark_with_event { .. })) { - return true - } - } - - // Allow to change dedicated storage items (called by governance-like) - match call { - RuntimeCall::System(frame_system::Call::set_storage { items }) - if items.iter().all(|(k, _)| { - k.eq(&DeliveryRewardInBalance::key()) | - k.eq(&RequiredStakeForStakeAndSlash::key()) - }) => - return true, - _ => (), - }; - - matches!( - call, - RuntimeCall::PolkadotXcm( - pallet_xcm::Call::force_xcm_version { .. } | - 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 { .. }, - ) | RuntimeCall::ParachainSystem(..) | - RuntimeCall::Timestamp(..) | - RuntimeCall::Balances(..) | - RuntimeCall::CollatorSelection(..) | - RuntimeCall::Session(pallet_session::Call::purge_keys { .. }) | - RuntimeCall::XcmpQueue(..) | - RuntimeCall::MessageQueue(..) | - RuntimeCall::BridgeRococoGrandpa(pallet_bridge_grandpa::Call::< - Runtime, - crate::bridge_to_rococo_config::BridgeGrandpaRococoInstance, - >::initialize { .. }) | - RuntimeCall::BridgeRococoGrandpa(pallet_bridge_grandpa::Call::< - Runtime, - crate::bridge_to_rococo_config::BridgeGrandpaRococoInstance, - >::set_operating_mode { .. }) | - RuntimeCall::BridgeRococoParachains(pallet_bridge_parachains::Call::< - Runtime, - crate::bridge_to_rococo_config::BridgeParachainRococoInstance, - >::set_operating_mode { .. }) | - RuntimeCall::BridgeRococoMessages(pallet_bridge_messages::Call::< - Runtime, - crate::bridge_to_rococo_config::WithBridgeHubRococoMessagesInstance, - >::set_operating_mode { .. }) - ) - } -} - pub type Barrier = TrailingSetTopicAsId< DenyThenTry< DenyReserveTransferToRelayChain, @@ -207,6 +139,8 @@ pub type Barrier = TrailingSetTopicAsId< )>, // Subscriptions for version tracking are OK. AllowSubscriptionsFrom, + // HRMP notifications from the relay chain are OK. + AllowHrmpNotificationsFromRelayChain, ), UniversalLocation, ConstU32<8>, @@ -265,13 +199,14 @@ impl xcm_executor::Config for XcmConfig { >; type MessageExporter = (crate::bridge_to_rococo_config::ToBridgeHubRococoHaulBlobExporter,); type UniversalAliases = Nothing; - type CallDispatcher = WithOriginFilter; - type SafeCallFilter = SafeCallFilter; + type CallDispatcher = RuntimeCall; + type SafeCallFilter = Everything; type Aliasers = Nothing; type TransactionalProcessor = FrameTransactionalProcessor; type HrmpNewChannelOpenRequestHandler = (); type HrmpChannelAcceptedHandler = (); type HrmpChannelClosingHandler = (); + type XcmRecorder = PolkadotXcm; } pub type PriceForParentDelivery = 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 988b10e1e2d8fac610c2feaec41d018012ec9fc3..836594140b2328081ff6c0de8cac40ea82dfb6f7 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 @@ -94,11 +94,10 @@ fn construct_and_apply_extrinsic( r.unwrap() } -fn construct_and_estimate_extrinsic_fee(batch: pallet_utility::Call) -> Balance { - let batch_call = RuntimeCall::Utility(batch); - let batch_info = batch_call.get_dispatch_info(); - let xt = construct_extrinsic(Alice, batch_call); - TransactionPayment::compute_fee(xt.encoded_size() as _, &batch_info, 0) +fn construct_and_estimate_extrinsic_fee(call: RuntimeCall) -> Balance { + let info = call.get_dispatch_info(); + let xt = construct_extrinsic(Alice, call); + TransactionPayment::compute_fee(xt.encoded_size() as _, &info, 0) } fn collator_session_keys() -> bridge_hub_test_utils::CollatorSessionKeys { @@ -271,22 +270,6 @@ fn relayed_incoming_message_works() { ) } -#[test] -pub fn complex_relay_extrinsic_works() { - from_parachain::complex_relay_extrinsic_works::( - collator_session_keys(), - slot_durations(), - bp_bridge_hub_westend::BRIDGE_HUB_WESTEND_PARACHAIN_ID, - bp_bridge_hub_rococo::BRIDGE_HUB_ROCOCO_PARACHAIN_ID, - SIBLING_PARACHAIN_ID, - BridgeHubRococoChainId::get(), - Westend, - XCM_LANE_FOR_ASSET_HUB_WESTEND_TO_ASSET_HUB_ROCOCO, - || (), - construct_and_apply_extrinsic, - ); -} - #[test] pub fn can_calculate_weight_for_paid_export_message_with_reserve_transfer() { bridge_hub_test_utils::check_sane_fees_values( @@ -309,12 +292,12 @@ pub fn can_calculate_weight_for_paid_export_message_with_reserve_transfer() { } #[test] -pub fn can_calculate_fee_for_complex_message_delivery_transaction() { +pub fn can_calculate_fee_for_standalone_message_delivery_transaction() { bridge_hub_test_utils::check_sane_fees_values( "bp_bridge_hub_westend::BridgeHubWestendBaseDeliveryFeeInWnds", bp_bridge_hub_westend::BridgeHubWestendBaseDeliveryFeeInWnds::get(), || { - from_parachain::can_calculate_fee_for_complex_message_delivery_transaction::< + from_parachain::can_calculate_fee_for_standalone_message_delivery_transaction::< RuntimeTestsAdapter, >(collator_session_keys(), construct_and_estimate_extrinsic_fee) }, @@ -328,12 +311,12 @@ pub fn can_calculate_fee_for_complex_message_delivery_transaction() { } #[test] -pub fn can_calculate_fee_for_complex_message_confirmation_transaction() { +pub fn can_calculate_fee_for_standalone_message_confirmation_transaction() { bridge_hub_test_utils::check_sane_fees_values( "bp_bridge_hub_westend::BridgeHubWestendBaseConfirmationFeeInWnds", bp_bridge_hub_westend::BridgeHubWestendBaseConfirmationFeeInWnds::get(), || { - from_parachain::can_calculate_fee_for_complex_message_confirmation_transaction::< + from_parachain::can_calculate_fee_for_standalone_message_confirmation_transaction::< RuntimeTestsAdapter, >(collator_session_keys(), construct_and_estimate_extrinsic_fee) }, diff --git a/cumulus/parachains/runtimes/bridge-hubs/common/Cargo.toml b/cumulus/parachains/runtimes/bridge-hubs/common/Cargo.toml index 2f5f783ce48fb19e1087e24e712fc4dc52b607da..aece34613e6a6c4dfe100e84b0317a96ad7ee97c 100644 --- a/cumulus/parachains/runtimes/bridge-hubs/common/Cargo.toml +++ b/cumulus/parachains/runtimes/bridge-hubs/common/Cargo.toml @@ -7,7 +7,7 @@ description = "Bridge hub common utilities" license = "Apache-2.0" [dependencies] -codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = ["derive"] } +codec = { package = "parity-scale-codec", version = "3.6.12", default-features = false, features = ["derive"] } scale-info = { version = "2.11.1", default-features = false, features = ["derive"] } frame-support = { path = "../../../../../substrate/frame/support", default-features = false } sp-std = { path = "../../../../../substrate/primitives/std", default-features = false } diff --git a/cumulus/parachains/runtimes/bridge-hubs/test-utils/Cargo.toml b/cumulus/parachains/runtimes/bridge-hubs/test-utils/Cargo.toml index 5f2a6e050d83c3db662f8ff4896d32dc8a28fde3..5a8fa18b92901dc20f0b19520bacb35f6b52f72c 100644 --- a/cumulus/parachains/runtimes/bridge-hubs/test-utils/Cargo.toml +++ b/cumulus/parachains/runtimes/bridge-hubs/test-utils/Cargo.toml @@ -10,7 +10,7 @@ license = "Apache-2.0" workspace = true [dependencies] -codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = ["derive", "max-encoded-len"] } +codec = { package = "parity-scale-codec", version = "3.6.12", default-features = false, features = ["derive", "max-encoded-len"] } impl-trait-for-tuples = "0.2" log = { workspace = true } diff --git a/cumulus/parachains/runtimes/bridge-hubs/test-utils/src/test_cases/from_grandpa_chain.rs b/cumulus/parachains/runtimes/bridge-hubs/test-utils/src/test_cases/from_grandpa_chain.rs index 8aaaa4f59d7884ff211855a925638317a3b722ea..bfa2f0f50f94ca3ba2f663f9646be3165dd48220 100644 --- a/cumulus/parachains/runtimes/bridge-hubs/test-utils/src/test_cases/from_grandpa_chain.rs +++ b/cumulus/parachains/runtimes/bridge-hubs/test-utils/src/test_cases/from_grandpa_chain.rs @@ -41,6 +41,7 @@ use frame_system::pallet_prelude::BlockNumberFor; use parachains_runtimes_test_utils::{ AccountIdOf, BasicParachainRuntime, CollatorSessionKeys, RuntimeCallOf, SlotDurations, }; +use sp_core::Get; use sp_keyring::AccountKeyring::*; use sp_runtime::{traits::Header as HeaderT, AccountId32}; use xcm::latest::prelude::*; @@ -162,7 +163,14 @@ pub fn relayed_incoming_message_works( test_data::from_grandpa_chain::make_complex_relayer_delivery_proofs::< RuntimeHelper::MB, (), - >(lane_id, xcm.into(), message_nonce, message_destination, relay_header_number); + >( + lane_id, + xcm.into(), + message_nonce, + message_destination, + relay_header_number, + false, + ); let relay_chain_header_hash = relay_chain_header.hash(); vec![ @@ -202,6 +210,142 @@ pub fn relayed_incoming_message_works( ); } +/// Test-case makes sure that Runtime can dispatch XCM messages submitted by relayer, +/// with proofs (finality, message) independently submitted. +/// Finality proof is submitted for free in this test. +/// Also verifies relayer transaction signed extensions work as intended. +pub fn free_relay_extrinsic_works( + collator_session_key: CollatorSessionKeys, + slot_durations: SlotDurations, + runtime_para_id: u32, + bridged_chain_id: bp_runtime::ChainId, + sibling_parachain_id: u32, + local_relay_chain_id: NetworkId, + lane_id: LaneId, + prepare_configuration: impl Fn(), + construct_and_apply_extrinsic: fn( + sp_keyring::AccountKeyring, + RuntimeCallOf, + ) -> sp_runtime::DispatchOutcome, +) where + RuntimeHelper: WithRemoteGrandpaChainHelper, + RuntimeHelper::Runtime: pallet_balances::Config, + AccountIdOf: From, + RuntimeCallOf: From> + + From>, + UnderlyingChainOf>: ChainWithGrandpa, + >::SourceHeaderChain: + SourceHeaderChain< + MessagesProof = FromBridgedChainMessagesProof< + HashOf>, + >, + >, +{ + // ensure that the runtime allows free header submissions + let free_headers_interval = >::FreeHeadersInterval::get() + .expect("this test requires runtime, configured to accept headers for free; qed"); + + helpers::relayed_incoming_message_works::< + RuntimeHelper::Runtime, + RuntimeHelper::AllPalletsWithoutSystem, + RuntimeHelper::MPI, + >( + collator_session_key, + slot_durations, + runtime_para_id, + sibling_parachain_id, + local_relay_chain_id, + construct_and_apply_extrinsic, + |relayer_id_at_this_chain, + relayer_id_at_bridged_chain, + message_destination, + message_nonce, + xcm| { + prepare_configuration(); + + // start with bridged relay chain block#0 + let initial_block_number = 0; + helpers::initialize_bridge_grandpa_pallet::( + test_data::initialization_data::( + initial_block_number, + ), + ); + + // free relay chain header is `0 + free_headers_interval` + let relay_header_number = initial_block_number + free_headers_interval; + + // relayer balance shall not change after relay and para header submissions + let initial_relayer_balance = + pallet_balances::Pallet::::free_balance( + relayer_id_at_this_chain.clone(), + ); + + // initialize the `FreeHeadersRemaining` storage value + pallet_bridge_grandpa::Pallet::::on_initialize( + 0u32.into(), + ); + + // generate bridged relay chain finality, parachain heads and message proofs, + // to be submitted by relayer to this chain. + let (relay_chain_header, grandpa_justification, message_proof) = + test_data::from_grandpa_chain::make_complex_relayer_delivery_proofs::< + RuntimeHelper::MB, + (), + >( + lane_id, + xcm.into(), + message_nonce, + message_destination, + relay_header_number.into(), + true, + ); + + let relay_chain_header_hash = relay_chain_header.hash(); + vec![ + ( + BridgeGrandpaCall::::submit_finality_proof { + finality_target: Box::new(relay_chain_header), + justification: grandpa_justification, + }.into(), + Box::new(( + helpers::VerifySubmitGrandpaFinalityProofOutcome::::expect_best_header_hash( + relay_chain_header_hash, + ), + helpers::VerifyRelayerBalance::::expect_relayer_balance( + relayer_id_at_this_chain.clone(), + initial_relayer_balance, + ), + )) + ), + ( + BridgeMessagesCall::::receive_messages_proof { + relayer_id_at_bridged_chain, + proof: message_proof, + messages_count: 1, + dispatch_weight: Weight::from_parts(1000000000, 0), + }.into(), + Box::new(( + helpers::VerifySubmitMessagesProofOutcome::::expect_last_delivered_nonce( + lane_id, + 1, + ), + helpers::VerifyRelayerRewarded::::expect_relayer_reward( + relayer_id_at_this_chain, + RewardsAccountParams::new( + lane_id, + bridged_chain_id, + RewardsAccountOwner::ThisChain, + ), + ), + )), + ), + ] + }, + ); +} + /// Test-case makes sure that Runtime can dispatch XCM messages submitted by relayer, /// with proofs (finality, message) batched together in signed extrinsic. /// Also verifies relayer transaction signed extensions work as intended. @@ -265,7 +409,14 @@ pub fn complex_relay_extrinsic_works( test_data::from_grandpa_chain::make_complex_relayer_delivery_proofs::< RuntimeHelper::MB, (), - >(lane_id, xcm.into(), message_nonce, message_destination, relay_header_number); + >( + lane_id, + xcm.into(), + message_nonce, + message_destination, + relay_header_number, + false, + ); let relay_chain_header_hash = relay_chain_header.hash(); vec![( @@ -344,6 +495,7 @@ where 1, [GlobalConsensus(Polkadot), Parachain(1_000)].into(), 1u32.into(), + false, ); // generate batch call that provides finality for bridged relay and parachains + message @@ -423,3 +575,109 @@ where compute_extrinsic_fee(batch) }) } + +/// Estimates transaction fee for default message delivery transaction from bridged GRANDPA chain. +pub fn can_calculate_fee_for_standalone_message_delivery_transaction( + collator_session_key: CollatorSessionKeys, + compute_extrinsic_fee: fn( + ::RuntimeCall, + ) -> u128, +) -> u128 +where + RuntimeHelper: WithRemoteGrandpaChainHelper, + RuntimeCallOf: + From>, + UnderlyingChainOf>: ChainWithGrandpa, + >::SourceHeaderChain: + SourceHeaderChain< + MessagesProof = FromBridgedChainMessagesProof< + HashOf>, + >, + >, +{ + run_test::(collator_session_key, 1000, vec![], || { + // generate bridged relay chain finality, parachain heads and message proofs, + // to be submitted by relayer to this chain. + // + // we don't care about parameter values here, apart from the XCM message size. But we + // do not need to have a large message here, because we're charging for every byte of + // the message additionally + let (_, _, message_proof) = + test_data::from_grandpa_chain::make_complex_relayer_delivery_proofs::< + RuntimeHelper::MB, + (), + >( + LaneId::default(), + vec![Instruction::<()>::ClearOrigin; 1_024].into(), + 1, + [GlobalConsensus(Polkadot), Parachain(1_000)].into(), + 1u32.into(), + false, + ); + + let call = test_data::from_grandpa_chain::make_standalone_relayer_delivery_call::< + RuntimeHelper::Runtime, + RuntimeHelper::GPI, + RuntimeHelper::MPI, + >( + message_proof, + helpers::relayer_id_at_bridged_chain::(), + ); + + compute_extrinsic_fee(call) + }) +} + +/// Estimates transaction fee for default message confirmation transaction (batched with required +/// proofs) from bridged parachain. +pub fn can_calculate_fee_for_standalone_message_confirmation_transaction( + collator_session_key: CollatorSessionKeys, + compute_extrinsic_fee: fn( + ::RuntimeCall, + ) -> u128, +) -> u128 +where + RuntimeHelper: WithRemoteGrandpaChainHelper, + AccountIdOf: From, + MessageThisChain: + bp_runtime::Chain>, + RuntimeCallOf: + From>, + UnderlyingChainOf>: ChainWithGrandpa, + >::TargetHeaderChain: + TargetHeaderChain< + XcmAsPlainPayload, + AccountIdOf, + MessagesDeliveryProof = FromBridgedChainMessagesDeliveryProof< + HashOf>>, + >, + >, +{ + run_test::(collator_session_key, 1000, vec![], || { + // generate bridged relay chain finality, parachain heads and message proofs, + // to be submitted by relayer to this chain. + let unrewarded_relayers = UnrewardedRelayersState { + unrewarded_relayer_entries: 1, + total_messages: 1, + ..Default::default() + }; + let (_, _, message_delivery_proof) = + test_data::from_grandpa_chain::make_complex_relayer_confirmation_proofs::< + RuntimeHelper::MB, + (), + >( + LaneId::default(), + 1u32.into(), + AccountId32::from(Alice.public()).into(), + unrewarded_relayers.clone(), + ); + + let call = test_data::from_grandpa_chain::make_standalone_relayer_confirmation_call::< + RuntimeHelper::Runtime, + RuntimeHelper::GPI, + RuntimeHelper::MPI, + >(message_delivery_proof, unrewarded_relayers); + + compute_extrinsic_fee(call) + }) +} diff --git a/cumulus/parachains/runtimes/bridge-hubs/test-utils/src/test_cases/from_parachain.rs b/cumulus/parachains/runtimes/bridge-hubs/test-utils/src/test_cases/from_parachain.rs index 72ec0718acf7759aedb02e91356fea73ee73e7e7..12ab382d9e0f6518afb93f118199170acb5f8cc6 100644 --- a/cumulus/parachains/runtimes/bridge-hubs/test-utils/src/test_cases/from_parachain.rs +++ b/cumulus/parachains/runtimes/bridge-hubs/test-utils/src/test_cases/from_parachain.rs @@ -42,6 +42,7 @@ use frame_system::pallet_prelude::BlockNumberFor; use parachains_runtimes_test_utils::{ AccountIdOf, BasicParachainRuntime, CollatorSessionKeys, RuntimeCallOf, SlotDurations, }; +use sp_core::Get; use sp_keyring::AccountKeyring::*; use sp_runtime::{traits::Header as HeaderT, AccountId32}; use xcm::latest::prelude::*; @@ -188,6 +189,7 @@ pub fn relayed_incoming_message_works( para_header_number, relay_header_number, bridged_para_id, + false, ); let parachain_head_hash = parachain_head.hash(); @@ -241,6 +243,177 @@ pub fn relayed_incoming_message_works( ); } +/// Test-case makes sure that Runtime can dispatch XCM messages submitted by relayer, +/// with proofs (finality, para heads, message) independently submitted. +/// Finality and para heads are submitted for free in this test. +/// Also verifies relayer transaction signed extensions work as intended. +pub fn free_relay_extrinsic_works( + collator_session_key: CollatorSessionKeys, + slot_durations: SlotDurations, + runtime_para_id: u32, + bridged_para_id: u32, + bridged_chain_id: bp_runtime::ChainId, + sibling_parachain_id: u32, + local_relay_chain_id: NetworkId, + lane_id: LaneId, + prepare_configuration: impl Fn(), + construct_and_apply_extrinsic: fn( + sp_keyring::AccountKeyring, + ::RuntimeCall, + ) -> sp_runtime::DispatchOutcome, +) where + RuntimeHelper: WithRemoteParachainHelper, + RuntimeHelper::Runtime: pallet_balances::Config, + AccountIdOf: From, + RuntimeCallOf: From> + + From> + + From>, + UnderlyingChainOf>: + bp_runtime::Chain + Parachain, + >::BridgedChain: + bp_runtime::Chain + ChainWithGrandpa, + >::SourceHeaderChain: + SourceHeaderChain< + MessagesProof = FromBridgedChainMessagesProof< + HashOf>, + >, + >, +{ + // ensure that the runtime allows free header submissions + let free_headers_interval = >::FreeHeadersInterval::get() + .expect("this test requires runtime, configured to accept headers for free; qed"); + + helpers::relayed_incoming_message_works::< + RuntimeHelper::Runtime, + RuntimeHelper::AllPalletsWithoutSystem, + RuntimeHelper::MPI, + >( + collator_session_key, + slot_durations, + runtime_para_id, + sibling_parachain_id, + local_relay_chain_id, + construct_and_apply_extrinsic, + |relayer_id_at_this_chain, + relayer_id_at_bridged_chain, + message_destination, + message_nonce, + xcm| { + prepare_configuration(); + + // start with bridged relay chain block#0 + let initial_block_number = 0; + helpers::initialize_bridge_grandpa_pallet::( + test_data::initialization_data::( + initial_block_number, + ), + ); + + // free relay chain header is `0 + free_headers_interval` + let relay_header_number = initial_block_number + free_headers_interval; + // first parachain header is always submitted for free + let para_header_number = 1; + + // relayer balance shall not change after relay and para header submissions + let initial_relayer_balance = + pallet_balances::Pallet::::free_balance( + relayer_id_at_this_chain.clone(), + ); + + // initialize the `FreeHeadersRemaining` storage value + pallet_bridge_grandpa::Pallet::::on_initialize( + 0u32.into(), + ); + + // generate bridged relay chain finality, parachain heads and message proofs, + // to be submitted by relayer to this chain. + let ( + relay_chain_header, + grandpa_justification, + parachain_head, + parachain_heads, + para_heads_proof, + message_proof, + ) = test_data::from_parachain::make_complex_relayer_delivery_proofs::< + >::BridgedChain, + RuntimeHelper::MB, + (), + >( + lane_id, + xcm.into(), + message_nonce, + message_destination, + para_header_number, + relay_header_number, + bridged_para_id, + true, + ); + + let parachain_head_hash = parachain_head.hash(); + let relay_chain_header_hash = relay_chain_header.hash(); + let relay_chain_header_number = *relay_chain_header.number(); + vec![ + ( + BridgeGrandpaCall::::submit_finality_proof { + finality_target: Box::new(relay_chain_header), + justification: grandpa_justification, + }.into(), + Box::new(( + helpers::VerifySubmitGrandpaFinalityProofOutcome::::expect_best_header_hash( + relay_chain_header_hash, + ), + helpers::VerifyRelayerBalance::::expect_relayer_balance( + relayer_id_at_this_chain.clone(), + initial_relayer_balance, + ), + )), + ), + ( + BridgeParachainsCall::::submit_parachain_heads { + at_relay_block: (relay_chain_header_number, relay_chain_header_hash), + parachains: parachain_heads, + parachain_heads_proof: para_heads_proof, + }.into(), + Box::new(( + helpers::VerifySubmitParachainHeaderProofOutcome::::expect_best_header_hash( + bridged_para_id, + parachain_head_hash, + ), + /*helpers::VerifyRelayerBalance::::expect_relayer_balance( + relayer_id_at_this_chain.clone(), + initial_relayer_balance, + ),*/ + )), + ), + ( + BridgeMessagesCall::::receive_messages_proof { + relayer_id_at_bridged_chain, + proof: message_proof, + messages_count: 1, + dispatch_weight: Weight::from_parts(1000000000, 0), + }.into(), + Box::new(( + helpers::VerifySubmitMessagesProofOutcome::::expect_last_delivered_nonce( + lane_id, + 1, + ), + helpers::VerifyRelayerRewarded::::expect_relayer_reward( + relayer_id_at_this_chain, + RewardsAccountParams::new( + lane_id, + bridged_chain_id, + RewardsAccountOwner::ThisChain, + ), + ), + )), + ), + ] + }, + ); +} + /// Test-case makes sure that Runtime can dispatch XCM messages submitted by relayer, /// with proofs (finality, para heads, message) batched together in signed extrinsic. /// Also verifies relayer transaction signed extensions work as intended. @@ -325,6 +498,7 @@ pub fn complex_relay_extrinsic_works( para_header_number, relay_header_number, bridged_para_id, + false, ); let parachain_head_hash = parachain_head.hash(); @@ -428,6 +602,7 @@ where 1, 5, 1_000, + false, ); // generate batch call that provides finality for bridged relay and parachains + message @@ -527,3 +702,126 @@ where compute_extrinsic_fee(batch) }) } + +/// Estimates transaction fee for default message delivery transaction from bridged parachain. +pub fn can_calculate_fee_for_standalone_message_delivery_transaction( + collator_session_key: CollatorSessionKeys, + compute_extrinsic_fee: fn( + ::RuntimeCall, + ) -> u128, +) -> u128 +where + RuntimeHelper: WithRemoteParachainHelper, + RuntimeCallOf: + From>, + UnderlyingChainOf>: + bp_runtime::Chain + Parachain, + >::BridgedChain: + bp_runtime::Chain + ChainWithGrandpa, + >::SourceHeaderChain: + SourceHeaderChain< + MessagesProof = FromBridgedChainMessagesProof< + HashOf>, + >, + >, +{ + run_test::(collator_session_key, 1000, vec![], || { + // generate bridged relay chain finality, parachain heads and message proofs, + // to be submitted by relayer to this chain. + // + // we don't care about parameter values here, apart from the XCM message size. But we + // do not need to have a large message here, because we're charging for every byte of + // the message additionally + let ( + _, + _, + _, + _, + _, + message_proof, + ) = test_data::from_parachain::make_complex_relayer_delivery_proofs::< + >::BridgedChain, + RuntimeHelper::MB, + (), + >( + LaneId::default(), + vec![Instruction::<()>::ClearOrigin; 1_024].into(), + 1, + [GlobalConsensus(Polkadot), Parachain(1_000)].into(), + 1, + 5, + 1_000, + false, + ); + + let call = test_data::from_parachain::make_standalone_relayer_delivery_call::< + RuntimeHelper::Runtime, + RuntimeHelper::MPI, + _, + >( + message_proof, + helpers::relayer_id_at_bridged_chain::(), + ); + + compute_extrinsic_fee(call) + }) +} + +/// Estimates transaction fee for default message confirmation transaction (batched with required +/// proofs) from bridged parachain. +pub fn can_calculate_fee_for_standalone_message_confirmation_transaction( + collator_session_key: CollatorSessionKeys, + compute_extrinsic_fee: fn( + ::RuntimeCall, + ) -> u128, +) -> u128 +where + RuntimeHelper: WithRemoteParachainHelper, + AccountIdOf: From, + MessageThisChain: + bp_runtime::Chain>, + RuntimeCallOf: + From>, + UnderlyingChainOf>: + bp_runtime::Chain + Parachain, + >::BridgedChain: + bp_runtime::Chain + ChainWithGrandpa, + >::TargetHeaderChain: + TargetHeaderChain< + XcmAsPlainPayload, + AccountIdOf, + MessagesDeliveryProof = FromBridgedChainMessagesDeliveryProof< + HashOf>>, + >, + >, +{ + run_test::(collator_session_key, 1000, vec![], || { + // generate bridged relay chain finality, parachain heads and message proofs, + // to be submitted by relayer to this chain. + let unrewarded_relayers = UnrewardedRelayersState { + unrewarded_relayer_entries: 1, + total_messages: 1, + ..Default::default() + }; + let (_, _, _, _, _, message_delivery_proof) = + test_data::from_parachain::make_complex_relayer_confirmation_proofs::< + >::BridgedChain, + RuntimeHelper::MB, + (), + >( + LaneId::default(), + 1, + 5, + 1_000, + AccountId32::from(Alice.public()).into(), + unrewarded_relayers.clone(), + ); + + let call = test_data::from_parachain::make_standalone_relayer_confirmation_call::< + RuntimeHelper::Runtime, + RuntimeHelper::MPI, + >(message_delivery_proof, unrewarded_relayers); + + compute_extrinsic_fee(call) + }) +} 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 2b48f2e3d515f625532d9c5f50fabadb9a89517a..0ce049cd1c4630c55c244afbc8a72213cb83d6b9 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 @@ -193,6 +193,34 @@ where } } +/// Verifies that relayer balance is equal to given value. +pub struct VerifyRelayerBalance { + relayer: Runtime::AccountId, + balance: Runtime::Balance, +} + +impl VerifyRelayerBalance +where + Runtime: pallet_balances::Config, +{ + /// Expect given relayer balance after transaction. + pub fn expect_relayer_balance( + relayer: Runtime::AccountId, + balance: Runtime::Balance, + ) -> Box { + Box::new(Self { relayer, balance }) + } +} + +impl VerifyTransactionOutcome for VerifyRelayerBalance +where + Runtime: pallet_balances::Config, +{ + fn verify_outcome(&self) { + assert_eq!(pallet_balances::Pallet::::free_balance(&self.relayer), self.balance,); + } +} + /// Initialize bridge GRANDPA pallet. pub(crate) fn initialize_bridge_grandpa_pallet( init_data: bp_header_chain::InitializationData>, diff --git a/cumulus/parachains/runtimes/bridge-hubs/test-utils/src/test_data/from_grandpa_chain.rs b/cumulus/parachains/runtimes/bridge-hubs/test-utils/src/test_data/from_grandpa_chain.rs index 017ec0fd54052ae0b00c19a2c474a8e265c768b0..e5d5e7cac96ba14f6abfdae792908352f40d3e31 100644 --- a/cumulus/parachains/runtimes/bridge-hubs/test-utils/src/test_data/from_grandpa_chain.rs +++ b/cumulus/parachains/runtimes/bridge-hubs/test-utils/src/test_data/from_grandpa_chain.rs @@ -121,6 +121,60 @@ where } } +/// Prepare a call with message proof. +pub fn make_standalone_relayer_delivery_call( + message_proof: FromBridgedChainMessagesProof>>, + relayer_id_at_bridged_chain: AccountIdOf>, +) -> Runtime::RuntimeCall +where + Runtime: pallet_bridge_grandpa::Config + + pallet_bridge_messages::Config< + MPI, + InboundPayload = XcmAsPlainPayload, + InboundRelayer = AccountIdOf>, + >, + MPI: 'static, + >::SourceHeaderChain: SourceHeaderChain< + MessagesProof = FromBridgedChainMessagesProof>>, + >, + Runtime::RuntimeCall: From>, +{ + pallet_bridge_messages::Call::::receive_messages_proof { + relayer_id_at_bridged_chain, + proof: message_proof, + messages_count: 1, + dispatch_weight: Weight::from_parts(1000000000, 0), + } + .into() +} + +/// Prepare a call with message delivery proof. +pub fn make_standalone_relayer_confirmation_call( + message_delivery_proof: FromBridgedChainMessagesDeliveryProof< + HashOf>, + >, + relayers_state: UnrewardedRelayersState, +) -> Runtime::RuntimeCall +where + Runtime: pallet_bridge_grandpa::Config + + pallet_bridge_messages::Config, + MPI: 'static, + >::TargetHeaderChain: TargetHeaderChain< + XcmAsPlainPayload, + Runtime::AccountId, + MessagesDeliveryProof = FromBridgedChainMessagesDeliveryProof< + HashOf>, + >, + >, + Runtime::RuntimeCall: From>, +{ + pallet_bridge_messages::Call::::receive_messages_delivery_proof { + proof: message_delivery_proof, + relayers_state, + } + .into() +} + /// Prepare storage proofs of messages, stored at the (bridged) source GRANDPA chain. pub fn make_complex_relayer_delivery_proofs( lane_id: LaneId, @@ -128,6 +182,7 @@ pub fn make_complex_relayer_delivery_proofs( message_nonce: MessageNonce, message_destination: Junctions, header_number: BlockNumberOf>, + is_minimal_call: bool, ) -> ( HeaderOf>, GrandpaJustification>>, @@ -153,7 +208,7 @@ where let (header, justification) = make_complex_bridged_grandpa_header_proof::< MessageBridgedChain, - >(state_root, header_number); + >(state_root, header_number, is_minimal_call); let message_proof = FromBridgedChainMessagesProof { bridged_header_hash: header.hash(), @@ -200,8 +255,11 @@ where StorageProofSize::Minimal(0), ); - let (header, justification) = - make_complex_bridged_grandpa_header_proof::(state_root, header_number); + let (header, justification) = make_complex_bridged_grandpa_header_proof::( + state_root, + header_number, + false, + ); let message_delivery_proof = FromBridgedChainMessagesDeliveryProof { bridged_header_hash: header.hash(), @@ -216,6 +274,7 @@ where pub fn make_complex_bridged_grandpa_header_proof( state_root: HashOf, header_number: BlockNumberOf, + is_minimal_call: bool, ) -> (HeaderOf, GrandpaJustification>) where BridgedChain: ChainWithGrandpa, @@ -229,7 +288,9 @@ where // `submit_finality_proof` call size would be close to maximal expected (and refundable) let extra_bytes_required = maximal_expected_submit_finality_proof_call_size::() .saturating_sub(header.encoded_size()); - header.digest_mut().push(DigestItem::Other(vec![42; extra_bytes_required])); + if !is_minimal_call { + header.digest_mut().push(DigestItem::Other(vec![42; extra_bytes_required])); + } let justification = make_default_justification(&header); (header, justification) diff --git a/cumulus/parachains/runtimes/bridge-hubs/test-utils/src/test_data/from_parachain.rs b/cumulus/parachains/runtimes/bridge-hubs/test-utils/src/test_data/from_parachain.rs index 932ba231239973db8b46ccea56faacc5628a4ffb..5d3cba4e53b5ec7ec9cd2e6141e6e95aa8928970 100644 --- a/cumulus/parachains/runtimes/bridge-hubs/test-utils/src/test_data/from_parachain.rs +++ b/cumulus/parachains/runtimes/bridge-hubs/test-utils/src/test_data/from_parachain.rs @@ -159,6 +159,52 @@ where } } +/// Prepare a call with message proof. +pub fn make_standalone_relayer_delivery_call( + message_proof: FromBridgedChainMessagesProof, + relayer_id_at_bridged_chain: InboundRelayer, +) -> Runtime::RuntimeCall where + Runtime: pallet_bridge_messages::Config< + MPI, + InboundPayload = XcmAsPlainPayload, + InboundRelayer = InboundRelayer, + >, + MPI: 'static, + Runtime::RuntimeCall: From>, + <>::SourceHeaderChain as SourceHeaderChain>::MessagesProof: + From>, +{ + pallet_bridge_messages::Call::::receive_messages_proof { + relayer_id_at_bridged_chain: relayer_id_at_bridged_chain.into(), + proof: message_proof.into(), + messages_count: 1, + dispatch_weight: Weight::from_parts(1000000000, 0), + } + .into() +} + +/// Prepare a call with message delivery proof. +pub fn make_standalone_relayer_confirmation_call( + message_delivery_proof: FromBridgedChainMessagesDeliveryProof, + relayers_state: UnrewardedRelayersState, +) -> Runtime::RuntimeCall +where + Runtime: pallet_bridge_messages::Config, + MPI: 'static, + Runtime::RuntimeCall: From>, + >::TargetHeaderChain: TargetHeaderChain< + XcmAsPlainPayload, + Runtime::AccountId, + MessagesDeliveryProof = FromBridgedChainMessagesDeliveryProof, + >, +{ + pallet_bridge_messages::Call::::receive_messages_delivery_proof { + proof: message_delivery_proof, + relayers_state, + } + .into() +} + /// Prepare storage proofs of messages, stored at the source chain. pub fn make_complex_relayer_delivery_proofs( lane_id: LaneId, @@ -168,6 +214,7 @@ pub fn make_complex_relayer_delivery_proofs ( HeaderOf, GrandpaJustification>, @@ -201,6 +248,7 @@ where para_header_number, relay_header_number, bridged_para_id, + is_minimal_call, ); let message_proof = FromBridgedChainMessagesProof { @@ -266,6 +314,7 @@ where para_header_number, relay_header_number, bridged_para_id, + false, ); let message_delivery_proof = FromBridgedChainMessagesDeliveryProof { @@ -290,6 +339,7 @@ pub fn make_complex_bridged_parachain_heads_proof( para_header_number: u32, relay_header_number: BlockNumberOf, bridged_para_id: u32, + is_minimal_call: bool, ) -> ( HeaderOf, GrandpaJustification>, @@ -319,9 +369,12 @@ where )]); assert_eq!(bridged_para_head.hash(), parachain_heads[0].1); - let (relay_chain_header, justification) = make_complex_bridged_grandpa_header_proof::< - BridgedRelayChain, - >(relay_state_root, relay_header_number); + let (relay_chain_header, justification) = + make_complex_bridged_grandpa_header_proof::( + relay_state_root, + relay_header_number, + is_minimal_call, + ); (relay_chain_header, justification, bridged_para_head, parachain_heads, para_heads_proof) } diff --git a/cumulus/parachains/runtimes/collectives/collectives-westend/Cargo.toml b/cumulus/parachains/runtimes/collectives/collectives-westend/Cargo.toml index 22821170a54c9ef0faf6fb3756b6d62234bf654a..a7f517222420dce6ee44e6590a51a3e3f101cf0b 100644 --- a/cumulus/parachains/runtimes/collectives/collectives-westend/Cargo.toml +++ b/cumulus/parachains/runtimes/collectives/collectives-westend/Cargo.toml @@ -10,7 +10,7 @@ description = "Westend Collectives Parachain Runtime" workspace = true [dependencies] -codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = ["derive", "max-encoded-len"] } +codec = { package = "parity-scale-codec", version = "3.6.12", default-features = false, features = ["derive", "max-encoded-len"] } hex-literal = { version = "0.4.1" } log = { workspace = true } scale-info = { version = "2.11.1", default-features = false, features = ["derive"] } @@ -34,6 +34,7 @@ pallet-preimage = { path = "../../../../../substrate/frame/preimage", default-fe pallet-proxy = { path = "../../../../../substrate/frame/proxy", default-features = false } pallet-scheduler = { path = "../../../../../substrate/frame/scheduler", default-features = false } pallet-session = { path = "../../../../../substrate/frame/session", default-features = false } +pallet-state-trie-migration = { path = "../../../../../substrate/frame/state-trie-migration", 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 } @@ -118,6 +119,7 @@ runtime-benchmarks = [ "pallet-referenda/runtime-benchmarks", "pallet-salary/runtime-benchmarks", "pallet-scheduler/runtime-benchmarks", + "pallet-state-trie-migration/runtime-benchmarks", "pallet-timestamp/runtime-benchmarks", "pallet-treasury/runtime-benchmarks", "pallet-utility/runtime-benchmarks", @@ -156,6 +158,7 @@ try-runtime = [ "pallet-salary/try-runtime", "pallet-scheduler/try-runtime", "pallet-session/try-runtime", + "pallet-state-trie-migration/try-runtime", "pallet-timestamp/try-runtime", "pallet-transaction-payment/try-runtime", "pallet-treasury/try-runtime", @@ -202,6 +205,7 @@ std = [ "pallet-salary/std", "pallet-scheduler/std", "pallet-session/std", + "pallet-state-trie-migration/std", "pallet-timestamp/std", "pallet-transaction-payment-rpc-runtime-api/std", "pallet-transaction-payment/std", diff --git a/cumulus/parachains/runtimes/collectives/collectives-westend/build.rs b/cumulus/parachains/runtimes/collectives/collectives-westend/build.rs index 60f8a125129ff1344a1799246e931acdb1d139d5..239ccac19ec7778039fb1ee56f4e772b3ddd3711 100644 --- a/cumulus/parachains/runtimes/collectives/collectives-westend/build.rs +++ b/cumulus/parachains/runtimes/collectives/collectives-westend/build.rs @@ -15,11 +15,7 @@ #[cfg(feature = "std")] fn main() { - substrate_wasm_builder::WasmBuilder::new() - .with_current_project() - .export_heap_base() - .import_memory() - .build() + substrate_wasm_builder::WasmBuilder::build_using_defaults(); } #[cfg(not(feature = "std"))] diff --git a/cumulus/parachains/runtimes/collectives/collectives-westend/src/fellowship/mod.rs b/cumulus/parachains/runtimes/collectives/collectives-westend/src/fellowship/mod.rs index 3816d2ed848ed51740283ffea31e9f7e53c01f1a..94765287637b57d47c588d9a4359666d1b54f509 100644 --- a/cumulus/parachains/runtimes/collectives/collectives-westend/src/fellowship/mod.rs +++ b/cumulus/parachains/runtimes/collectives/collectives-westend/src/fellowship/mod.rs @@ -21,13 +21,16 @@ mod tracks; use crate::{ weights, xcm_config::{FellowshipAdminBodyId, LocationToAccountId, TreasurerBodyId, UsdtAssetHub}, - AccountId, AssetRate, Balance, Balances, FellowshipReferenda, GovernanceLocation, Preimage, - Runtime, RuntimeCall, RuntimeEvent, RuntimeOrigin, Scheduler, WestendTreasuryAccount, DAYS, + AccountId, AssetRate, Balance, Balances, FellowshipReferenda, GovernanceLocation, + ParachainInfo, Preimage, Runtime, RuntimeCall, RuntimeEvent, RuntimeOrigin, Scheduler, + WestendTreasuryAccount, DAYS, }; +use cumulus_primitives_core::ParaId; use frame_support::{ parameter_types, traits::{ - EitherOf, EitherOfDiverse, MapSuccess, NeverEnsureOrigin, OriginTrait, TryWithMorphedArg, + tokens::UnityOrOuterConversion, EitherOf, EitherOfDiverse, FromContains, MapSuccess, + NeverEnsureOrigin, OriginTrait, TryWithMorphedArg, }, PalletId, }; @@ -40,10 +43,10 @@ use pallet_ranked_collective::EnsureOfRank; use pallet_xcm::{EnsureXcm, IsVoiceOfBody}; use parachains_common::impls::ToParentTreasury; use polkadot_runtime_common::impls::{ - LocatableAssetConverter, VersionedLocatableAsset, VersionedLocationConverter, + ContainsParts, LocatableAssetConverter, VersionedLocatableAsset, VersionedLocationConverter, }; use sp_arithmetic::Permill; -use sp_core::{ConstU128, ConstU32}; +use sp_core::{ConstU128, ConstU32, ConstU8}; use sp_runtime::traits::{ConstU16, ConvertToValue, IdentityLookup, Replace, TakeFirst}; use testnet_parachains_constants::westend::{account, currency::GRAND}; use westend_runtime_constants::time::HOURS; @@ -263,6 +266,7 @@ parameter_types! { // The asset's interior location for the paying account. This is the Fellowship Treasury // pallet instance (which sits at index 65). pub FellowshipTreasuryInteriorLocation: InteriorLocation = PalletInstance(65).into(); + pub SelfParaId: ParaId = ParachainInfo::parachain_id(); } #[cfg(feature = "runtime-benchmarks")] @@ -345,7 +349,15 @@ impl pallet_treasury::Config for Runtime { type Paymaster = FellowshipTreasuryPaymaster; #[cfg(feature = "runtime-benchmarks")] type Paymaster = PayWithEnsure>>; - type BalanceConverter = AssetRate; + type BalanceConverter = UnityOrOuterConversion< + ContainsParts< + FromContains< + xcm_builder::IsSiblingSystemParachain, + xcm_builder::IsParentsOnly>, + >, + >, + AssetRate, + >; type PayoutPeriod = ConstU32<{ 30 * DAYS }>; #[cfg(feature = "runtime-benchmarks")] type BenchmarkHelper = polkadot_runtime_common::impls::benchmarks::TreasuryArguments< diff --git a/cumulus/parachains/runtimes/collectives/collectives-westend/src/lib.rs b/cumulus/parachains/runtimes/collectives/collectives-westend/src/lib.rs index c599ba37f128bb01adaa1e4dc3203a1ae15def9d..59005d0fa97dd71bb30feae83009e6e9bdae2091 100644 --- a/cumulus/parachains/runtimes/collectives/collectives-westend/src/lib.rs +++ b/cumulus/parachains/runtimes/collectives/collectives-westend/src/lib.rs @@ -117,11 +117,11 @@ 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_010_000, + spec_version: 1_011_000, impl_version: 0, apis: RUNTIME_API_VERSIONS, - transaction_version: 5, - state_version: 0, + transaction_version: 6, + state_version: 1, }; /// The version information used to identify this runtime when compiled natively. @@ -420,7 +420,7 @@ impl pallet_message_queue::Config for Runtime { // The XCMP queue pallet is only ever able to handle the `Sibling(ParaId)` origin: type QueueChangeHandler = NarrowOriginToSibling; type QueuePausedQuery = NarrowOriginToSibling; - type HeapSize = sp_core::ConstU32<{ 64 * 1024 }>; + type HeapSize = sp_core::ConstU32<{ 103 * 1024 }>; type MaxStale = sp_core::ConstU32<8>; type ServiceWeight = MessageQueueServiceWeight; type IdleMaxServiceWeight = MessageQueueServiceWeight; @@ -448,13 +448,22 @@ impl cumulus_pallet_xcmp_queue::Config for Runtime { type VersionWrapper = PolkadotXcm; // Enqueue XCMP messages from siblings for later processing. type XcmpQueue = TransformOrigin; - type MaxInboundSuspended = sp_core::ConstU32<1_000>; + type MaxInboundSuspended = ConstU32<1_000>; + type MaxActiveOutboundChannels = ConstU32<128>; + // Most on-chain HRMP channels are configured to use 102400 bytes of max message size, so we + // need to set the page size larger than that until we reduce the channel size on-chain. + type MaxPageSize = ConstU32<{ 103 * 1024 }>; type ControllerOrigin = EitherOfDiverse, Fellows>; type ControllerOriginConverter = XcmOriginToTransactDispatchOrigin; type WeightInfo = weights::cumulus_pallet_xcmp_queue::WeightInfo; type PriceForSiblingDelivery = PriceForSiblingParachainDelivery; } +impl cumulus_pallet_xcmp_queue::migration::v5::V5Config for Runtime { + // This must be the same as the `ChannelInfo` from the `Config`: + type ChannelList = ParachainSystem; +} + parameter_types! { pub const RelayOrigin: AggregateMessageOrigin = AggregateMessageOrigin::Parent; } @@ -693,6 +702,8 @@ construct_runtime!( AmbassadorCore: pallet_core_fellowship:: = 73, AmbassadorSalary: pallet_salary:: = 74, AmbassadorContent: pallet_collective_content:: = 75, + + StateTrieMigration: pallet_state_trie_migration = 80, } ); @@ -722,9 +733,10 @@ pub type UncheckedExtrinsic = /// `OnRuntimeUpgrade`. Included migrations must be idempotent. type Migrations = ( // unreleased - pallet_collator_selection::migration::v1::MigrateToV1, + pallet_collator_selection::migration::v2::MigrationToV2, // unreleased cumulus_pallet_xcmp_queue::migration::v4::MigrationToV4, + cumulus_pallet_xcmp_queue::migration::v5::MigrateV4ToV5, // permanent pallet_xcm::migration::MigrateToLatestXcmVersion, ); @@ -1080,3 +1092,44 @@ cumulus_pallet_parachain_system::register_validate_block! { Runtime = Runtime, BlockExecutor = cumulus_pallet_aura_ext::BlockExecutor::, } + +parameter_types! { + // The deposit configuration for the singed migration. Specially if you want to allow any signed account to do the migration (see `SignedFilter`, these deposits should be high) + pub const MigrationSignedDepositPerItem: Balance = CENTS; + pub const MigrationSignedDepositBase: Balance = 2_000 * CENTS; + pub const MigrationMaxKeyLen: u32 = 512; +} + +impl pallet_state_trie_migration::Config for Runtime { + type RuntimeEvent = RuntimeEvent; + type Currency = Balances; + type RuntimeHoldReason = RuntimeHoldReason; + type SignedDepositPerItem = MigrationSignedDepositPerItem; + type SignedDepositBase = MigrationSignedDepositBase; + // An origin that can control the whole pallet: should be Root, or a part of your council. + type ControlOrigin = frame_system::EnsureSignedBy; + // specific account for the migration, can trigger the signed migrations. + type SignedFilter = frame_system::EnsureSignedBy; + + // Replace this with weight based on your runtime. + type WeightInfo = pallet_state_trie_migration::weights::SubstrateWeight; + + type MaxKeyLen = MigrationMaxKeyLen; +} + +frame_support::ord_parameter_types! { + pub const MigController: AccountId = AccountId::from(hex_literal::hex!("8458ed39dc4b6f6c7255f7bc42be50c2967db126357c999d44e12ca7ac80dc52")); + pub const RootMigController: AccountId = AccountId::from(hex_literal::hex!("8458ed39dc4b6f6c7255f7bc42be50c2967db126357c999d44e12ca7ac80dc52")); +} + +#[test] +fn ensure_key_ss58() { + use frame_support::traits::SortedMembers; + use sp_core::crypto::Ss58Codec; + let acc = + AccountId::from_ss58check("5F4EbSkZz18X36xhbsjvDNs6NuZ82HyYtq5UiJ1h9SBHJXZD").unwrap(); + assert_eq!(acc, MigController::sorted_members()[0]); + let acc = + AccountId::from_ss58check("5F4EbSkZz18X36xhbsjvDNs6NuZ82HyYtq5UiJ1h9SBHJXZD").unwrap(); + assert_eq!(acc, RootMigController::sorted_members()[0]); +} diff --git a/cumulus/parachains/runtimes/collectives/collectives-westend/src/weights/pallet_balances.rs b/cumulus/parachains/runtimes/collectives/collectives-westend/src/weights/pallet_balances.rs index 602e7ca50c136c3c862bbf2f43fa452b9518116e..b100b0f2b1a83f6c939e25c88493814a80d29bd4 100644 --- a/cumulus/parachains/runtimes/collectives/collectives-westend/src/weights/pallet_balances.rs +++ b/cumulus/parachains/runtimes/collectives/collectives-westend/src/weights/pallet_balances.rs @@ -17,9 +17,9 @@ //! 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-05-06, 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-unxyhko3-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: @@ -54,8 +54,8 @@ impl pallet_balances::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `0` // Estimated: `3593` - // Minimum execution time: 45_085_000 picoseconds. - Weight::from_parts(45_772_000, 0) + // Minimum execution time: 46_316_000 picoseconds. + Weight::from_parts(46_965_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 +66,8 @@ impl pallet_balances::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `0` // Estimated: `3593` - // Minimum execution time: 35_447_000 picoseconds. - Weight::from_parts(36_143_000, 0) + // Minimum execution time: 36_337_000 picoseconds. + Weight::from_parts(36_803_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 +78,8 @@ impl pallet_balances::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `103` // Estimated: `3593` - // Minimum execution time: 12_314_000 picoseconds. - Weight::from_parts(12_679_000, 0) + // Minimum execution time: 12_331_000 picoseconds. + Weight::from_parts(12_774_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 +90,8 @@ impl pallet_balances::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `103` // Estimated: `3593` - // Minimum execution time: 17_455_000 picoseconds. - Weight::from_parts(17_902_000, 0) + // Minimum execution time: 17_532_000 picoseconds. + Weight::from_parts(17_948_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 +102,8 @@ impl pallet_balances::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `103` // Estimated: `6196` - // Minimum execution time: 46_785_000 picoseconds. - Weight::from_parts(47_436_000, 0) + // Minimum execution time: 47_251_000 picoseconds. + Weight::from_parts(48_164_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 +114,8 @@ impl pallet_balances::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `0` // Estimated: `3593` - // Minimum execution time: 43_948_000 picoseconds. - Weight::from_parts(44_680_000, 0) + // Minimum execution time: 45_319_000 picoseconds. + Weight::from_parts(46_094_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 +126,8 @@ impl pallet_balances::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `103` // Estimated: `3593` - // Minimum execution time: 15_267_000 picoseconds. - Weight::from_parts(15_499_000, 0) + // Minimum execution time: 15_263_000 picoseconds. + Weight::from_parts(15_632_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 +139,11 @@ impl pallet_balances::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `0 + u * (136 ±0)` // Estimated: `990 + u * (2603 ±0)` - // Minimum execution time: 14_817_000 picoseconds. - Weight::from_parts(15_287_000, 0) + // Minimum execution time: 15_106_000 picoseconds. + Weight::from_parts(15_353_000, 0) .saturating_add(Weight::from_parts(0, 990)) - // Standard Error: 11_738 - .saturating_add(Weight::from_parts(13_511_800, 0).saturating_mul(u.into())) + // Standard Error: 11_570 + .saturating_add(Weight::from_parts(13_765_985, 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,9 +154,25 @@ impl pallet_balances::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `0` // Estimated: `1501` - // Minimum execution time: 5_382_000 picoseconds. - Weight::from_parts(5_768_000, 0) + // Minimum execution time: 5_277_000 picoseconds. + Weight::from_parts(5_560_000, 0) .saturating_add(Weight::from_parts(0, 1501)) .saturating_add(T::DbWeight::get().reads(1)) } + fn burn_allow_death() -> Weight { + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 28_810_000 picoseconds. + Weight::from_parts(29_155_000, 0) + .saturating_add(Weight::from_parts(0, 0)) + } + fn burn_keep_alive() -> Weight { + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 18_957_000 picoseconds. + Weight::from_parts(19_292_000, 0) + .saturating_add(Weight::from_parts(0, 0)) + } } 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 0edd5dfff2b8b714c6de0a34dcd095787673d39b..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 @@ -17,9 +17,9 @@ //! Autogenerated weights for `pallet_xcm` //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 32.0.0 -//! DATE: 2024-03-21, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! DATE: 2024-02-20, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` //! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `runner-h2rr8wx7-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,30 +64,8 @@ impl pallet_xcm::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `145` // Estimated: `3610` - // Minimum execution time: 21_911_000 picoseconds. - Weight::from_parts(22_431_000, 0) - .saturating_add(Weight::from_parts(0, 3610)) - .saturating_add(T::DbWeight::get().reads(6)) - .saturating_add(T::DbWeight::get().writes(2)) - } - /// Storage: `ParachainSystem::UpwardDeliveryFeeFactor` (r:1 w:0) - /// Proof: `ParachainSystem::UpwardDeliveryFeeFactor` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - /// Storage: `PolkadotXcm::SupportedVersion` (r:1 w:0) - /// Proof: `PolkadotXcm::SupportedVersion` (`max_values`: None, `max_size`: None, mode: `Measured`) - /// Storage: `PolkadotXcm::VersionDiscoveryQueue` (r:1 w:1) - /// Proof: `PolkadotXcm::VersionDiscoveryQueue` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - /// Storage: `PolkadotXcm::SafeXcmVersion` (r:1 w:0) - /// Proof: `PolkadotXcm::SafeXcmVersion` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - /// Storage: `ParachainSystem::HostConfiguration` (r:1 w:0) - /// Proof: `ParachainSystem::HostConfiguration` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - /// Storage: `ParachainSystem::PendingUpwardMessages` (r:1 w:1) - /// Proof: `ParachainSystem::PendingUpwardMessages` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - fn send_blob() -> Weight { - // Proof Size summary in bytes: - // Measured: `145` - // Estimated: `3610` - // Minimum execution time: 22_143_000 picoseconds. - Weight::from_parts(22_843_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)) @@ -112,8 +90,8 @@ impl pallet_xcm::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `214` // Estimated: `3679` - // Minimum execution time: 96_273_000 picoseconds. - Weight::from_parts(98_351_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)) @@ -148,8 +126,8 @@ impl pallet_xcm::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `214` // Estimated: `3679` - // Minimum execution time: 95_571_000 picoseconds. - Weight::from_parts(96_251_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)) @@ -164,24 +142,14 @@ 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 execute_blob() -> 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: `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: 6_227_000 picoseconds. - Weight::from_parts(6_419_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)) } @@ -191,8 +159,8 @@ impl pallet_xcm::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_851_000 picoseconds. - Weight::from_parts(1_940_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)) } @@ -218,8 +186,8 @@ impl pallet_xcm::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `145` // Estimated: `3610` - // Minimum execution time: 27_449_000 picoseconds. - Weight::from_parts(28_513_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)) @@ -244,8 +212,8 @@ impl pallet_xcm::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `363` // Estimated: `3828` - // Minimum execution time: 29_477_000 picoseconds. - Weight::from_parts(30_251_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)) @@ -256,8 +224,8 @@ impl pallet_xcm::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_894_000 picoseconds. - Weight::from_parts(2_009_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)) } @@ -267,8 +235,8 @@ impl pallet_xcm::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `159` // Estimated: `13524` - // Minimum execution time: 17_991_000 picoseconds. - Weight::from_parts(18_651_000, 0) + // 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)) @@ -279,8 +247,8 @@ impl pallet_xcm::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `163` // Estimated: `13528` - // Minimum execution time: 18_321_000 picoseconds. - Weight::from_parts(18_701_000, 0) + // 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)) @@ -291,8 +259,8 @@ impl pallet_xcm::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `173` // Estimated: `16013` - // Minimum execution time: 19_762_000 picoseconds. - Weight::from_parts(20_529_000, 0) + // 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)) } @@ -314,8 +282,8 @@ impl pallet_xcm::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `212` // Estimated: `6152` - // Minimum execution time: 26_927_000 picoseconds. - Weight::from_parts(27_629_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)) @@ -326,8 +294,8 @@ impl pallet_xcm::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `206` // Estimated: `11096` - // Minimum execution time: 11_957_000 picoseconds. - Weight::from_parts(12_119_000, 0) + // 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)) } @@ -337,8 +305,8 @@ impl pallet_xcm::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `170` // Estimated: `13535` - // Minimum execution time: 17_942_000 picoseconds. - Weight::from_parts(18_878_000, 0) + // 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)) @@ -361,8 +329,8 @@ impl pallet_xcm::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `212` // Estimated: `13577` - // Minimum execution time: 35_640_000 picoseconds. - Weight::from_parts(36_340_000, 0) + // 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)) @@ -376,7 +344,7 @@ impl pallet_xcm::WeightInfo for WeightInfo { // Measured: `103` // Estimated: `1588` // Minimum execution time: 4_044_000 picoseconds. - Weight::from_parts(4_229_000, 0) + 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)) @@ -387,8 +355,8 @@ impl pallet_xcm::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `7740` // Estimated: `11205` - // Minimum execution time: 26_262_000 picoseconds. - Weight::from_parts(26_842_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)) @@ -399,8 +367,8 @@ impl pallet_xcm::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `160` // Estimated: `3625` - // Minimum execution time: 36_775_000 picoseconds. - Weight::from_parts(37_265_000, 0) + // 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 21ccd3b9cdb0b0474eb2023cc2509dbee66b1861..c68f230a16dc3d35b861df5aa7667d61d4cf53cf 100644 --- a/cumulus/parachains/runtimes/collectives/collectives-westend/src/xcm_config.rs +++ b/cumulus/parachains/runtimes/collectives/collectives-westend/src/xcm_config.rs @@ -35,16 +35,17 @@ use polkadot_runtime_common::xcm_sender::ExponentialPrice; use westend_runtime_constants::xcm as xcm_constants; use xcm::latest::prelude::*; use xcm_builder::{ - AccountId32Aliases, AllowExplicitUnpaidExecutionFrom, AllowKnownQueryResponses, - AllowSubscriptionsFrom, AllowTopLevelPaidExecutionFrom, DenyReserveTransferToRelayChain, - DenyThenTry, EnsureXcmOrigin, FixedWeightBounds, FrameTransactionalProcessor, FungibleAdapter, - IsConcrete, LocatableAssetId, OriginToPluralityVoice, ParentAsSuperuser, ParentIsPreset, - RelayChainAsNative, SiblingParachainAsNative, SiblingParachainConvertsVia, - SignedAccountId32AsNative, SignedToAccountId32, SovereignSignedViaLocation, TakeWeightCredit, - TrailingSetTopicAsId, UsingComponents, WithComputedOrigin, WithUniqueTopic, - XcmFeeManagerFromComponents, XcmFeeToAccount, + AccountId32Aliases, AllowExplicitUnpaidExecutionFrom, AllowHrmpNotificationsFromRelayChain, + AllowKnownQueryResponses, AllowSubscriptionsFrom, AllowTopLevelPaidExecutionFrom, + DenyReserveTransferToRelayChain, DenyThenTry, EnsureXcmOrigin, FixedWeightBounds, + FrameTransactionalProcessor, FungibleAdapter, IsConcrete, LocatableAssetId, + OriginToPluralityVoice, ParentAsSuperuser, ParentIsPreset, RelayChainAsNative, + SiblingParachainAsNative, SiblingParachainConvertsVia, SignedAccountId32AsNative, + SignedToAccountId32, SovereignSignedViaLocation, TakeWeightCredit, TrailingSetTopicAsId, + UsingComponents, WithComputedOrigin, WithUniqueTopic, XcmFeeManagerFromComponents, + XcmFeeToAccount, }; -use xcm_executor::{traits::WithOriginFilter, XcmExecutor}; +use xcm_executor::XcmExecutor; parameter_types! { pub const WndLocation: Location = Location::parent(); @@ -138,83 +139,6 @@ impl Contains for ParentOrParentsPlurality { } } -/// A call filter for the XCM Transact instruction. This is a temporary measure until we properly -/// account for proof size weights. -/// -/// Calls that are allowed through this filter must: -/// 1. Have a fixed weight; -/// 2. Cannot lead to another call being made; -/// 3. Have a defined proof size weight, e.g. no unbounded vecs in call parameters. -pub struct SafeCallFilter; -impl Contains for SafeCallFilter { - fn contains(call: &RuntimeCall) -> bool { - #[cfg(feature = "runtime-benchmarks")] - { - if matches!(call, RuntimeCall::System(frame_system::Call::remark_with_event { .. })) { - return true - } - } - - matches!( - call, - 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 { .. }, - ) | RuntimeCall::ParachainSystem(..) | - RuntimeCall::Timestamp(..) | - RuntimeCall::Balances(..) | - RuntimeCall::CollatorSelection(..) | - RuntimeCall::Session(pallet_session::Call::purge_keys { .. }) | - RuntimeCall::PolkadotXcm( - pallet_xcm::Call::force_xcm_version { .. } | - pallet_xcm::Call::force_default_xcm_version { .. } - ) | RuntimeCall::XcmpQueue(..) | - RuntimeCall::MessageQueue(..) | - RuntimeCall::Alliance( - // `init_members` accepts unbounded vecs as arguments, - // but the call can be initiated only by root origin. - pallet_alliance::Call::init_members { .. } | - pallet_alliance::Call::vote { .. } | - pallet_alliance::Call::disband { .. } | - pallet_alliance::Call::set_rule { .. } | - pallet_alliance::Call::announce { .. } | - pallet_alliance::Call::remove_announcement { .. } | - pallet_alliance::Call::join_alliance { .. } | - pallet_alliance::Call::nominate_ally { .. } | - pallet_alliance::Call::elevate_ally { .. } | - pallet_alliance::Call::give_retirement_notice { .. } | - pallet_alliance::Call::retire { .. } | - pallet_alliance::Call::kick_member { .. } | - pallet_alliance::Call::close { .. } | - pallet_alliance::Call::abdicate_fellow_status { .. }, - ) | RuntimeCall::AllianceMotion( - pallet_collective::Call::vote { .. } | - pallet_collective::Call::disapprove_proposal { .. } | - pallet_collective::Call::close { .. }, - ) | RuntimeCall::FellowshipCollective( - pallet_ranked_collective::Call::add_member { .. } | - pallet_ranked_collective::Call::promote_member { .. } | - pallet_ranked_collective::Call::demote_member { .. } | - pallet_ranked_collective::Call::remove_member { .. }, - ) | RuntimeCall::FellowshipCore( - pallet_core_fellowship::Call::bump { .. } | - pallet_core_fellowship::Call::set_params { .. } | - pallet_core_fellowship::Call::set_active { .. } | - pallet_core_fellowship::Call::approve { .. } | - pallet_core_fellowship::Call::induct { .. } | - pallet_core_fellowship::Call::promote { .. } | - pallet_core_fellowship::Call::offboard { .. } | - pallet_core_fellowship::Call::submit_evidence { .. } | - pallet_core_fellowship::Call::import { .. }, - ) - ) - } -} - pub type Barrier = TrailingSetTopicAsId< DenyThenTry< DenyReserveTransferToRelayChain, @@ -233,6 +157,8 @@ pub type Barrier = TrailingSetTopicAsId< AllowExplicitUnpaidExecutionFrom, // Subscriptions for version tracking are OK. AllowSubscriptionsFrom, + // HRMP notifications from the relay chain are OK. + AllowHrmpNotificationsFromRelayChain, ), UniversalLocation, ConstU32<8>, @@ -287,13 +213,14 @@ impl xcm_executor::Config for XcmConfig { >; type MessageExporter = (); type UniversalAliases = Nothing; - type CallDispatcher = WithOriginFilter; - type SafeCallFilter = SafeCallFilter; + type CallDispatcher = RuntimeCall; + type SafeCallFilter = Everything; type Aliasers = Nothing; type TransactionalProcessor = FrameTransactionalProcessor; type HrmpNewChannelOpenRequestHandler = (); type HrmpChannelAcceptedHandler = (); type HrmpChannelClosingHandler = (); + type XcmRecorder = PolkadotXcm; } /// Converts a local signed origin into an XCM location. diff --git a/cumulus/parachains/runtimes/contracts/contracts-rococo/Cargo.toml b/cumulus/parachains/runtimes/contracts/contracts-rococo/Cargo.toml index 74c5b5f8115958d0894af621e6c7307e3f67b9b7..4040e977fafd244f238986d6da268f997836bfd9 100644 --- a/cumulus/parachains/runtimes/contracts/contracts-rococo/Cargo.toml +++ b/cumulus/parachains/runtimes/contracts/contracts-rococo/Cargo.toml @@ -16,7 +16,7 @@ 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.6.12", default-features = false, features = ["derive"] } hex-literal = { version = "0.4.1", optional = true } log = { workspace = true } scale-info = { version = "2.11.1", default-features = false, features = ["derive"] } diff --git a/cumulus/parachains/runtimes/contracts/contracts-rococo/build.rs b/cumulus/parachains/runtimes/contracts/contracts-rococo/build.rs index 60f8a125129ff1344a1799246e931acdb1d139d5..239ccac19ec7778039fb1ee56f4e772b3ddd3711 100644 --- a/cumulus/parachains/runtimes/contracts/contracts-rococo/build.rs +++ b/cumulus/parachains/runtimes/contracts/contracts-rococo/build.rs @@ -15,11 +15,7 @@ #[cfg(feature = "std")] fn main() { - substrate_wasm_builder::WasmBuilder::new() - .with_current_project() - .export_heap_base() - .import_memory() - .build() + substrate_wasm_builder::WasmBuilder::build_using_defaults(); } #[cfg(not(feature = "std"))] diff --git a/cumulus/parachains/runtimes/contracts/contracts-rococo/src/lib.rs b/cumulus/parachains/runtimes/contracts/contracts-rococo/src/lib.rs index efa26fcbc22d534dd4573ab15d8052a7179c77a0..85a85e7086cb0d2ba62e3e315ac1870933966be8 100644 --- a/cumulus/parachains/runtimes/contracts/contracts-rococo/src/lib.rs +++ b/cumulus/parachains/runtimes/contracts/contracts-rococo/src/lib.rs @@ -98,12 +98,15 @@ pub type UncheckedExtrinsic = /// Migrations to apply on runtime upgrade. pub type Migrations = ( + pallet_collator_selection::migration::v1::MigrateToV1, + pallet_collator_selection::migration::v2::MigrationToV2, cumulus_pallet_parachain_system::migration::Migration, cumulus_pallet_xcmp_queue::migration::v2::MigrationToV2, cumulus_pallet_xcmp_queue::migration::v3::MigrationToV3, pallet_contracts::Migration, // unreleased cumulus_pallet_xcmp_queue::migration::v4::MigrationToV4, + cumulus_pallet_xcmp_queue::migration::v5::MigrateV4ToV5, // permanent pallet_xcm::migration::MigrateToLatestXcmVersion, ); @@ -134,10 +137,10 @@ 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_010_000, + spec_version: 1_011_000, impl_version: 0, apis: RUNTIME_API_VERSIONS, - transaction_version: 6, + transaction_version: 7, state_version: 1, }; @@ -316,7 +319,7 @@ impl pallet_message_queue::Config for Runtime { // The XCMP queue pallet is only ever able to handle the `Sibling(ParaId)` origin: type QueueChangeHandler = NarrowOriginToSibling; type QueuePausedQuery = NarrowOriginToSibling; - type HeapSize = sp_core::ConstU32<{ 64 * 1024 }>; + type HeapSize = sp_core::ConstU32<{ 103 * 1024 }>; type MaxStale = sp_core::ConstU32<8>; type ServiceWeight = MessageQueueServiceWeight; type IdleMaxServiceWeight = MessageQueueServiceWeight; 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 46fcbc6319c951efa91408ce310f3451002c8b77..ef5ded1731d0d9f3ff60e1e8cb71cd1fe18ca81b 100644 --- a/cumulus/parachains/runtimes/contracts/contracts-rococo/src/xcm_config.rs +++ b/cumulus/parachains/runtimes/contracts/contracts-rococo/src/xcm_config.rs @@ -38,22 +38,22 @@ use sp_runtime::traits::AccountIdConversion; use testnet_parachains_constants::rococo::currency::CENTS; use xcm::latest::prelude::*; use xcm_builder::{ - AccountId32Aliases, AllowExplicitUnpaidExecutionFrom, AllowKnownQueryResponses, - AllowSubscriptionsFrom, AllowTopLevelPaidExecutionFrom, DenyReserveTransferToRelayChain, - DenyThenTry, EnsureXcmOrigin, FixedWeightBounds, FrameTransactionalProcessor, FungibleAdapter, - IsConcrete, NativeAsset, ParentAsSuperuser, ParentIsPreset, RelayChainAsNative, - SiblingParachainAsNative, SiblingParachainConvertsVia, SignedAccountId32AsNative, - SignedToAccountId32, SovereignSignedViaLocation, TakeWeightCredit, TrailingSetTopicAsId, - UsingComponents, WithComputedOrigin, WithUniqueTopic, XcmFeeManagerFromComponents, - XcmFeeToAccount, + AccountId32Aliases, AllowExplicitUnpaidExecutionFrom, AllowHrmpNotificationsFromRelayChain, + AllowKnownQueryResponses, AllowSubscriptionsFrom, AllowTopLevelPaidExecutionFrom, + DenyReserveTransferToRelayChain, 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; parameter_types! { pub const RelayLocation: Location = Location::parent(); - pub const RelayNetwork: Option = None; + pub const RelayNetwork: NetworkId = NetworkId::Rococo; pub RelayChainOrigin: RuntimeOrigin = cumulus_pallet_xcm::Origin::Relay.into(); - pub UniversalLocation: InteriorLocation = Parachain(ParachainInfo::parachain_id().into()).into(); + pub UniversalLocation: InteriorLocation = [GlobalConsensus(RelayNetwork::get()), Parachain(ParachainInfo::parachain_id().into())].into(); pub const ExecutiveBody: BodyId = BodyId::Executive; pub TreasuryAccount: AccountId = TREASURY_PALLET_ID.into_account_truncating(); pub RelayTreasuryLocation: Location = (Parent, PalletInstance(rococo_runtime_constants::TREASURY_PALLET_ID)).into(); @@ -149,6 +149,8 @@ pub type Barrier = TrailingSetTopicAsId< )>, // Subscriptions for version tracking are OK. AllowSubscriptionsFrom, + // HRMP notifications from the relay chain are OK. + AllowHrmpNotificationsFromRelayChain, ), UniversalLocation, ConstU32<8>, @@ -200,6 +202,7 @@ impl xcm_executor::Config for XcmConfig { type HrmpNewChannelOpenRequestHandler = (); type HrmpChannelAcceptedHandler = (); type HrmpChannelClosingHandler = (); + type XcmRecorder = PolkadotXcm; } /// Converts a local signed origin into an XCM location. @@ -281,7 +284,11 @@ impl cumulus_pallet_xcmp_queue::Config for Runtime { cumulus_primitives_core::ParaId, parachains_common::message_queue::ParaIdToSibling, >; - type MaxInboundSuspended = sp_core::ConstU32<1_000>; + type MaxInboundSuspended = ConstU32<1_000>; + type MaxActiveOutboundChannels = ConstU32<128>; + // Most on-chain HRMP channels are configured to use 102400 bytes of max message size, so we + // need to set the page size larger than that until we reduce the channel size on-chain. + type MaxPageSize = ConstU32<{ 103 * 1024 }>; type ControllerOrigin = EitherOfDiverse< EnsureRoot, EnsureXcm>, @@ -291,6 +298,11 @@ impl cumulus_pallet_xcmp_queue::Config for Runtime { type PriceForSiblingDelivery = PriceForSiblingParachainDelivery; } +impl cumulus_pallet_xcmp_queue::migration::v5::V5Config for Runtime { + // This must be the same as the `ChannelInfo` from the `Config`: + type ChannelList = ParachainSystem; +} + parameter_types! { pub const RelayOrigin: AggregateMessageOrigin = AggregateMessageOrigin::Parent; } diff --git a/cumulus/parachains/runtimes/coretime/coretime-rococo/Cargo.toml b/cumulus/parachains/runtimes/coretime/coretime-rococo/Cargo.toml index ee9f5e87ec876d73d80eb088806f5b36f12079db..b92dc57989cf02d6e64c18eb05af963a00f960d7 100644 --- a/cumulus/parachains/runtimes/coretime/coretime-rococo/Cargo.toml +++ b/cumulus/parachains/runtimes/coretime/coretime-rococo/Cargo.toml @@ -13,7 +13,7 @@ workspace = true 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.6.12", default-features = false, features = ["derive"] } hex-literal = "0.4.1" log = { workspace = true } scale-info = { version = "2.9.0", default-features = false, features = ["derive"] } diff --git a/cumulus/parachains/runtimes/coretime/coretime-rococo/src/lib.rs b/cumulus/parachains/runtimes/coretime/coretime-rococo/src/lib.rs index 9959c15b11107ecba1470ab52cbef16fc6f22c25..4f4935de133bf34c9950272e80ff5be2172c0b34 100644 --- a/cumulus/parachains/runtimes/coretime/coretime-rococo/src/lib.rs +++ b/cumulus/parachains/runtimes/coretime/coretime-rococo/src/lib.rs @@ -108,7 +108,10 @@ pub type UncheckedExtrinsic = /// Migrations to apply on runtime upgrade. pub type Migrations = ( + pallet_collator_selection::migration::v2::MigrationToV2, cumulus_pallet_xcmp_queue::migration::v4::MigrationToV4, + cumulus_pallet_xcmp_queue::migration::v5::MigrateV4ToV5, + pallet_broker::migration::MigrateV0ToV1, // permanent pallet_xcm::migration::MigrateToLatestXcmVersion, ); @@ -134,10 +137,10 @@ 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_010_000, + spec_version: 1_011_000, impl_version: 0, apis: RUNTIME_API_VERSIONS, - transaction_version: 0, + transaction_version: 1, state_version: 1, }; @@ -299,7 +302,7 @@ impl pallet_message_queue::Config for Runtime { // The XCMP queue pallet is only ever able to handle the `Sibling(ParaId)` origin: type QueueChangeHandler = NarrowOriginToSibling; type QueuePausedQuery = NarrowOriginToSibling; - type HeapSize = sp_core::ConstU32<{ 64 * 1024 }>; + type HeapSize = sp_core::ConstU32<{ 103 * 1024 }>; type MaxStale = sp_core::ConstU32<8>; type ServiceWeight = MessageQueueServiceWeight; type IdleMaxServiceWeight = MessageQueueServiceWeight; @@ -339,13 +342,22 @@ impl cumulus_pallet_xcmp_queue::Config for Runtime { type ChannelInfo = ParachainSystem; type VersionWrapper = PolkadotXcm; type XcmpQueue = TransformOrigin; - type MaxInboundSuspended = sp_core::ConstU32<1_000>; + type MaxInboundSuspended = ConstU32<1_000>; + type MaxActiveOutboundChannels = ConstU32<128>; + // Most on-chain HRMP channels are configured to use 102400 bytes of max message size, so we + // need to set the page size larger than that until we reduce the channel size on-chain. + type MaxPageSize = ConstU32<{ 103 * 1024 }>; type ControllerOrigin = RootOrFellows; type ControllerOriginConverter = XcmOriginToTransactDispatchOrigin; type WeightInfo = weights::cumulus_pallet_xcmp_queue::WeightInfo; type PriceForSiblingDelivery = PriceForSiblingParachainDelivery; } +impl cumulus_pallet_xcmp_queue::migration::v5::V5Config for Runtime { + // This must be the same as the `ChannelInfo` from the `Config`: + type ChannelList = ParachainSystem; +} + pub const PERIOD: u32 = 6 * HOURS; pub const OFFSET: u32 = 0; @@ -719,11 +731,20 @@ 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, - >; + 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()) @@ -741,8 +762,21 @@ impl_runtime_apis! { } fn reserve_transferable_asset_and_dest() -> Option<(Asset, Location)> { - // Reserve transfers are disabled - None + // Coretime chain can reserve transfer regions to some random parachain. + + // Properties of a mock region: + let core = 0; + let begin = 0; + let end = 42; + + let region_id = pallet_broker::Pallet::::issue(core, begin, end, None, None); + Some(( + Asset { + fun: NonFungible(Index(region_id.into())), + id: AssetId(xcm_config::BrokerPalletLocation::get()) + }, + ParentThen(Parachain(RandomParaId::get().into()).into()).into(), + )) } fn get_asset() -> Asset { @@ -758,15 +792,25 @@ impl_runtime_apis! { RocRelayLocation::get(), ExistentialDeposit::get() ).into()); + pub const RandomParaId: ParaId = ParaId::new(43211234); } impl pallet_xcm_benchmarks::Config for Runtime { type XcmConfig = xcm_config::XcmConfig; - type DeliveryHelper = cumulus_primitives_utility::ToParentDeliveryHelper< - xcm_config::XcmConfig, - ExistentialDepositAsset, - xcm_config::PriceForParentDelivery, - >; + 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, + > + ); type AccountIdConverter = xcm_config::LocationToAccountId; fn valid_destination() -> Result { Ok(RocRelayLocation::get()) diff --git a/cumulus/parachains/runtimes/coretime/coretime-rococo/src/weights/pallet_balances.rs b/cumulus/parachains/runtimes/coretime/coretime-rococo/src/weights/pallet_balances.rs index aac7e10936615fddf39f9c306121dd9eda826ec6..a021d11478480bb941fbd79b85ec85eef25d3a66 100644 --- a/cumulus/parachains/runtimes/coretime/coretime-rococo/src/weights/pallet_balances.rs +++ b/cumulus/parachains/runtimes/coretime/coretime-rococo/src/weights/pallet_balances.rs @@ -17,9 +17,9 @@ //! 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-05-06, 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-unxyhko3-project-674-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` //! WASM-EXECUTION: `Compiled`, CHAIN: `Some("coretime-rococo-dev")`, DB CACHE: 1024 // Executed Command: @@ -54,8 +54,8 @@ impl pallet_balances::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `0` // Estimated: `3593` - // Minimum execution time: 41_557_000 picoseconds. - Weight::from_parts(42_618_000, 0) + // Minimum execution time: 43_792_000 picoseconds. + Weight::from_parts(44_475_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 +66,8 @@ impl pallet_balances::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `0` // Estimated: `3593` - // Minimum execution time: 33_046_000 picoseconds. - Weight::from_parts(33_550_000, 0) + // Minimum execution time: 34_144_000 picoseconds. + Weight::from_parts(34_887_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 +78,8 @@ impl pallet_balances::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `103` // Estimated: `3593` - // Minimum execution time: 11_804_000 picoseconds. - Weight::from_parts(12_007_000, 0) + // Minimum execution time: 11_864_000 picoseconds. + Weight::from_parts(12_253_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 +90,8 @@ impl pallet_balances::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `103` // Estimated: `3593` - // Minimum execution time: 16_261_000 picoseconds. - Weight::from_parts(16_655_000, 0) + // Minimum execution time: 16_448_000 picoseconds. + Weight::from_parts(17_008_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 +102,8 @@ impl pallet_balances::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `103` // Estimated: `6196` - // Minimum execution time: 42_967_000 picoseconds. - Weight::from_parts(43_870_000, 0) + // Minimum execution time: 44_353_000 picoseconds. + Weight::from_parts(45_131_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 +114,8 @@ impl pallet_balances::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `0` // Estimated: `3593` - // Minimum execution time: 41_022_000 picoseconds. - Weight::from_parts(41_475_000, 0) + // Minimum execution time: 42_899_000 picoseconds. + Weight::from_parts(43_749_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 +126,8 @@ impl pallet_balances::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `103` // Estimated: `3593` - // Minimum execution time: 14_339_000 picoseconds. - Weight::from_parts(14_641_000, 0) + // Minimum execution time: 14_308_000 picoseconds. + Weight::from_parts(15_020_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 +139,11 @@ impl pallet_balances::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `0 + u * (136 ±0)` // Estimated: `990 + u * (2603 ±0)` - // Minimum execution time: 14_241_000 picoseconds. - Weight::from_parts(14_463_000, 0) + // Minimum execution time: 14_369_000 picoseconds. + Weight::from_parts(14_525_000, 0) .saturating_add(Weight::from_parts(0, 990)) - // Standard Error: 12_290 - .saturating_add(Weight::from_parts(12_903_900, 0).saturating_mul(u.into())) + // Standard Error: 11_260 + .saturating_add(Weight::from_parts(13_056_576, 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,9 +154,25 @@ impl pallet_balances::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `0` // Estimated: `1501` - // Minimum execution time: 5_116_000 picoseconds. - Weight::from_parts(5_345_000, 0) + // Minimum execution time: 5_198_000 picoseconds. + Weight::from_parts(5_430_000, 0) .saturating_add(Weight::from_parts(0, 1501)) .saturating_add(T::DbWeight::get().reads(1)) } + fn burn_allow_death() -> Weight { + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 27_335_000 picoseconds. + Weight::from_parts(28_146_000, 0) + .saturating_add(Weight::from_parts(0, 0)) + } + fn burn_keep_alive() -> Weight { + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 18_390_000 picoseconds. + Weight::from_parts(18_893_000, 0) + .saturating_add(Weight::from_parts(0, 0)) + } } 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 df0044089c8f6fb558d368e2f006a6a4fbd9fb97..7fb492173dad9b88be6d32ab063c10e532155f53 100644 --- a/cumulus/parachains/runtimes/coretime/coretime-rococo/src/weights/pallet_xcm.rs +++ b/cumulus/parachains/runtimes/coretime/coretime-rococo/src/weights/pallet_xcm.rs @@ -17,9 +17,9 @@ //! Autogenerated weights for `pallet_xcm` //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 32.0.0 -//! DATE: 2024-03-21, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! DATE: 2024-05-07, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` //! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `runner-h2rr8wx7-project-674-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` +//! HOSTNAME: `runner-unxyhko3-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: @@ -62,12 +62,14 @@ impl pallet_xcm::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `74` // Estimated: `3539` - // Minimum execution time: 18_767_000 picoseconds. - Weight::from_parts(19_420_000, 0) + // Minimum execution time: 19_121_000 picoseconds. + Weight::from_parts(19_582_000, 0) .saturating_add(Weight::from_parts(0, 3539)) .saturating_add(T::DbWeight::get().reads(5)) .saturating_add(T::DbWeight::get().writes(2)) } + /// Storage: `ParachainInfo::ParachainId` (r:1 w:0) + /// Proof: `ParachainInfo::ParachainId` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) /// Storage: `PolkadotXcm::SupportedVersion` (r:1 w:0) /// Proof: `PolkadotXcm::SupportedVersion` (`max_values`: None, `max_size`: None, mode: `Measured`) /// Storage: `PolkadotXcm::VersionDiscoveryQueue` (r:1 w:1) @@ -78,47 +80,45 @@ 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 send_blob() -> Weight { + fn teleport_assets() -> Weight { // Proof Size summary in bytes: - // Measured: `74` - // Estimated: `3539` - // Minimum execution time: 19_184_000 picoseconds. - Weight::from_parts(19_695_000, 0) - .saturating_add(Weight::from_parts(0, 3539)) - .saturating_add(T::DbWeight::get().reads(5)) + // Measured: `106` + // Estimated: `3571` + // Minimum execution time: 61_722_000 picoseconds. + Weight::from_parts(63_616_000, 0) + .saturating_add(Weight::from_parts(0, 3571)) + .saturating_add(T::DbWeight::get().reads(6)) .saturating_add(T::DbWeight::get().writes(2)) } /// Storage: `ParachainInfo::ParachainId` (r:1 w:0) /// Proof: `ParachainInfo::ParachainId` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) + /// Storage: `Broker::Regions` (r:1 w:1) + /// Proof: `Broker::Regions` (`max_values`: None, `max_size`: Some(86), added: 2561, mode: `MaxEncodedLen`) + /// Storage: `XcmpQueue::DeliveryFeeFactor` (r:1 w:0) + /// Proof: `XcmpQueue::DeliveryFeeFactor` (`max_values`: None, `max_size`: None, mode: `Measured`) /// 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: `106` - // Estimated: `3571` - // Minimum execution time: 58_120_000 picoseconds. - Weight::from_parts(59_533_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: `Benchmark::Override` (`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: `ParachainSystem::RelevantMessagingState` (r:1 w:0) + /// Proof: `ParachainSystem::RelevantMessagingState` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `XcmpQueue::OutboundXcmpStatus` (r:1 w:1) + /// Proof: `XcmpQueue::OutboundXcmpStatus` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `XcmpQueue::OutboundXcmpMessages` (r:0 w:1) + /// Proof: `XcmpQueue::OutboundXcmpMessages` (`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)) + // Measured: `377` + // Estimated: `3842` + // Minimum execution time: 97_823_000 picoseconds. + Weight::from_parts(102_022_000, 0) + .saturating_add(Weight::from_parts(0, 3842)) + .saturating_add(T::DbWeight::get().reads(9)) + .saturating_add(T::DbWeight::get().writes(5)) } /// Storage: `Benchmark::Override` (r:0 w:0) /// Proof: `Benchmark::Override` (`max_values`: None, `max_size`: None, mode: `Measured`) @@ -130,24 +130,12 @@ 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 execute() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 18_446_744_073_709_551_000 picoseconds. - Weight::from_parts(18_446_744_073_709_551_000, 0) - .saturating_add(Weight::from_parts(0, 0)) - } - /// Storage: `Benchmark::Override` (r:0 w:0) - /// Proof: `Benchmark::Override` (`max_values`: None, `max_size`: None, mode: `Measured`) - fn execute_blob() -> 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) + // Minimum execution time: 8_397_000 picoseconds. + Weight::from_parts(8_773_000, 0) .saturating_add(Weight::from_parts(0, 0)) } /// Storage: `PolkadotXcm::SupportedVersion` (r:0 w:1) @@ -156,8 +144,8 @@ impl pallet_xcm::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 6_074_000 picoseconds. - Weight::from_parts(6_398_000, 0) + // Minimum execution time: 5_806_000 picoseconds. + Weight::from_parts(6_106_000, 0) .saturating_add(Weight::from_parts(0, 0)) .saturating_add(T::DbWeight::get().writes(1)) } @@ -167,8 +155,8 @@ impl pallet_xcm::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 2_036_000 picoseconds. - Weight::from_parts(2_180_000, 0) + // Minimum execution time: 1_802_000 picoseconds. + Weight::from_parts(1_939_000, 0) .saturating_add(Weight::from_parts(0, 0)) .saturating_add(T::DbWeight::get().writes(1)) } @@ -192,8 +180,8 @@ impl pallet_xcm::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `74` // Estimated: `3539` - // Minimum execution time: 25_014_000 picoseconds. - Weight::from_parts(25_374_000, 0) + // Minimum execution time: 24_300_000 picoseconds. + Weight::from_parts(25_359_000, 0) .saturating_add(Weight::from_parts(0, 3539)) .saturating_add(T::DbWeight::get().reads(7)) .saturating_add(T::DbWeight::get().writes(5)) @@ -216,8 +204,8 @@ impl pallet_xcm::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `292` // Estimated: `3757` - // Minimum execution time: 27_616_000 picoseconds. - Weight::from_parts(28_499_000, 0) + // Minimum execution time: 27_579_000 picoseconds. + Weight::from_parts(28_414_000, 0) .saturating_add(Weight::from_parts(0, 3757)) .saturating_add(T::DbWeight::get().reads(6)) .saturating_add(T::DbWeight::get().writes(4)) @@ -228,8 +216,8 @@ impl pallet_xcm::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 2_061_000 picoseconds. - Weight::from_parts(2_153_000, 0) + // Minimum execution time: 1_762_000 picoseconds. + Weight::from_parts(1_884_000, 0) .saturating_add(Weight::from_parts(0, 0)) .saturating_add(T::DbWeight::get().writes(1)) } @@ -239,8 +227,8 @@ impl pallet_xcm::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `89` // Estimated: `13454` - // Minimum execution time: 16_592_000 picoseconds. - Weight::from_parts(16_900_000, 0) + // Minimum execution time: 16_512_000 picoseconds. + Weight::from_parts(16_818_000, 0) .saturating_add(Weight::from_parts(0, 13454)) .saturating_add(T::DbWeight::get().reads(5)) .saturating_add(T::DbWeight::get().writes(2)) @@ -251,8 +239,8 @@ impl pallet_xcm::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `93` // Estimated: `13458` - // Minimum execution time: 16_694_000 picoseconds. - Weight::from_parts(16_905_000, 0) + // Minimum execution time: 16_368_000 picoseconds. + Weight::from_parts(16_887_000, 0) .saturating_add(Weight::from_parts(0, 13458)) .saturating_add(T::DbWeight::get().reads(5)) .saturating_add(T::DbWeight::get().writes(2)) @@ -263,8 +251,8 @@ impl pallet_xcm::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `106` // Estimated: `15946` - // Minimum execution time: 17_779_000 picoseconds. - Weight::from_parts(18_490_000, 0) + // Minimum execution time: 17_661_000 picoseconds. + Weight::from_parts(17_963_000, 0) .saturating_add(Weight::from_parts(0, 15946)) .saturating_add(T::DbWeight::get().reads(6)) } @@ -284,8 +272,8 @@ impl pallet_xcm::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `142` // Estimated: `6082` - // Minimum execution time: 24_526_000 picoseconds. - Weight::from_parts(25_182_000, 0) + // Minimum execution time: 24_498_000 picoseconds. + Weight::from_parts(25_339_000, 0) .saturating_add(Weight::from_parts(0, 6082)) .saturating_add(T::DbWeight::get().reads(7)) .saturating_add(T::DbWeight::get().writes(3)) @@ -296,8 +284,8 @@ impl pallet_xcm::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `136` // Estimated: `11026` - // Minimum execution time: 10_467_000 picoseconds. - Weight::from_parts(10_934_000, 0) + // Minimum execution time: 10_675_000 picoseconds. + Weight::from_parts(11_106_000, 0) .saturating_add(Weight::from_parts(0, 11026)) .saturating_add(T::DbWeight::get().reads(4)) } @@ -307,8 +295,8 @@ impl pallet_xcm::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `100` // Estimated: `13465` - // Minimum execution time: 16_377_000 picoseconds. - Weight::from_parts(17_114_000, 0) + // Minimum execution time: 16_520_000 picoseconds. + Weight::from_parts(16_915_000, 0) .saturating_add(Weight::from_parts(0, 13465)) .saturating_add(T::DbWeight::get().reads(5)) .saturating_add(T::DbWeight::get().writes(2)) @@ -329,8 +317,8 @@ impl pallet_xcm::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `142` // Estimated: `13507` - // Minimum execution time: 32_575_000 picoseconds. - Weight::from_parts(33_483_000, 0) + // Minimum execution time: 32_851_000 picoseconds. + Weight::from_parts(33_772_000, 0) .saturating_add(Weight::from_parts(0, 13507)) .saturating_add(T::DbWeight::get().reads(10)) .saturating_add(T::DbWeight::get().writes(4)) @@ -343,8 +331,8 @@ impl pallet_xcm::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `32` // Estimated: `1517` - // Minimum execution time: 3_604_000 picoseconds. - Weight::from_parts(3_744_000, 0) + // Minimum execution time: 3_373_000 picoseconds. + Weight::from_parts(3_534_000, 0) .saturating_add(Weight::from_parts(0, 1517)) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(2)) @@ -355,8 +343,8 @@ impl pallet_xcm::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `7669` // Estimated: `11134` - // Minimum execution time: 23_983_000 picoseconds. - Weight::from_parts(24_404_000, 0) + // Minimum execution time: 26_027_000 picoseconds. + Weight::from_parts(26_467_000, 0) .saturating_add(Weight::from_parts(0, 11134)) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(1)) @@ -367,8 +355,8 @@ impl pallet_xcm::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `90` // Estimated: `3555` - // Minimum execution time: 34_446_000 picoseconds. - Weight::from_parts(35_465_000, 0) + // Minimum execution time: 35_692_000 picoseconds. + Weight::from_parts(36_136_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/pallet_xcm_benchmarks_fungible.rs b/cumulus/parachains/runtimes/coretime/coretime-rococo/src/weights/xcm/pallet_xcm_benchmarks_fungible.rs index ec71a87b5a753a879a8157f094693140316ca792..7ff1cce2e072339dccd52c0809aafd59337db7b4 100644 --- a/cumulus/parachains/runtimes/coretime/coretime-rococo/src/weights/xcm/pallet_xcm_benchmarks_fungible.rs +++ b/cumulus/parachains/runtimes/coretime/coretime-rococo/src/weights/xcm/pallet_xcm_benchmarks_fungible.rs @@ -16,29 +16,27 @@ //! Autogenerated weights for `pallet_xcm_benchmarks::fungible` //! -//! 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-05-07, 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-unxyhko3-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 -// --template=./cumulus/templates/xcm-bench-template.hbs -// --chain=coretime-rococo-dev -// --wasm-execution=compiled -// --pallet=pallet_xcm_benchmarks::fungible -// --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_benchmarks::fungible +// --chain=coretime-rococo-dev // --header=./cumulus/file_header.txt -// --output=./cumulus/parachains/runtimes/coretime/coretime-rococo/src/weights/xcm/pallet_xcm_benchmarks_fungible.rs +// --template=./cumulus/templates/xcm-bench-template.hbs +// --output=./cumulus/parachains/runtimes/coretime/coretime-rococo/src/weights/xcm/ #![cfg_attr(rustfmt, rustfmt_skip)] #![allow(unused_parens)] @@ -56,8 +54,8 @@ impl WeightInfo { // Proof Size summary in bytes: // Measured: `101` // Estimated: `3593` - // Minimum execution time: 19_199_000 picoseconds. - Weight::from_parts(19_784_000, 3593) + // Minimum execution time: 26_642_000 picoseconds. + Weight::from_parts(27_583_000, 3593) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(1)) } @@ -67,8 +65,8 @@ impl WeightInfo { // Proof Size summary in bytes: // Measured: `101` // Estimated: `6196` - // Minimum execution time: 42_601_000 picoseconds. - Weight::from_parts(43_296_000, 6196) + // Minimum execution time: 35_124_000 picoseconds. + Weight::from_parts(36_510_000, 6196) .saturating_add(T::DbWeight::get().reads(2)) .saturating_add(T::DbWeight::get().writes(2)) } @@ -90,8 +88,8 @@ impl WeightInfo { // Proof Size summary in bytes: // Measured: `207` // Estimated: `6196` - // Minimum execution time: 62_463_000 picoseconds. - Weight::from_parts(64_142_000, 6196) + // Minimum execution time: 55_950_000 picoseconds. + Weight::from_parts(57_207_000, 6196) .saturating_add(T::DbWeight::get().reads(8)) .saturating_add(T::DbWeight::get().writes(4)) } @@ -120,8 +118,8 @@ impl WeightInfo { // Proof Size summary in bytes: // Measured: `106` // Estimated: `3571` - // Minimum execution time: 31_417_000 picoseconds. - Weight::from_parts(32_153_000, 3571) + // Minimum execution time: 23_747_000 picoseconds. + Weight::from_parts(24_424_000, 3571) .saturating_add(T::DbWeight::get().reads(6)) .saturating_add(T::DbWeight::get().writes(2)) } @@ -129,8 +127,8 @@ impl WeightInfo { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 3_235_000 picoseconds. - Weight::from_parts(3_331_000, 0) + // Minimum execution time: 1_853_000 picoseconds. + Weight::from_parts(1_998_000, 0) } // Storage: `System::Account` (r:1 w:1) // Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) @@ -138,13 +136,11 @@ impl WeightInfo { // Proof Size summary in bytes: // Measured: `0` // Estimated: `3593` - // Minimum execution time: 17_701_000 picoseconds. - Weight::from_parts(18_219_000, 3593) + // Minimum execution time: 19_164_000 picoseconds. + Weight::from_parts(19_643_000, 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`) // 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) @@ -153,6 +149,8 @@ impl WeightInfo { // 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) @@ -161,8 +159,8 @@ impl WeightInfo { // Proof Size summary in bytes: // Measured: `106` // Estimated: `3593` - // Minimum execution time: 41_748_000 picoseconds. - Weight::from_parts(42_401_000, 3593) + // Minimum execution time: 48_708_000 picoseconds. + Weight::from_parts(49_610_000, 3593) .saturating_add(T::DbWeight::get().reads(7)) .saturating_add(T::DbWeight::get().writes(3)) } @@ -182,8 +180,8 @@ impl WeightInfo { // Proof Size summary in bytes: // Measured: `106` // Estimated: `3571` - // Minimum execution time: 27_455_000 picoseconds. - Weight::from_parts(27_976_000, 3571) + // Minimum execution time: 20_586_000 picoseconds. + Weight::from_parts(21_147_000, 3571) .saturating_add(T::DbWeight::get().reads(6)) .saturating_add(T::DbWeight::get().writes(2)) } 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 719e7543e8886a803f773126eafbc77f34749ddb..16412eb49a5267d3f3f38cdd285e8f3b248a5f99 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 @@ -16,29 +16,27 @@ //! Autogenerated weights for `pallet_xcm_benchmarks::generic` //! -//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 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-05-07, 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-unxyhko3-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 -// --template=./cumulus/templates/xcm-bench-template.hbs -// --chain=coretime-rococo-dev -// --wasm-execution=compiled -// --pallet=pallet_xcm_benchmarks::generic -// --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_benchmarks::generic +// --chain=coretime-rococo-dev // --header=./cumulus/file_header.txt -// --output=./cumulus/parachains/runtimes/coretime/coretime-rococo/src/weights/xcm/pallet_xcm_benchmarks_generic.rs +// --template=./cumulus/templates/xcm-bench-template.hbs +// --output=./cumulus/parachains/runtimes/coretime/coretime-rococo/src/weights/xcm/ #![cfg_attr(rustfmt, rustfmt_skip)] #![allow(unused_parens)] @@ -66,8 +64,8 @@ impl WeightInfo { // Proof Size summary in bytes: // Measured: `106` // Estimated: `3571` - // Minimum execution time: 35_477_000 picoseconds. - Weight::from_parts(36_129_000, 3571) + // Minimum execution time: 23_760_000 picoseconds. + Weight::from_parts(24_411_000, 3571) .saturating_add(T::DbWeight::get().reads(6)) .saturating_add(T::DbWeight::get().writes(2)) } @@ -75,8 +73,8 @@ impl WeightInfo { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 2_243_000 picoseconds. - Weight::from_parts(2_329_000, 0) + // Minimum execution time: 522_000 picoseconds. + Weight::from_parts(546_000, 0) } // Storage: `PolkadotXcm::Queries` (r:1 w:0) // Proof: `PolkadotXcm::Queries` (`max_values`: None, `max_size`: None, mode: `Measured`) @@ -84,58 +82,58 @@ impl WeightInfo { // Proof Size summary in bytes: // Measured: `32` // Estimated: `3497` - // Minimum execution time: 8_112_000 picoseconds. - Weight::from_parts(8_275_000, 3497) + // Minimum execution time: 5_830_000 picoseconds. + Weight::from_parts(6_069_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: 8_960_000 picoseconds. - Weight::from_parts(9_253_000, 0) + // Minimum execution time: 5_508_000 picoseconds. + Weight::from_parts(5_801_000, 0) } pub fn refund_surplus() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 2_332_000 picoseconds. - Weight::from_parts(2_438_000, 0) + // Minimum execution time: 1_130_000 picoseconds. + Weight::from_parts(1_239_000, 0) } pub fn set_error_handler() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 2_054_000 picoseconds. - Weight::from_parts(2_119_000, 0) + // Minimum execution time: 541_000 picoseconds. + Weight::from_parts(567_000, 0) } pub fn set_appendix() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 2_061_000 picoseconds. - Weight::from_parts(2_133_000, 0) + // Minimum execution time: 560_000 picoseconds. + Weight::from_parts(591_000, 0) } pub fn clear_error() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 2_054_000 picoseconds. - Weight::from_parts(2_128_000, 0) + // Minimum execution time: 505_000 picoseconds. + Weight::from_parts(547_000, 0) } pub fn descend_origin() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 2_791_000 picoseconds. - Weight::from_parts(2_903_000, 0) + // Minimum execution time: 538_000 picoseconds. + Weight::from_parts(565_000, 0) } pub fn clear_origin() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 2_088_000 picoseconds. - Weight::from_parts(2_153_000, 0) + // Minimum execution time: 514_000 picoseconds. + Weight::from_parts(541_000, 0) } // Storage: `ParachainInfo::ParachainId` (r:1 w:0) // Proof: `ParachainInfo::ParachainId` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) @@ -153,8 +151,8 @@ impl WeightInfo { // Proof Size summary in bytes: // Measured: `106` // Estimated: `3571` - // Minimum execution time: 27_721_000 picoseconds. - Weight::from_parts(28_602_000, 3571) + // Minimum execution time: 20_920_000 picoseconds. + Weight::from_parts(21_437_000, 3571) .saturating_add(T::DbWeight::get().reads(6)) .saturating_add(T::DbWeight::get().writes(2)) } @@ -164,8 +162,8 @@ impl WeightInfo { // Proof Size summary in bytes: // Measured: `90` // Estimated: `3555` - // Minimum execution time: 11_468_000 picoseconds. - Weight::from_parts(11_866_000, 3555) + // Minimum execution time: 8_549_000 picoseconds. + Weight::from_parts(8_821_000, 3555) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(1)) } @@ -173,8 +171,8 @@ impl WeightInfo { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 2_125_000 picoseconds. - Weight::from_parts(2_167_000, 0) + // Minimum execution time: 525_000 picoseconds. + Weight::from_parts(544_000, 0) } // Storage: `PolkadotXcm::VersionNotifyTargets` (r:1 w:1) // Proof: `PolkadotXcm::VersionNotifyTargets` (`max_values`: None, `max_size`: None, mode: `Measured`) @@ -192,8 +190,8 @@ impl WeightInfo { // Proof Size summary in bytes: // Measured: `74` // Estimated: `3539` - // Minimum execution time: 22_422_000 picoseconds. - Weight::from_parts(22_924_000, 3539) + // Minimum execution time: 19_645_000 picoseconds. + Weight::from_parts(20_104_000, 3539) .saturating_add(T::DbWeight::get().reads(6)) .saturating_add(T::DbWeight::get().writes(3)) } @@ -203,44 +201,44 @@ impl WeightInfo { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 3_880_000 picoseconds. - Weight::from_parts(4_050_000, 0) + // Minimum execution time: 2_232_000 picoseconds. + Weight::from_parts(2_334_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: 3_432_000 picoseconds. - Weight::from_parts(3_536_000, 0) + // Minimum execution time: 883_000 picoseconds. + Weight::from_parts(945_000, 0) } pub fn expect_asset() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 2_213_000 picoseconds. - Weight::from_parts(2_286_000, 0) + // Minimum execution time: 600_000 picoseconds. + Weight::from_parts(645_000, 0) } pub fn expect_origin() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 2_155_000 picoseconds. - Weight::from_parts(2_239_000, 0) + // Minimum execution time: 527_000 picoseconds. + Weight::from_parts(552_000, 0) } pub fn expect_error() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 2_093_000 picoseconds. - Weight::from_parts(2_139_000, 0) + // Minimum execution time: 527_000 picoseconds. + Weight::from_parts(550_000, 0) } pub fn expect_transact_status() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 2_345_000 picoseconds. - Weight::from_parts(2_378_000, 0) + // Minimum execution time: 657_000 picoseconds. + Weight::from_parts(703_000, 0) } // Storage: `ParachainInfo::ParachainId` (r:1 w:0) // Proof: `ParachainInfo::ParachainId` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) @@ -258,8 +256,8 @@ impl WeightInfo { // Proof Size summary in bytes: // Measured: `106` // Estimated: `3571` - // Minimum execution time: 31_543_000 picoseconds. - Weight::from_parts(32_075_000, 3571) + // Minimum execution time: 24_999_000 picoseconds. + Weight::from_parts(25_671_000, 3571) .saturating_add(T::DbWeight::get().reads(6)) .saturating_add(T::DbWeight::get().writes(2)) } @@ -267,8 +265,8 @@ impl WeightInfo { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 4_416_000 picoseconds. - Weight::from_parts(4_613_000, 0) + // Minimum execution time: 3_159_000 picoseconds. + Weight::from_parts(3_296_000, 0) } // Storage: `ParachainInfo::ParachainId` (r:1 w:0) // Proof: `ParachainInfo::ParachainId` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) @@ -286,8 +284,8 @@ impl WeightInfo { // Proof Size summary in bytes: // Measured: `106` // Estimated: `3571` - // Minimum execution time: 28_050_000 picoseconds. - Weight::from_parts(28_755_000, 3571) + // Minimum execution time: 21_052_000 picoseconds. + Weight::from_parts(22_153_000, 3571) .saturating_add(T::DbWeight::get().reads(6)) .saturating_add(T::DbWeight::get().writes(2)) } @@ -295,35 +293,35 @@ impl WeightInfo { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 2_073_000 picoseconds. - Weight::from_parts(2_181_000, 0) + // Minimum execution time: 547_000 picoseconds. + Weight::from_parts(584_000, 0) } pub fn set_topic() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 2_049_000 picoseconds. - Weight::from_parts(2_137_000, 0) + // Minimum execution time: 506_000 picoseconds. + Weight::from_parts(551_000, 0) } pub fn clear_topic() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 2_082_000 picoseconds. - Weight::from_parts(2_144_000, 0) + // Minimum execution time: 508_000 picoseconds. + Weight::from_parts(527_000, 0) } pub fn set_fees_mode() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 2_043_000 picoseconds. - Weight::from_parts(2_151_000, 0) + // Minimum execution time: 527_000 picoseconds. + Weight::from_parts(558_000, 0) } pub fn unpaid_execution() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 2_197_000 picoseconds. - Weight::from_parts(2_293_000, 0) + // Minimum execution time: 514_000 picoseconds. + Weight::from_parts(553_000, 0) } } diff --git a/cumulus/parachains/runtimes/coretime/coretime-rococo/src/xcm_config.rs b/cumulus/parachains/runtimes/coretime/coretime-rococo/src/xcm_config.rs index 7580ab33b8d63ae7f4510e784b22e60bea3b78da..c16b40b8675fbce2878bca4ba1106b89bbd9e9b1 100644 --- a/cumulus/parachains/runtimes/coretime/coretime-rococo/src/xcm_config.rs +++ b/cumulus/parachains/runtimes/coretime/coretime-rococo/src/xcm_config.rs @@ -39,16 +39,16 @@ use polkadot_runtime_common::xcm_sender::ExponentialPrice; use sp_runtime::traits::AccountIdConversion; use xcm::latest::prelude::*; use xcm_builder::{ - AccountId32Aliases, AllowExplicitUnpaidExecutionFrom, AllowKnownQueryResponses, - AllowSubscriptionsFrom, AllowTopLevelPaidExecutionFrom, DenyReserveTransferToRelayChain, - DenyThenTry, EnsureXcmOrigin, FrameTransactionalProcessor, FungibleAdapter, IsConcrete, - NonFungibleAdapter, ParentAsSuperuser, ParentIsPreset, RelayChainAsNative, - SiblingParachainAsNative, SiblingParachainConvertsVia, SignedAccountId32AsNative, - SignedToAccountId32, SovereignSignedViaLocation, TakeWeightCredit, TrailingSetTopicAsId, - UsingComponents, WeightInfoBounds, WithComputedOrigin, WithUniqueTopic, + AccountId32Aliases, AllowExplicitUnpaidExecutionFrom, AllowHrmpNotificationsFromRelayChain, + AllowKnownQueryResponses, AllowSubscriptionsFrom, AllowTopLevelPaidExecutionFrom, + DenyReserveTransferToRelayChain, 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}; +use xcm_executor::XcmExecutor; parameter_types! { pub const RocRelayLocation: Location = Location::parent(); @@ -139,49 +139,6 @@ impl Contains for ParentOrParentsPlurality { } } -/// A call filter for the XCM Transact instruction. This is a temporary measure until we properly -/// account for proof size weights. -/// -/// Calls that are allowed through this filter must: -/// 1. Have a fixed weight; -/// 2. Cannot lead to another call being made; -/// 3. Have a defined proof size weight, e.g. no unbounded vecs in call parameters. -pub struct SafeCallFilter; -impl Contains for SafeCallFilter { - fn contains(call: &RuntimeCall) -> bool { - #[cfg(feature = "runtime-benchmarks")] - { - if matches!(call, RuntimeCall::System(frame_system::Call::remark_with_event { .. })) { - return true - } - } - - matches!( - call, - RuntimeCall::PolkadotXcm( - pallet_xcm::Call::force_xcm_version { .. } | - 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 { .. } | - // 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::Sudo(..) | - RuntimeCall::CollatorSelection(..) | - RuntimeCall::Session(pallet_session::Call::purge_keys { .. }) | - RuntimeCall::XcmpQueue(..) | - RuntimeCall::Broker(..) - ) - } -} - pub type Barrier = TrailingSetTopicAsId< DenyThenTry< DenyReserveTransferToRelayChain, @@ -199,6 +156,8 @@ pub type Barrier = TrailingSetTopicAsId< AllowExplicitUnpaidExecutionFrom, // Subscriptions for version tracking are OK. AllowSubscriptionsFrom, + // HRMP notifications from the relay chain are OK. + AllowHrmpNotificationsFromRelayChain, ), UniversalLocation, ConstU32<8>, @@ -258,13 +217,14 @@ impl xcm_executor::Config for XcmConfig { >; type MessageExporter = (); type UniversalAliases = Nothing; - type CallDispatcher = WithOriginFilter; - type SafeCallFilter = SafeCallFilter; + type CallDispatcher = RuntimeCall; + type SafeCallFilter = Everything; type Aliasers = Nothing; type TransactionalProcessor = FrameTransactionalProcessor; type HrmpNewChannelOpenRequestHandler = (); type HrmpChannelAcceptedHandler = (); type HrmpChannelClosingHandler = (); + type XcmRecorder = PolkadotXcm; } /// Converts a local signed origin into an XCM location. Forms the basis for local origins @@ -293,7 +253,7 @@ impl pallet_xcm::Config for Runtime { type XcmExecuteFilter = Everything; type XcmExecutor = XcmExecutor; type XcmTeleportFilter = Everything; - type XcmReserveTransferFilter = Nothing; // This parachain is not meant as a reserve location. + type XcmReserveTransferFilter = Everything; type Weigher = WeightInfoBounds< crate::weights::xcm::CoretimeRococoXcmWeight, RuntimeCall, diff --git a/cumulus/parachains/runtimes/coretime/coretime-westend/Cargo.toml b/cumulus/parachains/runtimes/coretime/coretime-westend/Cargo.toml index 60cc7e2f765477052332b4c422facb8b19e1f5a4..a377e243af3a80b4a2643bc0f142a00a126d2ead 100644 --- a/cumulus/parachains/runtimes/coretime/coretime-westend/Cargo.toml +++ b/cumulus/parachains/runtimes/coretime/coretime-westend/Cargo.toml @@ -13,7 +13,7 @@ workspace = true 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.6.12", default-features = false, features = ["derive"] } hex-literal = "0.4.1" log = { workspace = true } scale-info = { version = "2.9.0", default-features = false, features = ["derive"] } diff --git a/cumulus/parachains/runtimes/coretime/coretime-westend/src/lib.rs b/cumulus/parachains/runtimes/coretime/coretime-westend/src/lib.rs index 1ee8c3bc0ec3d4f9b3201659cca5f388a05e78e1..fca1b0e7c6ec4146300e996233ed3962dc6b5c23 100644 --- a/cumulus/parachains/runtimes/coretime/coretime-westend/src/lib.rs +++ b/cumulus/parachains/runtimes/coretime/coretime-westend/src/lib.rs @@ -108,7 +108,9 @@ pub type UncheckedExtrinsic = /// Migrations to apply on runtime upgrade. pub type Migrations = ( + pallet_collator_selection::migration::v2::MigrationToV2, cumulus_pallet_xcmp_queue::migration::v4::MigrationToV4, + pallet_broker::migration::MigrateV0ToV1, // permanent pallet_xcm::migration::MigrateToLatestXcmVersion, ); @@ -134,10 +136,10 @@ 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_010_000, + spec_version: 1_011_000, impl_version: 0, apis: RUNTIME_API_VERSIONS, - transaction_version: 0, + transaction_version: 1, state_version: 1, }; @@ -218,6 +220,7 @@ impl pallet_authorship::Config for Runtime { parameter_types! { pub const ExistentialDeposit: Balance = EXISTENTIAL_DEPOSIT; + pub const RandomParaId: ParaId = ParaId::new(43211234); } impl pallet_balances::Config for Runtime { @@ -299,7 +302,7 @@ impl pallet_message_queue::Config for Runtime { // The XCMP queue pallet is only ever able to handle the `Sibling(ParaId)` origin: type QueueChangeHandler = NarrowOriginToSibling; type QueuePausedQuery = NarrowOriginToSibling; - type HeapSize = sp_core::ConstU32<{ 64 * 1024 }>; + type HeapSize = sp_core::ConstU32<{ 103 * 1024 }>; type MaxStale = sp_core::ConstU32<8>; type ServiceWeight = MessageQueueServiceWeight; type IdleMaxServiceWeight = MessageQueueServiceWeight; @@ -339,13 +342,22 @@ impl cumulus_pallet_xcmp_queue::Config for Runtime { type ChannelInfo = ParachainSystem; type VersionWrapper = PolkadotXcm; type XcmpQueue = TransformOrigin; - type MaxInboundSuspended = sp_core::ConstU32<1_000>; + type MaxInboundSuspended = ConstU32<1_000>; + type MaxActiveOutboundChannels = ConstU32<128>; + // Most on-chain HRMP channels are configured to use 102400 bytes of max message size, so we + // need to set the page size larger than that until we reduce the channel size on-chain. + type MaxPageSize = ConstU32<{ 103 * 1024 }>; type ControllerOrigin = RootOrFellows; type ControllerOriginConverter = XcmOriginToTransactDispatchOrigin; type WeightInfo = weights::cumulus_pallet_xcmp_queue::WeightInfo; type PriceForSiblingDelivery = PriceForSiblingParachainDelivery; } +impl cumulus_pallet_xcmp_queue::migration::v5::V5Config for Runtime { + // This must be the same as the `ChannelInfo` from the `Config`: + type ChannelList = ParachainSystem; +} + pub const PERIOD: u32 = 6 * HOURS; pub const OFFSET: u32 = 0; @@ -710,11 +722,20 @@ 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, - >; + 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()) @@ -732,8 +753,21 @@ impl_runtime_apis! { } fn reserve_transferable_asset_and_dest() -> Option<(Asset, Location)> { - // Reserve transfers are disabled - None + // Coretime chain can reserve transfer regions to some random parachain. + + // Properties of a mock region: + let core = 0; + let begin = 0; + let end = 42; + + let region_id = pallet_broker::Pallet::::issue(core, begin, end, None, None); + Some(( + Asset { + fun: NonFungible(Index(region_id.into())), + id: AssetId(xcm_config::BrokerPalletLocation::get()) + }, + ParentThen(Parachain(RandomParaId::get().into()).into()).into(), + )) } fn get_asset() -> Asset { @@ -753,11 +787,22 @@ impl_runtime_apis! { impl pallet_xcm_benchmarks::Config for Runtime { type XcmConfig = xcm_config::XcmConfig; - type DeliveryHelper = cumulus_primitives_utility::ToParentDeliveryHelper< - xcm_config::XcmConfig, - ExistentialDepositAsset, - xcm_config::PriceForParentDelivery, - >; + + 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, + > + ); + type AccountIdConverter = xcm_config::LocationToAccountId; fn valid_destination() -> Result { Ok(TokenRelayLocation::get()) 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 c4770a7c94381cfca9404a6577c703164f215918..7024c58d97f961199784890142dbde3558e16ab4 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,25 +17,23 @@ //! Autogenerated weights for `pallet_balances` //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 32.0.0 -//! DATE: 2024-02-08, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! DATE: 2024-05-06, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` //! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `runner-bn-ce5rx-project-674-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` +//! HOSTNAME: `runner-unxyhko3-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 -// --chain=coretime-westend-dev -// --wasm-execution=compiled -// --pallet=pallet_balances -// --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_balances +// --chain=coretime-westend-dev // --header=./cumulus/file_header.txt // --output=./cumulus/parachains/runtimes/coretime/coretime-westend/src/weights/ @@ -56,8 +54,8 @@ impl pallet_balances::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `0` // Estimated: `3593` - // Minimum execution time: 42_773_000 picoseconds. - Weight::from_parts(43_292_000, 0) + // Minimum execution time: 44_250_000 picoseconds. + Weight::from_parts(45_303_000, 0) .saturating_add(Weight::from_parts(0, 3593)) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(1)) @@ -68,8 +66,8 @@ impl pallet_balances::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `0` // Estimated: `3593` - // Minimum execution time: 34_023_000 picoseconds. - Weight::from_parts(34_513_000, 0) + // Minimum execution time: 34_451_000 picoseconds. + Weight::from_parts(35_413_000, 0) .saturating_add(Weight::from_parts(0, 3593)) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(1)) @@ -80,8 +78,8 @@ impl pallet_balances::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `103` // Estimated: `3593` - // Minimum execution time: 11_685_000 picoseconds. - Weight::from_parts(12_103_000, 0) + // Minimum execution time: 11_886_000 picoseconds. + Weight::from_parts(12_158_000, 0) .saturating_add(Weight::from_parts(0, 3593)) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(1)) @@ -92,8 +90,8 @@ impl pallet_balances::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `103` // Estimated: `3593` - // Minimum execution time: 16_233_000 picoseconds. - Weight::from_parts(16_706_000, 0) + // Minimum execution time: 16_457_000 picoseconds. + Weight::from_parts(16_940_000, 0) .saturating_add(Weight::from_parts(0, 3593)) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(1)) @@ -104,8 +102,8 @@ impl pallet_balances::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `103` // Estimated: `6196` - // Minimum execution time: 43_909_000 picoseconds. - Weight::from_parts(44_683_000, 0) + // Minimum execution time: 45_416_000 picoseconds. + Weight::from_parts(46_173_000, 0) .saturating_add(Weight::from_parts(0, 6196)) .saturating_add(T::DbWeight::get().reads(2)) .saturating_add(T::DbWeight::get().writes(2)) @@ -116,8 +114,8 @@ impl pallet_balances::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `0` // Estimated: `3593` - // Minimum execution time: 42_081_000 picoseconds. - Weight::from_parts(42_553_000, 0) + // Minimum execution time: 43_502_000 picoseconds. + Weight::from_parts(44_060_000, 0) .saturating_add(Weight::from_parts(0, 3593)) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(1)) @@ -128,8 +126,8 @@ impl pallet_balances::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `103` // Estimated: `3593` - // Minimum execution time: 14_413_000 picoseconds. - Weight::from_parts(14_827_000, 0) + // Minimum execution time: 14_790_000 picoseconds. + Weight::from_parts(15_451_000, 0) .saturating_add(Weight::from_parts(0, 3593)) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(1)) @@ -141,11 +139,11 @@ impl pallet_balances::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `0 + u * (136 ±0)` // Estimated: `990 + u * (2603 ±0)` - // Minimum execution time: 14_189_000 picoseconds. - Weight::from_parts(14_587_000, 0) + // Minimum execution time: 14_582_000 picoseconds. + Weight::from_parts(14_797_000, 0) .saturating_add(Weight::from_parts(0, 990)) - // Standard Error: 10_909 - .saturating_add(Weight::from_parts(13_040_864, 0).saturating_mul(u.into())) + // Standard Error: 12_074 + .saturating_add(Weight::from_parts(13_220_968, 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())) @@ -156,9 +154,25 @@ impl pallet_balances::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `0` // Estimated: `1501` - // Minimum execution time: 5_218_000 picoseconds. - Weight::from_parts(5_562_000, 0) + // Minimum execution time: 4_939_000 picoseconds. + Weight::from_parts(5_403_000, 0) .saturating_add(Weight::from_parts(0, 1501)) .saturating_add(T::DbWeight::get().reads(1)) } + fn burn_allow_death() -> Weight { + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 27_479_000 picoseconds. + Weight::from_parts(28_384_000, 0) + .saturating_add(Weight::from_parts(0, 0)) + } + fn burn_keep_alive() -> Weight { + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 18_174_000 picoseconds. + Weight::from_parts(18_737_000, 0) + .saturating_add(Weight::from_parts(0, 0)) + } } 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 a1701c5f1c2ced1bbdcac49863cc05ceb28a019f..fa588e982f0965218fa9cca7f93a20f9f70b37c5 100644 --- a/cumulus/parachains/runtimes/coretime/coretime-westend/src/weights/pallet_xcm.rs +++ b/cumulus/parachains/runtimes/coretime/coretime-westend/src/weights/pallet_xcm.rs @@ -17,9 +17,9 @@ //! Autogenerated weights for `pallet_xcm` //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 32.0.0 -//! DATE: 2024-03-21, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! DATE: 2024-05-07, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` //! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `runner-h2rr8wx7-project-674-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` +//! HOSTNAME: `runner-unxyhko3-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: @@ -62,12 +62,14 @@ impl pallet_xcm::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `74` // Estimated: `3539` - // Minimum execution time: 17_681_000 picoseconds. - Weight::from_parts(18_350_000, 0) + // Minimum execution time: 18_707_000 picoseconds. + Weight::from_parts(19_391_000, 0) .saturating_add(Weight::from_parts(0, 3539)) .saturating_add(T::DbWeight::get().reads(5)) .saturating_add(T::DbWeight::get().writes(2)) } + /// Storage: `ParachainInfo::ParachainId` (r:1 w:0) + /// Proof: `ParachainInfo::ParachainId` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) /// Storage: `PolkadotXcm::SupportedVersion` (r:1 w:0) /// Proof: `PolkadotXcm::SupportedVersion` (`max_values`: None, `max_size`: None, mode: `Measured`) /// Storage: `PolkadotXcm::VersionDiscoveryQueue` (r:1 w:1) @@ -78,47 +80,45 @@ 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 send_blob() -> Weight { + fn teleport_assets() -> Weight { // Proof Size summary in bytes: - // Measured: `74` - // Estimated: `3539` - // Minimum execution time: 18_091_000 picoseconds. - Weight::from_parts(18_327_000, 0) - .saturating_add(Weight::from_parts(0, 3539)) - .saturating_add(T::DbWeight::get().reads(5)) + // Measured: `106` + // Estimated: `3571` + // Minimum execution time: 61_874_000 picoseconds. + Weight::from_parts(63_862_000, 0) + .saturating_add(Weight::from_parts(0, 3571)) + .saturating_add(T::DbWeight::get().reads(6)) .saturating_add(T::DbWeight::get().writes(2)) } /// Storage: `ParachainInfo::ParachainId` (r:1 w:0) /// Proof: `ParachainInfo::ParachainId` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) + /// Storage: `Broker::Regions` (r:1 w:1) + /// Proof: `Broker::Regions` (`max_values`: None, `max_size`: Some(86), added: 2561, mode: `MaxEncodedLen`) + /// Storage: `XcmpQueue::DeliveryFeeFactor` (r:1 w:0) + /// Proof: `XcmpQueue::DeliveryFeeFactor` (`max_values`: None, `max_size`: None, mode: `Measured`) /// 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: `106` - // Estimated: `3571` - // Minimum execution time: 54_943_000 picoseconds. - Weight::from_parts(56_519_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: `Benchmark::Override` (`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: `ParachainSystem::RelevantMessagingState` (r:1 w:0) + /// Proof: `ParachainSystem::RelevantMessagingState` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `XcmpQueue::OutboundXcmpStatus` (r:1 w:1) + /// Proof: `XcmpQueue::OutboundXcmpStatus` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `XcmpQueue::OutboundXcmpMessages` (r:0 w:1) + /// Proof: `XcmpQueue::OutboundXcmpMessages` (`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)) + // Measured: `377` + // Estimated: `3842` + // Minimum execution time: 98_657_000 picoseconds. + Weight::from_parts(101_260_000, 0) + .saturating_add(Weight::from_parts(0, 3842)) + .saturating_add(T::DbWeight::get().reads(9)) + .saturating_add(T::DbWeight::get().writes(5)) } /// Storage: `Benchmark::Override` (r:0 w:0) /// Proof: `Benchmark::Override` (`max_values`: None, `max_size`: None, mode: `Measured`) @@ -130,24 +130,12 @@ 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 execute() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 18_446_744_073_709_551_000 picoseconds. - Weight::from_parts(18_446_744_073_709_551_000, 0) - .saturating_add(Weight::from_parts(0, 0)) - } - /// Storage: `Benchmark::Override` (r:0 w:0) - /// Proof: `Benchmark::Override` (`max_values`: None, `max_size`: None, mode: `Measured`) - fn execute_blob() -> 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) + // Minimum execution time: 8_455_000 picoseconds. + Weight::from_parts(8_842_000, 0) .saturating_add(Weight::from_parts(0, 0)) } /// Storage: `PolkadotXcm::SupportedVersion` (r:0 w:1) @@ -156,8 +144,8 @@ impl pallet_xcm::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 5_887_000 picoseconds. - Weight::from_parts(6_101_000, 0) + // Minimum execution time: 5_850_000 picoseconds. + Weight::from_parts(6_044_000, 0) .saturating_add(Weight::from_parts(0, 0)) .saturating_add(T::DbWeight::get().writes(1)) } @@ -167,8 +155,8 @@ impl pallet_xcm::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_940_000 picoseconds. - Weight::from_parts(2_022_000, 0) + // Minimum execution time: 1_754_000 picoseconds. + Weight::from_parts(1_832_000, 0) .saturating_add(Weight::from_parts(0, 0)) .saturating_add(T::DbWeight::get().writes(1)) } @@ -192,8 +180,8 @@ impl pallet_xcm::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `74` // Estimated: `3539` - // Minimum execution time: 23_165_000 picoseconds. - Weight::from_parts(23_800_000, 0) + // Minimum execution time: 24_886_000 picoseconds. + Weight::from_parts(25_403_000, 0) .saturating_add(Weight::from_parts(0, 3539)) .saturating_add(T::DbWeight::get().reads(7)) .saturating_add(T::DbWeight::get().writes(5)) @@ -216,8 +204,8 @@ impl pallet_xcm::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `292` // Estimated: `3757` - // Minimum execution time: 26_506_000 picoseconds. - Weight::from_parts(27_180_000, 0) + // Minimum execution time: 28_114_000 picoseconds. + Weight::from_parts(28_414_000, 0) .saturating_add(Weight::from_parts(0, 3757)) .saturating_add(T::DbWeight::get().reads(6)) .saturating_add(T::DbWeight::get().writes(4)) @@ -228,8 +216,8 @@ impl pallet_xcm::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_868_000 picoseconds. - Weight::from_parts(2_002_000, 0) + // Minimum execution time: 1_713_000 picoseconds. + Weight::from_parts(1_810_000, 0) .saturating_add(Weight::from_parts(0, 0)) .saturating_add(T::DbWeight::get().writes(1)) } @@ -239,8 +227,8 @@ impl pallet_xcm::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `89` // Estimated: `13454` - // Minimum execution time: 16_138_000 picoseconds. - Weight::from_parts(16_447_000, 0) + // Minimum execution time: 15_910_000 picoseconds. + Weight::from_parts(16_256_000, 0) .saturating_add(Weight::from_parts(0, 13454)) .saturating_add(T::DbWeight::get().reads(5)) .saturating_add(T::DbWeight::get().writes(2)) @@ -251,8 +239,8 @@ impl pallet_xcm::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `93` // Estimated: `13458` - // Minimum execution time: 16_099_000 picoseconds. - Weight::from_parts(16_592_000, 0) + // Minimum execution time: 15_801_000 picoseconds. + Weight::from_parts(16_298_000, 0) .saturating_add(Weight::from_parts(0, 13458)) .saturating_add(T::DbWeight::get().reads(5)) .saturating_add(T::DbWeight::get().writes(2)) @@ -263,8 +251,8 @@ impl pallet_xcm::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `106` // Estimated: `15946` - // Minimum execution time: 17_972_000 picoseconds. - Weight::from_parts(18_379_000, 0) + // Minimum execution time: 17_976_000 picoseconds. + Weight::from_parts(18_390_000, 0) .saturating_add(Weight::from_parts(0, 15946)) .saturating_add(T::DbWeight::get().reads(6)) } @@ -284,8 +272,8 @@ impl pallet_xcm::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `142` // Estimated: `6082` - // Minimum execution time: 23_554_000 picoseconds. - Weight::from_parts(24_446_000, 0) + // Minimum execution time: 24_723_000 picoseconds. + Weight::from_parts(25_531_000, 0) .saturating_add(Weight::from_parts(0, 6082)) .saturating_add(T::DbWeight::get().reads(7)) .saturating_add(T::DbWeight::get().writes(3)) @@ -296,8 +284,8 @@ impl pallet_xcm::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `136` // Estimated: `11026` - // Minimum execution time: 10_541_000 picoseconds. - Weight::from_parts(10_894_000, 0) + // Minimum execution time: 10_954_000 picoseconds. + Weight::from_parts(11_199_000, 0) .saturating_add(Weight::from_parts(0, 11026)) .saturating_add(T::DbWeight::get().reads(4)) } @@ -307,8 +295,8 @@ impl pallet_xcm::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `100` // Estimated: `13465` - // Minimum execution time: 16_404_000 picoseconds. - Weight::from_parts(16_818_000, 0) + // Minimum execution time: 16_561_000 picoseconds. + Weight::from_parts(16_908_000, 0) .saturating_add(Weight::from_parts(0, 13465)) .saturating_add(T::DbWeight::get().reads(5)) .saturating_add(T::DbWeight::get().writes(2)) @@ -329,8 +317,8 @@ impl pallet_xcm::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `142` // Estimated: `13507` - // Minimum execution time: 31_617_000 picoseconds. - Weight::from_parts(32_336_000, 0) + // Minimum execution time: 33_279_000 picoseconds. + Weight::from_parts(33_869_000, 0) .saturating_add(Weight::from_parts(0, 13507)) .saturating_add(T::DbWeight::get().reads(10)) .saturating_add(T::DbWeight::get().writes(4)) @@ -343,8 +331,8 @@ impl pallet_xcm::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `32` // Estimated: `1517` - // Minimum execution time: 3_328_000 picoseconds. - Weight::from_parts(3_501_000, 0) + // Minimum execution time: 3_405_000 picoseconds. + Weight::from_parts(3_489_000, 0) .saturating_add(Weight::from_parts(0, 1517)) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(2)) @@ -355,8 +343,8 @@ impl pallet_xcm::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `7669` // Estimated: `11134` - // Minimum execution time: 23_571_000 picoseconds. - Weight::from_parts(24_312_000, 0) + // Minimum execution time: 24_387_000 picoseconds. + Weight::from_parts(25_143_000, 0) .saturating_add(Weight::from_parts(0, 11134)) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(1)) @@ -367,8 +355,8 @@ impl pallet_xcm::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `90` // Estimated: `3555` - // Minimum execution time: 32_879_000 picoseconds. - Weight::from_parts(33_385_000, 0) + // Minimum execution time: 35_229_000 picoseconds. + Weight::from_parts(36_035_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/pallet_xcm_benchmarks_fungible.rs b/cumulus/parachains/runtimes/coretime/coretime-westend/src/weights/xcm/pallet_xcm_benchmarks_fungible.rs index 6f5a52de98c39fb7ff5de96c41652be063f56a74..8e1461c4a99e2e95dea078280844a157ab4084de 100644 --- a/cumulus/parachains/runtimes/coretime/coretime-westend/src/weights/xcm/pallet_xcm_benchmarks_fungible.rs +++ b/cumulus/parachains/runtimes/coretime/coretime-westend/src/weights/xcm/pallet_xcm_benchmarks_fungible.rs @@ -17,28 +17,26 @@ //! Autogenerated weights for `pallet_xcm_benchmarks::fungible` //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 32.0.0 -//! DATE: 2024-02-08, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! DATE: 2024-05-07, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` //! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `runner-bn-ce5rx-project-674-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` +//! HOSTNAME: `runner-unxyhko3-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 -// --template=./cumulus/templates/xcm-bench-template.hbs -// --chain=coretime-westend-dev -// --wasm-execution=compiled -// --pallet=pallet_xcm_benchmarks::fungible -// --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_benchmarks::fungible +// --chain=coretime-westend-dev // --header=./cumulus/file_header.txt -// --output=./cumulus/parachains/runtimes/coretime/coretime-westend/src/weights/xcm/pallet_xcm_benchmarks_fungible.rs +// --template=./cumulus/templates/xcm-bench-template.hbs +// --output=./cumulus/parachains/runtimes/coretime/coretime-westend/src/weights/xcm/ #![cfg_attr(rustfmt, rustfmt_skip)] #![allow(unused_parens)] @@ -56,8 +54,8 @@ impl WeightInfo { // Proof Size summary in bytes: // Measured: `101` // Estimated: `3593` - // Minimum execution time: 19_401_000 picoseconds. - Weight::from_parts(19_768_000, 3593) + // Minimum execution time: 26_842_000 picoseconds. + Weight::from_parts(27_606_000, 3593) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(1)) } @@ -67,8 +65,8 @@ impl WeightInfo { // Proof Size summary in bytes: // Measured: `101` // Estimated: `6196` - // Minimum execution time: 42_452_000 picoseconds. - Weight::from_parts(43_126_000, 6196) + // Minimum execution time: 35_076_000 picoseconds. + Weight::from_parts(36_109_000, 6196) .saturating_add(T::DbWeight::get().reads(2)) .saturating_add(T::DbWeight::get().writes(2)) } @@ -90,8 +88,8 @@ impl WeightInfo { // Proof Size summary in bytes: // Measured: `207` // Estimated: `6196` - // Minimum execution time: 58_090_000 picoseconds. - Weight::from_parts(59_502_000, 6196) + // Minimum execution time: 56_951_000 picoseconds. + Weight::from_parts(58_286_000, 6196) .saturating_add(T::DbWeight::get().reads(8)) .saturating_add(T::DbWeight::get().writes(4)) } @@ -120,8 +118,8 @@ impl WeightInfo { // Proof Size summary in bytes: // Measured: `106` // Estimated: `3571` - // Minimum execution time: 23_569_000 picoseconds. - Weight::from_parts(24_598_000, 3571) + // Minimum execution time: 23_796_000 picoseconds. + Weight::from_parts(24_692_000, 3571) .saturating_add(T::DbWeight::get().reads(6)) .saturating_add(T::DbWeight::get().writes(2)) } @@ -129,8 +127,8 @@ impl WeightInfo { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 2_546_000 picoseconds. - Weight::from_parts(2_674_000, 0) + // Minimum execution time: 1_990_000 picoseconds. + Weight::from_parts(2_142_000, 0) } // Storage: `System::Account` (r:1 w:1) // Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) @@ -138,11 +136,13 @@ impl WeightInfo { // Proof Size summary in bytes: // Measured: `0` // Estimated: `3593` - // Minimum execution time: 16_889_000 picoseconds. - Weight::from_parts(17_350_000, 3593) + // Minimum execution time: 19_572_000 picoseconds. + Weight::from_parts(20_017_000, 3593) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(1)) } + // 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) @@ -151,8 +151,6 @@ impl WeightInfo { // 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) @@ -161,8 +159,8 @@ impl WeightInfo { // Proof Size summary in bytes: // Measured: `106` // Estimated: `3593` - // Minimum execution time: 43_964_000 picoseconds. - Weight::from_parts(45_293_000, 3593) + // Minimum execution time: 49_336_000 picoseconds. + Weight::from_parts(50_507_000, 3593) .saturating_add(T::DbWeight::get().reads(7)) .saturating_add(T::DbWeight::get().writes(3)) } @@ -182,8 +180,8 @@ impl WeightInfo { // Proof Size summary in bytes: // Measured: `106` // Estimated: `3571` - // Minimum execution time: 20_704_000 picoseconds. - Weight::from_parts(21_266_000, 3571) + // Minimum execution time: 21_230_000 picoseconds. + Weight::from_parts(21_870_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 74254814bcafc7f67dd20d8fa5dcd8da4337f782..9657fa55c1f2fdd4cf6ffdc4888e13e22a262155 100644 --- a/cumulus/parachains/runtimes/coretime/coretime-westend/src/weights/xcm/pallet_xcm_benchmarks_generic.rs +++ b/cumulus/parachains/runtimes/coretime/coretime-westend/src/weights/xcm/pallet_xcm_benchmarks_generic.rs @@ -17,28 +17,26 @@ //! Autogenerated weights for `pallet_xcm_benchmarks::generic` //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 32.0.0 -//! DATE: 2024-02-08, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! DATE: 2024-05-07, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` //! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `runner-bn-ce5rx-project-674-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` +//! HOSTNAME: `runner-unxyhko3-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 -// --template=./cumulus/templates/xcm-bench-template.hbs -// --chain=coretime-westend-dev -// --wasm-execution=compiled -// --pallet=pallet_xcm_benchmarks::generic -// --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_benchmarks::generic +// --chain=coretime-westend-dev // --header=./cumulus/file_header.txt -// --output=./cumulus/parachains/runtimes/coretime/coretime-westend/src/weights/xcm/pallet_xcm_benchmarks_generic.rs +// --template=./cumulus/templates/xcm-bench-template.hbs +// --output=./cumulus/parachains/runtimes/coretime/coretime-westend/src/weights/xcm/ #![cfg_attr(rustfmt, rustfmt_skip)] #![allow(unused_parens)] @@ -66,8 +64,8 @@ impl WeightInfo { // Proof Size summary in bytes: // Measured: `106` // Estimated: `3571` - // Minimum execution time: 22_424_000 picoseconds. - Weight::from_parts(23_208_000, 3571) + // Minimum execution time: 23_688_000 picoseconds. + Weight::from_parts(24_845_000, 3571) .saturating_add(T::DbWeight::get().reads(6)) .saturating_add(T::DbWeight::get().writes(2)) } @@ -75,8 +73,8 @@ impl WeightInfo { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_194_000 picoseconds. - Weight::from_parts(1_306_000, 0) + // Minimum execution time: 569_000 picoseconds. + Weight::from_parts(619_000, 0) } // Storage: `PolkadotXcm::Queries` (r:1 w:0) // Proof: `PolkadotXcm::Queries` (`max_values`: None, `max_size`: None, mode: `Measured`) @@ -84,58 +82,58 @@ impl WeightInfo { // Proof Size summary in bytes: // Measured: `32` // Estimated: `3497` - // Minimum execution time: 6_359_000 picoseconds. - Weight::from_parts(6_585_000, 3497) + // Minimum execution time: 5_851_000 picoseconds. + Weight::from_parts(6_061_000, 3497) .saturating_add(T::DbWeight::get().reads(1)) } pub fn transact() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 6_297_000 picoseconds. - Weight::from_parts(6_661_000, 0) + // Minimum execution time: 5_770_000 picoseconds. + Weight::from_parts(5_916_000, 0) } pub fn refund_surplus() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_778_000 picoseconds. - Weight::from_parts(1_923_000, 0) + // Minimum execution time: 1_155_000 picoseconds. + Weight::from_parts(1_270_000, 0) } pub fn set_error_handler() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_212_000 picoseconds. - Weight::from_parts(1_314_000, 0) + // Minimum execution time: 558_000 picoseconds. + Weight::from_parts(628_000, 0) } pub fn set_appendix() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_165_000 picoseconds. - Weight::from_parts(1_247_000, 0) + // Minimum execution time: 603_000 picoseconds. + Weight::from_parts(630_000, 0) } pub fn clear_error() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_173_000 picoseconds. - Weight::from_parts(1_275_000, 0) + // Minimum execution time: 533_000 picoseconds. + Weight::from_parts(563_000, 0) } pub fn descend_origin() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_247_000 picoseconds. - Weight::from_parts(1_332_000, 0) + // Minimum execution time: 597_000 picoseconds. + Weight::from_parts(644_000, 0) } pub fn clear_origin() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_170_000 picoseconds. - Weight::from_parts(1_237_000, 0) + // Minimum execution time: 536_000 picoseconds. + Weight::from_parts(588_000, 0) } // Storage: `ParachainInfo::ParachainId` (r:1 w:0) // Proof: `ParachainInfo::ParachainId` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) @@ -153,8 +151,8 @@ impl WeightInfo { // Proof Size summary in bytes: // Measured: `106` // Estimated: `3571` - // Minimum execution time: 19_872_000 picoseconds. - Weight::from_parts(20_453_000, 3571) + // Minimum execution time: 21_146_000 picoseconds. + Weight::from_parts(21_771_000, 3571) .saturating_add(T::DbWeight::get().reads(6)) .saturating_add(T::DbWeight::get().writes(2)) } @@ -164,8 +162,8 @@ impl WeightInfo { // Proof Size summary in bytes: // Measured: `90` // Estimated: `3555` - // Minimum execution time: 9_105_000 picoseconds. - Weight::from_parts(9_365_000, 3555) + // Minimum execution time: 8_446_000 picoseconds. + Weight::from_parts(8_660_000, 3555) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(1)) } @@ -173,8 +171,8 @@ impl WeightInfo { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_228_000 picoseconds. - Weight::from_parts(1_293_000, 0) + // Minimum execution time: 561_000 picoseconds. + Weight::from_parts(594_000, 0) } // Storage: `PolkadotXcm::VersionNotifyTargets` (r:1 w:1) // Proof: `PolkadotXcm::VersionNotifyTargets` (`max_values`: None, `max_size`: None, mode: `Measured`) @@ -192,8 +190,8 @@ impl WeightInfo { // Proof Size summary in bytes: // Measured: `74` // Estimated: `3539` - // Minimum execution time: 19_535_000 picoseconds. - Weight::from_parts(20_139_000, 3539) + // Minimum execution time: 19_953_000 picoseconds. + Weight::from_parts(20_608_000, 3539) .saturating_add(T::DbWeight::get().reads(6)) .saturating_add(T::DbWeight::get().writes(3)) } @@ -203,44 +201,44 @@ impl WeightInfo { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 3_158_000 picoseconds. - Weight::from_parts(3_275_000, 0) + // Minimum execution time: 2_290_000 picoseconds. + Weight::from_parts(2_370_000, 0) .saturating_add(T::DbWeight::get().writes(1)) } pub fn burn_asset() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_539_000 picoseconds. - Weight::from_parts(1_607_000, 0) + // Minimum execution time: 943_000 picoseconds. + Weight::from_parts(987_000, 0) } pub fn expect_asset() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_317_000 picoseconds. - Weight::from_parts(1_427_000, 0) + // Minimum execution time: 635_000 picoseconds. + Weight::from_parts(699_000, 0) } pub fn expect_origin() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_176_000 picoseconds. - Weight::from_parts(1_250_000, 0) + // Minimum execution time: 553_000 picoseconds. + Weight::from_parts(609_000, 0) } pub fn expect_error() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_202_000 picoseconds. - Weight::from_parts(1_279_000, 0) + // Minimum execution time: 547_000 picoseconds. + Weight::from_parts(581_000, 0) } pub fn expect_transact_status() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_411_000 picoseconds. - Weight::from_parts(1_463_000, 0) + // Minimum execution time: 700_000 picoseconds. + Weight::from_parts(757_000, 0) } // Storage: `ParachainInfo::ParachainId` (r:1 w:0) // Proof: `ParachainInfo::ParachainId` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) @@ -258,8 +256,8 @@ impl WeightInfo { // Proof Size summary in bytes: // Measured: `106` // Estimated: `3571` - // Minimum execution time: 22_991_000 picoseconds. - Weight::from_parts(23_820_000, 3571) + // Minimum execution time: 24_953_000 picoseconds. + Weight::from_parts(25_516_000, 3571) .saturating_add(T::DbWeight::get().reads(6)) .saturating_add(T::DbWeight::get().writes(2)) } @@ -267,8 +265,8 @@ impl WeightInfo { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 3_534_000 picoseconds. - Weight::from_parts(3_708_000, 0) + // Minimum execution time: 2_746_000 picoseconds. + Weight::from_parts(2_944_000, 0) } // Storage: `ParachainInfo::ParachainId` (r:1 w:0) // Proof: `ParachainInfo::ParachainId` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) @@ -286,8 +284,8 @@ impl WeightInfo { // Proof Size summary in bytes: // Measured: `106` // Estimated: `3571` - // Minimum execution time: 20_025_000 picoseconds. - Weight::from_parts(20_463_000, 3571) + // Minimum execution time: 21_325_000 picoseconds. + Weight::from_parts(21_942_000, 3571) .saturating_add(T::DbWeight::get().reads(6)) .saturating_add(T::DbWeight::get().writes(2)) } @@ -295,35 +293,35 @@ impl WeightInfo { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_213_000 picoseconds. - Weight::from_parts(1_290_000, 0) + // Minimum execution time: 600_000 picoseconds. + Weight::from_parts(631_000, 0) } pub fn set_topic() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_207_000 picoseconds. - Weight::from_parts(1_265_000, 0) + // Minimum execution time: 534_000 picoseconds. + Weight::from_parts(566_000, 0) } pub fn clear_topic() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_195_000 picoseconds. - Weight::from_parts(1_231_000, 0) + // Minimum execution time: 540_000 picoseconds. + Weight::from_parts(565_000, 0) } pub fn set_fees_mode() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_182_000 picoseconds. - Weight::from_parts(1_265_000, 0) + // Minimum execution time: 542_000 picoseconds. + Weight::from_parts(581_000, 0) } pub fn unpaid_execution() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_165_000 picoseconds. - Weight::from_parts(1_252_000, 0) + // Minimum execution time: 568_000 picoseconds. + Weight::from_parts(597_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 346bdfa4d8c9ea2bd75260a2c6eeccad9b276eeb..b12765870bfdbbc7eb495a52e9ec4e931dc442da 100644 --- a/cumulus/parachains/runtimes/coretime/coretime-westend/src/xcm_config.rs +++ b/cumulus/parachains/runtimes/coretime/coretime-westend/src/xcm_config.rs @@ -39,16 +39,16 @@ use polkadot_runtime_common::xcm_sender::ExponentialPrice; use sp_runtime::traits::AccountIdConversion; use xcm::latest::prelude::*; use xcm_builder::{ - AccountId32Aliases, AllowExplicitUnpaidExecutionFrom, AllowKnownQueryResponses, - AllowSubscriptionsFrom, AllowTopLevelPaidExecutionFrom, DenyReserveTransferToRelayChain, - DenyThenTry, EnsureXcmOrigin, FrameTransactionalProcessor, FungibleAdapter, IsConcrete, - NonFungibleAdapter, ParentAsSuperuser, ParentIsPreset, RelayChainAsNative, - SiblingParachainAsNative, SiblingParachainConvertsVia, SignedAccountId32AsNative, - SignedToAccountId32, SovereignSignedViaLocation, TakeWeightCredit, TrailingSetTopicAsId, - UsingComponents, WeightInfoBounds, WithComputedOrigin, WithUniqueTopic, + AccountId32Aliases, AllowExplicitUnpaidExecutionFrom, AllowHrmpNotificationsFromRelayChain, + AllowKnownQueryResponses, AllowSubscriptionsFrom, AllowTopLevelPaidExecutionFrom, + DenyReserveTransferToRelayChain, 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}; +use xcm_executor::XcmExecutor; parameter_types! { pub const TokenRelayLocation: Location = Location::parent(); @@ -146,48 +146,6 @@ impl Contains for FellowsPlurality { } } -/// A call filter for the XCM Transact instruction. This is a temporary measure until we properly -/// account for proof size weights. -/// -/// Calls that are allowed through this filter must: -/// 1. Have a fixed weight; -/// 2. Cannot lead to another call being made; -/// 3. Have a defined proof size weight, e.g. no unbounded vecs in call parameters. -pub struct SafeCallFilter; -impl Contains for SafeCallFilter { - fn contains(call: &RuntimeCall) -> bool { - #[cfg(feature = "runtime-benchmarks")] - { - if matches!(call, RuntimeCall::System(frame_system::Call::remark_with_event { .. })) { - return true - } - } - - matches!( - call, - RuntimeCall::PolkadotXcm( - pallet_xcm::Call::force_xcm_version { .. } | - 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 { .. } | - // 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::Session(pallet_session::Call::purge_keys { .. }) | - RuntimeCall::XcmpQueue(..) | - RuntimeCall::Broker(..) - ) - } -} - pub type Barrier = TrailingSetTopicAsId< DenyThenTry< DenyReserveTransferToRelayChain, @@ -206,6 +164,8 @@ pub type Barrier = TrailingSetTopicAsId< AllowExplicitUnpaidExecutionFrom<(ParentOrParentsPlurality, FellowsPlurality)>, // Subscriptions for version tracking are OK. AllowSubscriptionsFrom, + // HRMP notifications from the relay chain are OK. + AllowHrmpNotificationsFromRelayChain, ), UniversalLocation, ConstU32<8>, @@ -265,13 +225,14 @@ impl xcm_executor::Config for XcmConfig { >; type MessageExporter = (); type UniversalAliases = Nothing; - type CallDispatcher = WithOriginFilter; - type SafeCallFilter = SafeCallFilter; + type CallDispatcher = RuntimeCall; + type SafeCallFilter = Everything; type Aliasers = Nothing; type TransactionalProcessor = FrameTransactionalProcessor; type HrmpNewChannelOpenRequestHandler = (); type HrmpChannelAcceptedHandler = (); type HrmpChannelClosingHandler = (); + type XcmRecorder = PolkadotXcm; } /// Converts a local signed origin into an XCM location. Forms the basis for local origins @@ -300,7 +261,7 @@ impl pallet_xcm::Config for Runtime { type XcmExecuteFilter = Everything; type XcmExecutor = XcmExecutor; type XcmTeleportFilter = Everything; - type XcmReserveTransferFilter = Nothing; // This parachain is not meant as a reserve location. + type XcmReserveTransferFilter = Everything; type Weigher = WeightInfoBounds< crate::weights::xcm::CoretimeWestendXcmWeight, RuntimeCall, diff --git a/cumulus/parachains/runtimes/glutton/glutton-westend/Cargo.toml b/cumulus/parachains/runtimes/glutton/glutton-westend/Cargo.toml index fe9cd25841bfc8c0b14278ed6ea167a46c3dd652..ccd73fb5ee6a68ac5eb8797ad22c14f8072987d8 100644 --- a/cumulus/parachains/runtimes/glutton/glutton-westend/Cargo.toml +++ b/cumulus/parachains/runtimes/glutton/glutton-westend/Cargo.toml @@ -10,7 +10,7 @@ description = "Glutton parachain runtime." workspace = true [dependencies] -codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = ["derive"] } +codec = { package = "parity-scale-codec", version = "3.6.12", default-features = false, features = ["derive"] } scale-info = { version = "2.11.1", default-features = false, features = ["derive"] } # Substrate @@ -22,8 +22,8 @@ frame-system-rpc-runtime-api = { path = "../../../../../substrate/frame/system/r frame-system-benchmarking = { path = "../../../../../substrate/frame/system/benchmarking", default-features = false, optional = true } frame-try-runtime = { path = "../../../../../substrate/frame/try-runtime", default-features = false, optional = true } pallet-aura = { path = "../../../../../substrate/frame/aura", default-features = false } -pallet-glutton = { path = "../../../../../substrate/frame/glutton", default-features = false, optional = true } -pallet-sudo = { path = "../../../../../substrate/frame/sudo", default-features = false, optional = true } +pallet-glutton = { path = "../../../../../substrate/frame/glutton", default-features = false } +pallet-sudo = { path = "../../../../../substrate/frame/sudo", default-features = false } pallet-timestamp = { path = "../../../../../substrate/frame/timestamp", default-features = false } sp-api = { path = "../../../../../substrate/primitives/api", default-features = false } sp-block-builder = { path = "../../../../../substrate/primitives/block-builder", default-features = false } diff --git a/cumulus/parachains/runtimes/glutton/glutton-westend/build.rs b/cumulus/parachains/runtimes/glutton/glutton-westend/build.rs index 1580e6f07bec466c644ccab1f4591d384632135e..2f311357403c0c179103a91d180c42d4e29f84a7 100644 --- a/cumulus/parachains/runtimes/glutton/glutton-westend/build.rs +++ b/cumulus/parachains/runtimes/glutton/glutton-westend/build.rs @@ -16,9 +16,5 @@ use substrate_wasm_builder::WasmBuilder; fn main() { - WasmBuilder::new() - .with_current_project() - .export_heap_base() - .import_memory() - .build() + WasmBuilder::build_using_defaults(); } diff --git a/cumulus/parachains/runtimes/glutton/glutton-westend/src/lib.rs b/cumulus/parachains/runtimes/glutton/glutton-westend/src/lib.rs index 996f7655c0319a9dd40ce724beab5bf544893c08..b4ee0f5ae7108dcf8d711aea8522ec3c41d9673f 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_010_000, + spec_version: 1_011_000, impl_version: 0, apis: RUNTIME_API_VERSIONS, transaction_version: 1, @@ -208,8 +208,9 @@ impl pallet_message_queue::Config for Runtime { >; type Size = u32; type QueueChangeHandler = (); - type QueuePausedQuery = (); // No XCMP queue pallet deployed. - type HeapSize = sp_core::ConstU32<{ 64 * 1024 }>; + // No XCMP queue pallet deployed. + type QueuePausedQuery = (); + type HeapSize = sp_core::ConstU32<{ 103 * 1024 }>; type MaxStale = sp_core::ConstU32<8>; type ServiceWeight = MessageQueueServiceWeight; type IdleMaxServiceWeight = MessageQueueServiceWeight; diff --git a/cumulus/parachains/runtimes/glutton/glutton-westend/src/xcm_config.rs b/cumulus/parachains/runtimes/glutton/glutton-westend/src/xcm_config.rs index 15bb519e115c5c2eaca25053a3d3e47c30fb21e0..d1fb50c1ab095cb07eb3f849c5e5d8be42fd1fc6 100644 --- a/cumulus/parachains/runtimes/glutton/glutton-westend/src/xcm_config.rs +++ b/cumulus/parachains/runtimes/glutton/glutton-westend/src/xcm_config.rs @@ -30,8 +30,8 @@ use xcm_builder::{ parameter_types! { pub const WestendLocation: Location = Location::parent(); - pub const WestendNetwork: Option = Some(NetworkId::Westend); - pub UniversalLocation: InteriorLocation = [Parachain(ParachainInfo::parachain_id().into())].into(); + pub const WestendNetwork: NetworkId = NetworkId::Westend; + pub UniversalLocation: InteriorLocation = [GlobalConsensus(WestendNetwork::get()), Parachain(ParachainInfo::parachain_id().into())].into(); } /// This is the type we use to convert an (incoming) XCM origin into a local `Origin` instance, @@ -91,6 +91,7 @@ impl xcm_executor::Config for XcmConfig { type HrmpNewChannelOpenRequestHandler = (); type HrmpChannelAcceptedHandler = (); type HrmpChannelClosingHandler = (); + type XcmRecorder = (); } impl cumulus_pallet_xcm::Config for Runtime { diff --git a/cumulus/parachains/runtimes/people/people-rococo/Cargo.toml b/cumulus/parachains/runtimes/people/people-rococo/Cargo.toml index 7183be5fc82cc594c6ad2f3738dbfd5b67738a2c..2b990d9270fb90dc5919d78f8caa0c88abc09c8c 100644 --- a/cumulus/parachains/runtimes/people/people-rococo/Cargo.toml +++ b/cumulus/parachains/runtimes/people/people-rococo/Cargo.toml @@ -10,7 +10,7 @@ license = "Apache-2.0" 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.6.12", default-features = false, features = ["derive"] } enumflags2 = { version = "0.7.7" } hex-literal = { version = "0.4.1" } log = { workspace = true } diff --git a/cumulus/parachains/runtimes/people/people-rococo/src/lib.rs b/cumulus/parachains/runtimes/people/people-rococo/src/lib.rs index 3cd085fec63248aeb872af7b9233eb0046f472c9..68e34a0e567ea5ccd3694df43e12757cffad2efc 100644 --- a/cumulus/parachains/runtimes/people/people-rococo/src/lib.rs +++ b/cumulus/parachains/runtimes/people/people-rococo/src/lib.rs @@ -102,6 +102,7 @@ pub type UncheckedExtrinsic = /// Migrations to apply on runtime upgrade. pub type Migrations = ( + pallet_collator_selection::migration::v2::MigrationToV2, // permanent pallet_xcm::migration::MigrateToLatestXcmVersion, ); @@ -127,10 +128,10 @@ 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_010_000, + spec_version: 1_011_000, impl_version: 0, apis: RUNTIME_API_VERSIONS, - transaction_version: 0, + transaction_version: 1, state_version: 1, }; @@ -280,7 +281,7 @@ impl pallet_message_queue::Config for Runtime { // The XCMP queue pallet is only ever able to handle the `Sibling(ParaId)` origin: type QueueChangeHandler = NarrowOriginToSibling; type QueuePausedQuery = NarrowOriginToSibling; - type HeapSize = sp_core::ConstU32<{ 64 * 1024 }>; + type HeapSize = sp_core::ConstU32<{ 103 * 1024 }>; type MaxStale = sp_core::ConstU32<8>; type ServiceWeight = MessageQueueServiceWeight; type IdleMaxServiceWeight = MessageQueueServiceWeight; @@ -307,13 +308,22 @@ impl cumulus_pallet_xcmp_queue::Config for Runtime { type ChannelInfo = ParachainSystem; type VersionWrapper = PolkadotXcm; type XcmpQueue = TransformOrigin; - type MaxInboundSuspended = sp_core::ConstU32<1_000>; + type MaxInboundSuspended = ConstU32<1_000>; + type MaxActiveOutboundChannels = ConstU32<128>; + // Most on-chain HRMP channels are configured to use 102400 bytes of max message size, so we + // need to set the page size larger than that until we reduce the channel size on-chain. + type MaxPageSize = ConstU32<{ 103 * 1024 }>; type ControllerOrigin = RootOrFellows; type ControllerOriginConverter = XcmOriginToTransactDispatchOrigin; type PriceForSiblingDelivery = PriceForSiblingParachainDelivery; type WeightInfo = weights::cumulus_pallet_xcmp_queue::WeightInfo; } +impl cumulus_pallet_xcmp_queue::migration::v5::V5Config for Runtime { + // This must be the same as the `ChannelInfo` from the `Config`: + type ChannelList = ParachainSystem; +} + pub const PERIOD: u32 = 6 * HOURS; pub const OFFSET: u32 = 0; diff --git a/cumulus/parachains/runtimes/people/people-rococo/src/weights/pallet_balances.rs b/cumulus/parachains/runtimes/people/people-rococo/src/weights/pallet_balances.rs index 126d816afcdb551e31adc38aaeb54ad3af5b228c..4990e8c12d5aa2f3f3be9ac6fb2181f5f6e80f7a 100644 --- a/cumulus/parachains/runtimes/people/people-rococo/src/weights/pallet_balances.rs +++ b/cumulus/parachains/runtimes/people/people-rococo/src/weights/pallet_balances.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_balances` //! -//! 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-05-06, 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-unxyhko3-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_balances -// --extrinsic=* // --steps=50 // --repeat=20 -// --json -// --header=./file_header.txt -// --output=./cumulus/parachains/runtimes/people/people-kusama/src/weights/pallet_balances.rs +// --extrinsic=* +// --wasm-execution=compiled +// --heap-pages=4096 +// --json-file=/builds/parity/mirrors/polkadot-sdk/.git/.artifacts/bench.json +// --pallet=pallet_balances +// --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,112 +48,131 @@ use core::marker::PhantomData; /// Weight functions for `pallet_balances`. pub struct WeightInfo(PhantomData); impl pallet_balances::WeightInfo for WeightInfo { - /// 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 transfer_allow_death() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `3593` - // Minimum execution time: 63_775_000 picoseconds. - Weight::from_parts(64_181_000, 0) + // Minimum execution time: 42_847_000 picoseconds. + Weight::from_parts(44_471_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) + /// 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: `0` // Estimated: `3593` - // Minimum execution time: 47_986_000 picoseconds. - Weight::from_parts(48_308_000, 0) + // Minimum execution time: 33_076_000 picoseconds. + Weight::from_parts(35_052_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) + /// Storage: `System::Account` (r:1 w:1) + /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) fn force_set_balance_creating() -> Weight { // Proof Size summary in bytes: // Measured: `174` // Estimated: `3593` - // Minimum execution time: 18_083_000 picoseconds. - Weight::from_parts(18_380_000, 0) + // Minimum execution time: 13_422_000 picoseconds. + Weight::from_parts(13_682_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) + /// Storage: `System::Account` (r:1 w:1) + /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) fn force_set_balance_killing() -> Weight { // Proof Size summary in bytes: // Measured: `174` // Estimated: `3593` - // Minimum execution time: 26_341_000 picoseconds. - Weight::from_parts(26_703_000, 0) + // Minimum execution time: 18_360_000 picoseconds. + Weight::from_parts(18_721_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) + /// Storage: `System::Account` (r:2 w:2) + /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) fn force_transfer() -> Weight { // Proof Size summary in bytes: // Measured: `103` // Estimated: `6196` - // Minimum execution time: 66_227_000 picoseconds. - Weight::from_parts(67_321_000, 0) + // Minimum execution time: 44_647_000 picoseconds. + Weight::from_parts(46_142_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: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 transfer_all() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `3593` - // Minimum execution time: 59_472_000 picoseconds. - Weight::from_parts(60_842_000, 0) + // Minimum execution time: 41_807_000 picoseconds. + Weight::from_parts(44_490_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) + /// Storage: `System::Account` (r:1 w:1) + /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) fn force_unreserve() -> Weight { // Proof Size summary in bytes: // Measured: `174` // Estimated: `3593` - // Minimum execution time: 21_497_000 picoseconds. - Weight::from_parts(21_684_000, 0) + // Minimum execution time: 16_032_000 picoseconds. + Weight::from_parts(16_694_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:999 w:999) + /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) + /// The range of component `u` is `[1, 1000]`. + fn upgrade_accounts(u: u32, ) -> Weight { + // Proof Size summary in bytes: + // Measured: `0 + u * (136 ±0)` + // Estimated: `990 + u * (2603 ±0)` + // Minimum execution time: 14_593_000 picoseconds. + Weight::from_parts(14_767_000, 0) + .saturating_add(Weight::from_parts(0, 990)) + // Standard Error: 11_218 + .saturating_add(Weight::from_parts(13_432_648, 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())) + } /// Storage: `Balances::InactiveIssuance` (r:1 w:0) /// Proof: `Balances::InactiveIssuance` (`max_values`: Some(1), `max_size`: Some(16), added: 511, mode: `MaxEncodedLen`) fn force_adjust_total_issuance() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `1501` - // Minimum execution time: 5_132_000 picoseconds. - Weight::from_parts(5_467_000, 0) + // Minimum execution time: 5_044_000 picoseconds. + Weight::from_parts(5_368_000, 0) .saturating_add(Weight::from_parts(0, 1501)) .saturating_add(T::DbWeight::get().reads(1)) } - fn upgrade_accounts(u: u32, ) -> Weight { + fn burn_allow_death() -> Weight { // Proof Size summary in bytes: - // Measured: `0 + u * (136 ±0)` - // Estimated: `990 + u * (2603 ±0)` - // Minimum execution time: 20_385_000 picoseconds. - Weight::from_parts(20_587_000, 0) - .saturating_add(Weight::from_parts(0, 990)) - // Standard Error: 10_001 - .saturating_add(Weight::from_parts(16_801_557, 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())) + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 26_868_000 picoseconds. + Weight::from_parts(27_921_000, 0) + .saturating_add(Weight::from_parts(0, 0)) + } + fn burn_keep_alive() -> Weight { + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 17_988_000 picoseconds. + Weight::from_parts(18_962_000, 0) + .saturating_add(Weight::from_parts(0, 0)) } } 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 ac494fdc719f4139a79b9f92525bde8322267af2..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 @@ -17,9 +17,9 @@ //! Autogenerated weights for `pallet_xcm` //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 32.0.0 -//! DATE: 2024-03-21, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! DATE: 2024-02-20, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` //! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `runner-h2rr8wx7-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("people-rococo-dev")`, DB CACHE: 1024 // Executed Command: @@ -62,28 +62,8 @@ impl pallet_xcm::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `38` // Estimated: `3503` - // Minimum execution time: 17_935_000 picoseconds. - Weight::from_parts(18_482_000, 0) - .saturating_add(Weight::from_parts(0, 3503)) - .saturating_add(T::DbWeight::get().reads(5)) - .saturating_add(T::DbWeight::get().writes(2)) - } - /// 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_blob() -> Weight { - // Proof Size summary in bytes: - // Measured: `38` - // Estimated: `3503` - // Minimum execution time: 18_311_000 picoseconds. - Weight::from_parts(18_850_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)) @@ -104,8 +84,8 @@ impl pallet_xcm::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `70` // Estimated: `3535` - // Minimum execution time: 56_182_000 picoseconds. - Weight::from_parts(58_136_000, 0) + // 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)) @@ -140,24 +120,14 @@ 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 execute_blob() -> 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: `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: 5_979_000 picoseconds. - Weight::from_parts(6_289_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)) } @@ -167,8 +137,8 @@ impl pallet_xcm::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_853_000 picoseconds. - Weight::from_parts(2_045_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)) } @@ -192,8 +162,8 @@ impl pallet_xcm::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `38` // Estimated: `3503` - // Minimum execution time: 23_827_000 picoseconds. - Weight::from_parts(24_493_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)) @@ -216,8 +186,8 @@ impl pallet_xcm::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `255` // Estimated: `3720` - // Minimum execution time: 26_755_000 picoseconds. - Weight::from_parts(27_125_000, 0) + // 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)) @@ -228,8 +198,8 @@ impl pallet_xcm::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_898_000 picoseconds. - Weight::from_parts(2_028_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)) } @@ -239,8 +209,8 @@ impl pallet_xcm::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `89` // Estimated: `13454` - // Minimum execution time: 16_300_000 picoseconds. - Weight::from_parts(16_995_000, 0) + // 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)) @@ -251,8 +221,8 @@ impl pallet_xcm::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `93` // Estimated: `13458` - // Minimum execution time: 16_495_000 picoseconds. - Weight::from_parts(16_950_000, 0) + // 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)) @@ -263,8 +233,8 @@ impl pallet_xcm::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `106` // Estimated: `15946` - // Minimum execution time: 18_153_000 picoseconds. - Weight::from_parts(18_595_000, 0) + // 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)) } @@ -284,8 +254,8 @@ impl pallet_xcm::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `106` // Estimated: `6046` - // Minimum execution time: 23_387_000 picoseconds. - Weight::from_parts(24_677_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)) @@ -296,8 +266,8 @@ impl pallet_xcm::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `136` // Estimated: `11026` - // Minimum execution time: 10_939_000 picoseconds. - Weight::from_parts(11_210_000, 0) + // 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)) } @@ -307,8 +277,8 @@ impl pallet_xcm::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `100` // Estimated: `13465` - // Minimum execution time: 16_850_000 picoseconds. - Weight::from_parts(17_195_000, 0) + // 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)) @@ -329,8 +299,8 @@ impl pallet_xcm::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `106` // Estimated: `13471` - // Minimum execution time: 31_931_000 picoseconds. - Weight::from_parts(32_494_000, 0) + // 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)) @@ -343,8 +313,8 @@ impl pallet_xcm::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `32` // Estimated: `1517` - // Minimum execution time: 3_514_000 picoseconds. - Weight::from_parts(3_709_000, 0) + // 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)) @@ -355,8 +325,8 @@ impl pallet_xcm::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `7669` // Estimated: `11134` - // Minimum execution time: 24_863_000 picoseconds. - Weight::from_parts(25_293_000, 0) + // 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)) @@ -367,8 +337,8 @@ impl pallet_xcm::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `90` // Estimated: `3555` - // Minimum execution time: 33_799_000 picoseconds. - Weight::from_parts(34_665_000, 0) + // 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 1a42adeafd1d863b33d677abf0e2d90bf6e9feb1..cca964fb2441bbe8bd40d909eb90766907918df2 100644 --- a/cumulus/parachains/runtimes/people/people-rococo/src/xcm_config.rs +++ b/cumulus/parachains/runtimes/people/people-rococo/src/xcm_config.rs @@ -36,16 +36,16 @@ use polkadot_parachain_primitives::primitives::Sibling; use sp_runtime::traits::AccountIdConversion; use xcm::latest::prelude::*; use xcm_builder::{ - AccountId32Aliases, AllowExplicitUnpaidExecutionFrom, AllowKnownQueryResponses, - AllowSubscriptionsFrom, AllowTopLevelPaidExecutionFrom, DenyReserveTransferToRelayChain, - DenyThenTry, DescribeTerminus, EnsureXcmOrigin, FrameTransactionalProcessor, FungibleAdapter, - HashedDescription, IsConcrete, ParentAsSuperuser, ParentIsPreset, RelayChainAsNative, - SiblingParachainAsNative, SiblingParachainConvertsVia, SignedAccountId32AsNative, - SignedToAccountId32, SovereignSignedViaLocation, TakeWeightCredit, TrailingSetTopicAsId, - UsingComponents, WeightInfoBounds, WithComputedOrigin, WithUniqueTopic, + AccountId32Aliases, AllowExplicitUnpaidExecutionFrom, AllowHrmpNotificationsFromRelayChain, + AllowKnownQueryResponses, AllowSubscriptionsFrom, AllowTopLevelPaidExecutionFrom, + DenyReserveTransferToRelayChain, 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}; +use xcm_executor::XcmExecutor; parameter_types! { pub const RootLocation: Location = Location::here(); @@ -148,55 +148,6 @@ impl Contains for ParentOrParentsPlurality { } } -/// A call filter for the XCM Transact instruction. This is a temporary measure until we properly -/// account for proof size weights. -/// -/// Calls that are allowed through this filter must: -/// 1. Have a fixed weight; -/// 2. Cannot lead to another call being made; -/// 3. Have a defined proof size weight, e.g. no unbounded vecs in call parameters. -pub struct SafeCallFilter; -impl Contains for SafeCallFilter { - fn contains(call: &RuntimeCall) -> bool { - #[cfg(feature = "runtime-benchmarks")] - { - if matches!(call, RuntimeCall::System(frame_system::Call::remark_with_event { .. })) { - return true - } - } - - matches!( - call, - RuntimeCall::PolkadotXcm( - pallet_xcm::Call::force_xcm_version { .. } | - 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 { .. }, - ) | RuntimeCall::ParachainSystem(..) | - RuntimeCall::Timestamp(..) | - RuntimeCall::Balances(..) | - RuntimeCall::CollatorSelection( - pallet_collator_selection::Call::set_desired_candidates { .. } | - pallet_collator_selection::Call::set_candidacy_bond { .. } | - pallet_collator_selection::Call::register_as_candidate { .. } | - pallet_collator_selection::Call::leave_intent { .. } | - pallet_collator_selection::Call::set_invulnerables { .. } | - pallet_collator_selection::Call::add_invulnerable { .. } | - pallet_collator_selection::Call::remove_invulnerable { .. }, - ) | RuntimeCall::Session(pallet_session::Call::purge_keys { .. }) | - RuntimeCall::XcmpQueue(..) | - RuntimeCall::MessageQueue(..) | - RuntimeCall::Identity(..) | - RuntimeCall::IdentityMigrator(..) - ) - } -} - pub type Barrier = TrailingSetTopicAsId< DenyThenTry< DenyReserveTransferToRelayChain, @@ -214,6 +165,8 @@ pub type Barrier = TrailingSetTopicAsId< AllowExplicitUnpaidExecutionFrom, // Subscriptions for version tracking are OK. AllowSubscriptionsFrom, + // HRMP notifications from the relay chain are OK. + AllowHrmpNotificationsFromRelayChain, ), UniversalLocation, ConstU32<8>, @@ -270,13 +223,14 @@ impl xcm_executor::Config for XcmConfig { >; type MessageExporter = (); type UniversalAliases = Nothing; - type CallDispatcher = WithOriginFilter; - type SafeCallFilter = SafeCallFilter; + type CallDispatcher = RuntimeCall; + type SafeCallFilter = Everything; type Aliasers = Nothing; type TransactionalProcessor = FrameTransactionalProcessor; type HrmpNewChannelOpenRequestHandler = (); type HrmpChannelAcceptedHandler = (); type HrmpChannelClosingHandler = (); + type XcmRecorder = PolkadotXcm; } /// Converts a local signed origin into an XCM location. Forms the basis for local origins diff --git a/cumulus/parachains/runtimes/people/people-westend/Cargo.toml b/cumulus/parachains/runtimes/people/people-westend/Cargo.toml index 576c3b1aa4e3eaafafafd0af353580fef7a3c20c..cc7b6a6e2ff824ed377b705d47e0cb4e9e57b084 100644 --- a/cumulus/parachains/runtimes/people/people-westend/Cargo.toml +++ b/cumulus/parachains/runtimes/people/people-westend/Cargo.toml @@ -10,7 +10,7 @@ license = "Apache-2.0" 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.6.12", default-features = false, features = ["derive"] } enumflags2 = { version = "0.7.7" } hex-literal = { version = "0.4.1" } log = { workspace = true } diff --git a/cumulus/parachains/runtimes/people/people-westend/src/lib.rs b/cumulus/parachains/runtimes/people/people-westend/src/lib.rs index 307ab90a47723503725757d5862f5d0b21bdf9c0..4d838fb9961fe291fb260ed72725ec9ea15c3cf5 100644 --- a/cumulus/parachains/runtimes/people/people-westend/src/lib.rs +++ b/cumulus/parachains/runtimes/people/people-westend/src/lib.rs @@ -102,6 +102,7 @@ pub type UncheckedExtrinsic = /// Migrations to apply on runtime upgrade. pub type Migrations = ( + pallet_collator_selection::migration::v2::MigrationToV2, // permanent pallet_xcm::migration::MigrateToLatestXcmVersion, ); @@ -127,10 +128,10 @@ 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_010_000, + spec_version: 1_011_000, impl_version: 0, apis: RUNTIME_API_VERSIONS, - transaction_version: 0, + transaction_version: 1, state_version: 1, }; @@ -280,7 +281,7 @@ impl pallet_message_queue::Config for Runtime { // The XCMP queue pallet is only ever able to handle the `Sibling(ParaId)` origin: type QueueChangeHandler = NarrowOriginToSibling; type QueuePausedQuery = NarrowOriginToSibling; - type HeapSize = sp_core::ConstU32<{ 64 * 1024 }>; + type HeapSize = sp_core::ConstU32<{ 103 * 1024 }>; type MaxStale = sp_core::ConstU32<8>; type ServiceWeight = MessageQueueServiceWeight; type IdleMaxServiceWeight = MessageQueueServiceWeight; @@ -307,13 +308,22 @@ impl cumulus_pallet_xcmp_queue::Config for Runtime { type ChannelInfo = ParachainSystem; type VersionWrapper = PolkadotXcm; type XcmpQueue = TransformOrigin; - type MaxInboundSuspended = sp_core::ConstU32<1_000>; + type MaxInboundSuspended = ConstU32<1_000>; + type MaxActiveOutboundChannels = ConstU32<128>; + // Most on-chain HRMP channels are configured to use 102400 bytes of max message size, so we + // need to set the page size larger than that until we reduce the channel size on-chain. + type MaxPageSize = ConstU32<{ 103 * 1024 }>; type ControllerOrigin = RootOrFellows; type ControllerOriginConverter = XcmOriginToTransactDispatchOrigin; type WeightInfo = weights::cumulus_pallet_xcmp_queue::WeightInfo; type PriceForSiblingDelivery = PriceForSiblingParachainDelivery; } +impl cumulus_pallet_xcmp_queue::migration::v5::V5Config for Runtime { + // This must be the same as the `ChannelInfo` from the `Config`: + type ChannelList = ParachainSystem; +} + pub const PERIOD: u32 = 6 * HOURS; pub const OFFSET: u32 = 0; diff --git a/cumulus/parachains/runtimes/people/people-westend/src/weights/pallet_balances.rs b/cumulus/parachains/runtimes/people/people-westend/src/weights/pallet_balances.rs index 1a3df158a0d0742d6d721c66f9e6545608e0c88f..2649c1557a2f848826175e4b0ec1c30207f4fbb9 100644 --- a/cumulus/parachains/runtimes/people/people-westend/src/weights/pallet_balances.rs +++ b/cumulus/parachains/runtimes/people/people-westend/src/weights/pallet_balances.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_balances` //! -//! 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-05-06, 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-unxyhko3-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_balances -// --extrinsic=* // --steps=50 // --repeat=20 -// --json -// --header=./file_header.txt -// --output=./cumulus/parachains/runtimes/people/people-polkadot/src/weights/pallet_balances.rs +// --extrinsic=* +// --wasm-execution=compiled +// --heap-pages=4096 +// --json-file=/builds/parity/mirrors/polkadot-sdk/.git/.artifacts/bench.json +// --pallet=pallet_balances +// --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,112 +48,131 @@ use core::marker::PhantomData; /// Weight functions for `pallet_balances`. pub struct WeightInfo(PhantomData); impl pallet_balances::WeightInfo for WeightInfo { - /// 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 transfer_allow_death() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `3593` - // Minimum execution time: 59_580_000 picoseconds. - Weight::from_parts(60_317_000, 0) + // Minimum execution time: 42_705_000 picoseconds. + Weight::from_parts(43_367_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) + /// 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: `0` // Estimated: `3593` - // Minimum execution time: 45_490_000 picoseconds. - Weight::from_parts(45_910_000, 0) + // Minimum execution time: 33_334_000 picoseconds. + Weight::from_parts(34_183_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) + /// Storage: `System::Account` (r:1 w:1) + /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) fn force_set_balance_creating() -> Weight { // Proof Size summary in bytes: // Measured: `174` // Estimated: `3593` - // Minimum execution time: 17_353_000 picoseconds. - Weight::from_parts(17_676_000, 0) + // Minimum execution time: 13_036_000 picoseconds. + Weight::from_parts(13_392_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) + /// Storage: `System::Account` (r:1 w:1) + /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) fn force_set_balance_killing() -> Weight { // Proof Size summary in bytes: // Measured: `174` // Estimated: `3593` - // Minimum execution time: 25_017_000 picoseconds. - Weight::from_parts(25_542_000, 0) + // Minimum execution time: 17_734_000 picoseconds. + Weight::from_parts(18_504_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) + /// Storage: `System::Account` (r:2 w:2) + /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) fn force_transfer() -> Weight { // Proof Size summary in bytes: // Measured: `103` // Estimated: `6196` - // Minimum execution time: 61_161_000 picoseconds. - Weight::from_parts(61_665_000, 0) + // Minimum execution time: 44_343_000 picoseconds. + Weight::from_parts(44_783_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: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 transfer_all() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `3593` - // Minimum execution time: 55_422_000 picoseconds. - Weight::from_parts(55_880_000, 0) + // Minimum execution time: 41_562_000 picoseconds. + Weight::from_parts(42_397_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) + /// Storage: `System::Account` (r:1 w:1) + /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) fn force_unreserve() -> Weight { // Proof Size summary in bytes: // Measured: `174` // Estimated: `3593` - // Minimum execution time: 20_477_000 picoseconds. - Weight::from_parts(20_871_000, 0) + // Minimum execution time: 15_547_000 picoseconds. + Weight::from_parts(16_072_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:999 w:999) + /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) + /// The range of component `u` is `[1, 1000]`. + fn upgrade_accounts(u: u32, ) -> Weight { + // Proof Size summary in bytes: + // Measured: `0 + u * (136 ±0)` + // Estimated: `990 + u * (2603 ±0)` + // Minimum execution time: 13_969_000 picoseconds. + Weight::from_parts(14_302_000, 0) + .saturating_add(Weight::from_parts(0, 990)) + // Standard Error: 12_004 + .saturating_add(Weight::from_parts(12_993_439, 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())) + } /// Storage: `Balances::InactiveIssuance` (r:1 w:0) /// Proof: `Balances::InactiveIssuance` (`max_values`: Some(1), `max_size`: Some(16), added: 511, mode: `MaxEncodedLen`) fn force_adjust_total_issuance() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `1501` - // Minimum execution time: 5_132_000 picoseconds. - Weight::from_parts(5_467_000, 0) + // Minimum execution time: 4_854_000 picoseconds. + Weight::from_parts(5_148_000, 0) .saturating_add(Weight::from_parts(0, 1501)) .saturating_add(T::DbWeight::get().reads(1)) } - fn upgrade_accounts(u: u32, ) -> Weight { + fn burn_allow_death() -> Weight { // Proof Size summary in bytes: - // Measured: `0 + u * (136 ±0)` - // Estimated: `990 + u * (2603 ±0)` - // Minimum execution time: 19_501_000 picoseconds. - Weight::from_parts(19_726_000, 0) - .saturating_add(Weight::from_parts(0, 990)) - // Standard Error: 9_495 - .saturating_add(Weight::from_parts(15_658_957, 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())) + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 26_532_000 picoseconds. + Weight::from_parts(27_418_000, 0) + .saturating_add(Weight::from_parts(0, 0)) + } + fn burn_keep_alive() -> Weight { + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 18_148_000 picoseconds. + Weight::from_parts(18_809_000, 0) + .saturating_add(Weight::from_parts(0, 0)) } } 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 62a9c802808c0fdc2305f566f7b7f67b4d0a5748..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 @@ -17,9 +17,9 @@ //! Autogenerated weights for `pallet_xcm` //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 32.0.0 -//! DATE: 2024-03-21, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! DATE: 2024-02-20, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` //! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `runner-h2rr8wx7-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("people-westend-dev")`, DB CACHE: 1024 // Executed Command: @@ -62,28 +62,8 @@ impl pallet_xcm::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `38` // Estimated: `3503` - // Minimum execution time: 17_450_000 picoseconds. - Weight::from_parts(17_913_000, 0) - .saturating_add(Weight::from_parts(0, 3503)) - .saturating_add(T::DbWeight::get().reads(5)) - .saturating_add(T::DbWeight::get().writes(2)) - } - /// 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_blob() -> Weight { - // Proof Size summary in bytes: - // Measured: `38` - // Estimated: `3503` - // Minimum execution time: 18_082_000 picoseconds. - Weight::from_parts(18_293_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)) @@ -104,8 +84,8 @@ impl pallet_xcm::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `70` // Estimated: `3535` - // Minimum execution time: 54_939_000 picoseconds. - Weight::from_parts(55_721_000, 0) + // 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)) @@ -140,24 +120,14 @@ 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 execute_blob() -> 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: `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: 5_789_000 picoseconds. - Weight::from_parts(5_995_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)) } @@ -167,8 +137,8 @@ impl pallet_xcm::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_795_000 picoseconds. - Weight::from_parts(1_924_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)) } @@ -192,8 +162,8 @@ impl pallet_xcm::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `38` // Estimated: `3503` - // Minimum execution time: 23_445_000 picoseconds. - Weight::from_parts(23_906_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)) @@ -216,8 +186,8 @@ impl pallet_xcm::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `255` // Estimated: `3720` - // Minimum execution time: 26_590_000 picoseconds. - Weight::from_parts(27_056_000, 0) + // 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)) @@ -228,8 +198,8 @@ impl pallet_xcm::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_889_000 picoseconds. - Weight::from_parts(1_962_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)) } @@ -239,8 +209,8 @@ impl pallet_xcm::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `89` // Estimated: `13454` - // Minimum execution time: 16_408_000 picoseconds. - Weight::from_parts(16_877_000, 0) + // 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)) @@ -251,8 +221,8 @@ impl pallet_xcm::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `93` // Estimated: `13458` - // Minimum execution time: 16_791_000 picoseconds. - Weight::from_parts(17_111_000, 0) + // 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)) @@ -263,8 +233,8 @@ impl pallet_xcm::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `106` // Estimated: `15946` - // Minimum execution time: 18_355_000 picoseconds. - Weight::from_parts(19_110_000, 0) + // 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)) } @@ -284,8 +254,8 @@ impl pallet_xcm::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `106` // Estimated: `6046` - // Minimum execution time: 23_354_000 picoseconds. - Weight::from_parts(23_999_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)) @@ -296,8 +266,8 @@ impl pallet_xcm::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `136` // Estimated: `11026` - // Minimum execution time: 11_065_000 picoseconds. - Weight::from_parts(11_302_000, 0) + // 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)) } @@ -307,8 +277,8 @@ impl pallet_xcm::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `100` // Estimated: `13465` - // Minimum execution time: 16_998_000 picoseconds. - Weight::from_parts(17_509_000, 0) + // 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)) @@ -329,8 +299,8 @@ impl pallet_xcm::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `106` // Estimated: `13471` - // Minimum execution time: 31_068_000 picoseconds. - Weight::from_parts(31_978_000, 0) + // 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)) @@ -343,8 +313,8 @@ impl pallet_xcm::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `32` // Estimated: `1517` - // Minimum execution time: 3_478_000 picoseconds. - Weight::from_parts(3_595_000, 0) + // 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)) @@ -355,8 +325,8 @@ impl pallet_xcm::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `7669` // Estimated: `11134` - // Minimum execution time: 24_962_000 picoseconds. - Weight::from_parts(25_404_000, 0) + // 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)) @@ -367,8 +337,8 @@ impl pallet_xcm::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `90` // Estimated: `3555` - // Minimum execution time: 32_685_000 picoseconds. - Weight::from_parts(33_592_000, 0) + // 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 114923270645589b0bb1b0d8d5a7abed4e315a8d..3926ddcf21efe09933e85552b3fc31f368d69e9b 100644 --- a/cumulus/parachains/runtimes/people/people-westend/src/xcm_config.rs +++ b/cumulus/parachains/runtimes/people/people-westend/src/xcm_config.rs @@ -36,16 +36,16 @@ use polkadot_parachain_primitives::primitives::Sibling; use sp_runtime::traits::AccountIdConversion; use xcm::latest::prelude::*; use xcm_builder::{ - AccountId32Aliases, AllowExplicitUnpaidExecutionFrom, AllowKnownQueryResponses, - AllowSubscriptionsFrom, AllowTopLevelPaidExecutionFrom, DenyReserveTransferToRelayChain, - DenyThenTry, DescribeTerminus, EnsureXcmOrigin, FrameTransactionalProcessor, FungibleAdapter, - HashedDescription, IsConcrete, ParentAsSuperuser, ParentIsPreset, RelayChainAsNative, - SiblingParachainAsNative, SiblingParachainConvertsVia, SignedAccountId32AsNative, - SignedToAccountId32, SovereignSignedViaLocation, TakeWeightCredit, TrailingSetTopicAsId, - UsingComponents, WeightInfoBounds, WithComputedOrigin, WithUniqueTopic, + AccountId32Aliases, AllowExplicitUnpaidExecutionFrom, AllowHrmpNotificationsFromRelayChain, + AllowKnownQueryResponses, AllowSubscriptionsFrom, AllowTopLevelPaidExecutionFrom, + DenyReserveTransferToRelayChain, 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}; +use xcm_executor::XcmExecutor; parameter_types! { pub const RootLocation: Location = Location::here(); @@ -155,55 +155,6 @@ impl Contains for FellowsPlurality { } } -/// A call filter for the XCM Transact instruction. This is a temporary measure until we properly -/// account for proof size weights. -/// -/// Calls that are allowed through this filter must: -/// 1. Have a fixed weight; -/// 2. Cannot lead to another call being made; -/// 3. Have a defined proof size weight, e.g. no unbounded vecs in call parameters. -pub struct SafeCallFilter; -impl Contains for SafeCallFilter { - fn contains(call: &RuntimeCall) -> bool { - #[cfg(feature = "runtime-benchmarks")] - { - if matches!(call, RuntimeCall::System(frame_system::Call::remark_with_event { .. })) { - return true - } - } - - matches!( - call, - RuntimeCall::PolkadotXcm( - pallet_xcm::Call::force_xcm_version { .. } | - 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 { .. }, - ) | RuntimeCall::ParachainSystem(..) | - RuntimeCall::Timestamp(..) | - RuntimeCall::Balances(..) | - RuntimeCall::CollatorSelection( - pallet_collator_selection::Call::set_desired_candidates { .. } | - pallet_collator_selection::Call::set_candidacy_bond { .. } | - pallet_collator_selection::Call::register_as_candidate { .. } | - pallet_collator_selection::Call::leave_intent { .. } | - pallet_collator_selection::Call::set_invulnerables { .. } | - pallet_collator_selection::Call::add_invulnerable { .. } | - pallet_collator_selection::Call::remove_invulnerable { .. }, - ) | RuntimeCall::Session(pallet_session::Call::purge_keys { .. }) | - RuntimeCall::XcmpQueue(..) | - RuntimeCall::MessageQueue(..) | - RuntimeCall::Identity(..) | - RuntimeCall::IdentityMigrator(..) - ) - } -} - pub type Barrier = TrailingSetTopicAsId< DenyThenTry< DenyReserveTransferToRelayChain, @@ -222,6 +173,8 @@ pub type Barrier = TrailingSetTopicAsId< AllowExplicitUnpaidExecutionFrom<(ParentOrParentsPlurality, FellowsPlurality)>, // Subscriptions for version tracking are OK. AllowSubscriptionsFrom, + // HRMP notifications from the relay chain are OK. + AllowHrmpNotificationsFromRelayChain, ), UniversalLocation, ConstU32<8>, @@ -278,13 +231,14 @@ impl xcm_executor::Config for XcmConfig { >; type MessageExporter = (); type UniversalAliases = Nothing; - type CallDispatcher = WithOriginFilter; - type SafeCallFilter = SafeCallFilter; + type CallDispatcher = RuntimeCall; + type SafeCallFilter = Everything; type Aliasers = Nothing; type TransactionalProcessor = FrameTransactionalProcessor; type HrmpNewChannelOpenRequestHandler = (); type HrmpChannelAcceptedHandler = (); type HrmpChannelClosingHandler = (); + type XcmRecorder = PolkadotXcm; } /// Converts a local signed origin into an XCM location. Forms the basis for local origins diff --git a/cumulus/parachains/runtimes/starters/seedling/Cargo.toml b/cumulus/parachains/runtimes/starters/seedling/Cargo.toml index eb702c9f2cdf30844fbf4ea17534566c038c4880..469269e37ff42f7679e34d9b8f6f143acc34e5b0 100644 --- a/cumulus/parachains/runtimes/starters/seedling/Cargo.toml +++ b/cumulus/parachains/runtimes/starters/seedling/Cargo.toml @@ -10,7 +10,7 @@ license = "Apache-2.0" workspace = true [dependencies] -codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = ["derive"] } +codec = { package = "parity-scale-codec", version = "3.6.12", default-features = false, features = ["derive"] } scale-info = { version = "2.11.1", default-features = false, features = ["derive"] } # Substrate diff --git a/cumulus/parachains/runtimes/starters/shell/Cargo.toml b/cumulus/parachains/runtimes/starters/shell/Cargo.toml index f66d04fec1fdd72eb30f183bb713e88d4fee00e7..ff388d2fa2edef2991bff1669482fa318709e449 100644 --- a/cumulus/parachains/runtimes/starters/shell/Cargo.toml +++ b/cumulus/parachains/runtimes/starters/shell/Cargo.toml @@ -10,7 +10,7 @@ license = "Apache-2.0" workspace = true [dependencies] -codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = ["derive"] } +codec = { package = "parity-scale-codec", version = "3.6.12", default-features = false, features = ["derive"] } scale-info = { version = "2.11.1", default-features = false, features = ["derive"] } # Substrate diff --git a/cumulus/parachains/runtimes/starters/shell/src/lib.rs b/cumulus/parachains/runtimes/starters/shell/src/lib.rs index a3d1629bbe5eb928f3f78998ed721968f140536d..7422b580cc3e08c1df8af5e9dce23d79d0c4e1a8 100644 --- a/cumulus/parachains/runtimes/starters/shell/src/lib.rs +++ b/cumulus/parachains/runtimes/starters/shell/src/lib.rs @@ -229,7 +229,7 @@ impl pallet_message_queue::Config for Runtime { // These need to be configured to the XCMP pallet - if it is deployed. type QueueChangeHandler = (); type QueuePausedQuery = (); - type HeapSize = sp_core::ConstU32<{ 64 * 1024 }>; + type HeapSize = sp_core::ConstU32<{ 103 * 1024 }>; type MaxStale = sp_core::ConstU32<8>; type ServiceWeight = MessageQueueServiceWeight; type IdleMaxServiceWeight = MessageQueueServiceWeight; diff --git a/cumulus/parachains/runtimes/starters/shell/src/xcm_config.rs b/cumulus/parachains/runtimes/starters/shell/src/xcm_config.rs index df89158729cd9935911df3a1bff76557c6d5c900..741b3bcd752f5511b09add16865a5f311e3626cc 100644 --- a/cumulus/parachains/runtimes/starters/shell/src/xcm_config.rs +++ b/cumulus/parachains/runtimes/starters/shell/src/xcm_config.rs @@ -30,8 +30,8 @@ use xcm_builder::{ parameter_types! { pub const RococoLocation: Location = Location::parent(); - pub const RococoNetwork: Option = Some(NetworkId::Rococo); - pub UniversalLocation: InteriorLocation = [Parachain(ParachainInfo::parachain_id().into())].into(); + pub const RococoNetwork: NetworkId = NetworkId::Rococo; + pub UniversalLocation: InteriorLocation = [GlobalConsensus(RococoNetwork::get()), Parachain(ParachainInfo::parachain_id().into())].into(); } /// This is the type we use to convert an (incoming) XCM origin into a local `Origin` instance, @@ -91,6 +91,7 @@ impl xcm_executor::Config for XcmConfig { type HrmpNewChannelOpenRequestHandler = (); type HrmpChannelAcceptedHandler = (); type HrmpChannelClosingHandler = (); + type XcmRecorder = (); } impl cumulus_pallet_xcm::Config for Runtime { diff --git a/cumulus/parachains/runtimes/test-utils/Cargo.toml b/cumulus/parachains/runtimes/test-utils/Cargo.toml index eda88beb7dabb41bd4075ec5ab6bf8ec2f42d3c8..475acb13b8b08cb97b7f3dd6718ff71c05d00cd9 100644 --- a/cumulus/parachains/runtimes/test-utils/Cargo.toml +++ b/cumulus/parachains/runtimes/test-utils/Cargo.toml @@ -10,7 +10,7 @@ license = "Apache-2.0" workspace = true [dependencies] -codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = ["derive", "max-encoded-len"] } +codec = { package = "parity-scale-codec", version = "3.6.12", default-features = false, features = ["derive", "max-encoded-len"] } # Substrate frame-support = { path = "../../../../substrate/frame/support", default-features = false } diff --git a/cumulus/parachains/runtimes/testing/penpal/Cargo.toml b/cumulus/parachains/runtimes/testing/penpal/Cargo.toml index 028aa002a91e508c858c7ba71c981d9c9cf8dc60..0ac79a3eab5a1a82903f4c4aa515b695250e4cf6 100644 --- a/cumulus/parachains/runtimes/testing/penpal/Cargo.toml +++ b/cumulus/parachains/runtimes/testing/penpal/Cargo.toml @@ -18,7 +18,7 @@ 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.6.12", default-features = false, features = ["derive"] } hex-literal = { version = "0.4.1", optional = true } log = { workspace = true } scale-info = { version = "2.11.1", default-features = false, features = ["derive"] } @@ -64,6 +64,7 @@ polkadot-runtime-common = { path = "../../../../../polkadot/runtime/common", def xcm = { package = "staging-xcm", path = "../../../../../polkadot/xcm", default-features = false } xcm-builder = { package = "staging-xcm-builder", path = "../../../../../polkadot/xcm/xcm-builder", default-features = false } xcm-executor = { package = "staging-xcm-executor", path = "../../../../../polkadot/xcm/xcm-executor", default-features = false } +xcm-fee-payment-runtime-api = { path = "../../../../../polkadot/xcm/xcm-fee-payment-runtime-api", default-features = false } # Cumulus cumulus-pallet-aura-ext = { path = "../../../../pallets/aura-ext", default-features = false } @@ -134,6 +135,7 @@ std = [ "substrate-wasm-builder", "xcm-builder/std", "xcm-executor/std", + "xcm-fee-payment-runtime-api/std", "xcm/std", ] @@ -164,6 +166,7 @@ runtime-benchmarks = [ "sp-runtime/runtime-benchmarks", "xcm-builder/runtime-benchmarks", "xcm-executor/runtime-benchmarks", + "xcm-fee-payment-runtime-api/runtime-benchmarks", ] try-runtime = [ diff --git a/cumulus/parachains/runtimes/testing/penpal/build.rs b/cumulus/parachains/runtimes/testing/penpal/build.rs index 9c9cde9a25a1a8ab1780b7df7e068264459a31af..c2fa89aa7028510ab3f95a152ababcffbecd280f 100644 --- a/cumulus/parachains/runtimes/testing/penpal/build.rs +++ b/cumulus/parachains/runtimes/testing/penpal/build.rs @@ -16,11 +16,7 @@ #[cfg(feature = "std")] fn main() { - substrate_wasm_builder::WasmBuilder::new() - .with_current_project() - .export_heap_base() - .import_memory() - .build() + substrate_wasm_builder::WasmBuilder::build_using_defaults(); } #[cfg(not(feature = "std"))] diff --git a/cumulus/parachains/runtimes/testing/penpal/src/lib.rs b/cumulus/parachains/runtimes/testing/penpal/src/lib.rs index 89885d77378ba2c1df13116b5f2d41f547002b30..86a8b0f1d9ea0518e27492e59fc417b1a2836ce9 100644 --- a/cumulus/parachains/runtimes/testing/penpal/src/lib.rs +++ b/cumulus/parachains/runtimes/testing/penpal/src/lib.rs @@ -32,6 +32,7 @@ include!(concat!(env!("OUT_DIR"), "/wasm_binary.rs")); mod weights; pub mod xcm_config; +use codec::Encode; use cumulus_pallet_parachain_system::RelayNumberStrictlyIncreases; use cumulus_primitives_core::{AggregateMessageOrigin, ParaId}; use frame_support::{ @@ -44,7 +45,7 @@ use frame_support::{ AsEnsureOriginWithArg, ConstBool, ConstU32, ConstU64, ConstU8, Everything, TransformOrigin, }, weights::{ - constants::WEIGHT_REF_TIME_PER_SECOND, ConstantMultiplier, FeePolynomial, + constants::WEIGHT_REF_TIME_PER_SECOND, ConstantMultiplier, FeePolynomial, WeightToFee as _, WeightToFeeCoefficient, WeightToFeeCoefficients, WeightToFeePolynomial, }, PalletId, @@ -80,7 +81,14 @@ pub use sp_runtime::BuildStorage; use parachains_common::{AccountId, Signature}; use polkadot_runtime_common::{BlockHashCount, SlowAdjustingFeeUpdate}; use weights::{BlockExecutionWeight, ExtrinsicBaseWeight, RocksDbWeight}; -use xcm::latest::prelude::{AssetId as AssetLocationId, BodyId}; +use xcm::{ + latest::prelude::{AssetId as AssetLocationId, BodyId}, + IntoVersion, VersionedAssetId, VersionedAssets, VersionedLocation, VersionedXcm, +}; +use xcm_fee_payment_runtime_api::{ + dry_run::{Error as XcmDryRunApiError, ExtrinsicDryRunEffects, XcmDryRunEffects}, + fees::Error as XcmPaymentApiError, +}; /// Balance of an account. pub type Balance = u128; @@ -533,7 +541,7 @@ impl pallet_message_queue::Config for Runtime { // The XCMP queue pallet is only ever able to handle the `Sibling(ParaId)` origin: type QueueChangeHandler = NarrowOriginToSibling; type QueuePausedQuery = NarrowOriginToSibling; - type HeapSize = sp_core::ConstU32<{ 64 * 1024 }>; + type HeapSize = sp_core::ConstU32<{ 103 * 1024 }>; type MaxStale = sp_core::ConstU32<8>; type ServiceWeight = MessageQueueServiceWeight; type IdleMaxServiceWeight = MessageQueueServiceWeight; @@ -561,7 +569,11 @@ impl cumulus_pallet_xcmp_queue::Config for Runtime { type VersionWrapper = PolkadotXcm; // Enqueue XCMP messages from siblings for later processing. type XcmpQueue = TransformOrigin; - type MaxInboundSuspended = sp_core::ConstU32<1_000>; + type MaxInboundSuspended = ConstU32<1_000>; + type MaxActiveOutboundChannels = ConstU32<128>; + // Most on-chain HRMP channels are configured to use 102400 bytes of max message size, so we + // need to set the page size larger than that until we reduce the channel size on-chain. + type MaxPageSize = ConstU32<{ 103 * 1024 }>; type ControllerOrigin = EnsureRoot; type ControllerOriginConverter = XcmOriginToTransactDispatchOrigin; type WeightInfo = (); @@ -835,6 +847,101 @@ impl_runtime_apis! { } } + impl xcm_fee_payment_runtime_api::fees::XcmPaymentApi for Runtime { + fn query_acceptable_payment_assets(xcm_version: xcm::Version) -> Result, XcmPaymentApiError> { + if !matches!(xcm_version, 3 | 4) { + return Err(XcmPaymentApiError::UnhandledXcmVersion); + } + Ok([VersionedAssetId::V4(xcm_config::RelayLocation::get().into())] + .into_iter() + .filter_map(|asset| asset.into_version(xcm_version).ok()) + .collect()) + } + + fn query_weight_to_asset_fee(weight: Weight, asset: VersionedAssetId) -> Result { + let local_asset = VersionedAssetId::V4(xcm_config::RelayLocation::get().into()); + let asset = asset + .into_version(4) + .map_err(|_| XcmPaymentApiError::VersionedConversionFailed)?; + + if asset != local_asset { return Err(XcmPaymentApiError::AssetNotFound); } + + Ok(WeightToFee::weight_to_fee(&weight)) + } + + fn query_xcm_weight(message: VersionedXcm<()>) -> Result { + PolkadotXcm::query_xcm_weight(message) + } + + fn query_delivery_fees(destination: VersionedLocation, message: VersionedXcm<()>) -> Result { + PolkadotXcm::query_delivery_fees(destination, message) + } + } + + impl xcm_fee_payment_runtime_api::dry_run::XcmDryRunApi for Runtime { + fn dry_run_extrinsic(extrinsic: ::Extrinsic) -> Result, XcmDryRunApiError> { + use xcm_builder::InspectMessageQueues; + use xcm_executor::RecordXcm; + use xcm::prelude::*; + + pallet_xcm::Pallet::::set_record_xcm(true); + let result = Executive::apply_extrinsic(extrinsic).map_err(|error| { + log::error!( + target: "xcm::XcmDryRunApi::dry_run_extrinsic", + "Applying extrinsic failed with error {:?}", + error, + ); + XcmDryRunApiError::InvalidExtrinsic + })?; + let local_xcm = pallet_xcm::Pallet::::recorded_xcm(); + let forwarded_xcms = xcm_config::XcmRouter::get_messages(); + let events: Vec = System::read_events_no_consensus().map(|record| record.event.clone()).collect(); + Ok(ExtrinsicDryRunEffects { + local_xcm: local_xcm.map(VersionedXcm::<()>::V4), + forwarded_xcms, + emitted_events: events, + execution_result: result, + }) + } + + fn dry_run_xcm(origin_location: VersionedLocation, program: VersionedXcm) -> Result, XcmDryRunApiError> { + use xcm_builder::InspectMessageQueues; + use xcm::prelude::*; + + let origin_location: Location = origin_location.try_into().map_err(|error| { + log::error!( + target: "xcm::XcmDryRunApi::dry_run_xcm", + "Location version conversion failed with error: {:?}", + error, + ); + XcmDryRunApiError::VersionedConversionFailed + })?; + let program: Xcm = program.try_into().map_err(|error| { + log::error!( + target: "xcm::XcmDryRunApi::dry_run_xcm", + "Xcm version conversion failed with error {:?}", + error, + ); + XcmDryRunApiError::VersionedConversionFailed + })?; + let mut hash = program.using_encoded(sp_core::hashing::blake2_256); + let result = xcm_executor::XcmExecutor::::prepare_and_execute( + origin_location, + program, + &mut hash, + Weight::MAX, // Max limit. + Weight::zero(), + ); + let forwarded_xcms = xcm_config::XcmRouter::get_messages(); + let events: Vec = System::read_events_no_consensus().map(|record| record.event.clone()).collect(); + Ok(XcmDryRunEffects { + forwarded_xcms, + emitted_events: events, + execution_result: result, + }) + } + } + #[cfg(feature = "try-runtime")] impl frame_try_runtime::TryRuntime for Runtime { fn on_runtime_upgrade(checks: frame_try_runtime::UpgradeCheckSelect) -> (Weight, Weight) { diff --git a/cumulus/parachains/runtimes/testing/penpal/src/xcm_config.rs b/cumulus/parachains/runtimes/testing/penpal/src/xcm_config.rs index 6832e2f4f4409b833cce74d691cb0442ec6a724f..08a2da260c57e67b17eecf55f3845049e371b996 100644 --- a/cumulus/parachains/runtimes/testing/penpal/src/xcm_config.rs +++ b/cumulus/parachains/runtimes/testing/penpal/src/xcm_config.rs @@ -43,14 +43,15 @@ use polkadot_runtime_common::{impls::ToAuthor, xcm_sender::ExponentialPrice}; use sp_runtime::traits::{AccountIdConversion, ConvertInto, Identity, TryConvertInto}; use xcm::latest::prelude::*; use xcm_builder::{ - AccountId32Aliases, AllowKnownQueryResponses, AllowSubscriptionsFrom, - AllowTopLevelPaidExecutionFrom, AsPrefixedGeneralIndex, ConvertedConcreteId, EnsureXcmOrigin, - FixedWeightBounds, FrameTransactionalProcessor, FungibleAdapter, FungiblesAdapter, IsConcrete, - LocalMint, NativeAsset, NoChecking, ParentAsSuperuser, ParentIsPreset, RelayChainAsNative, - SiblingParachainAsNative, SiblingParachainConvertsVia, SignedAccountId32AsNative, - SignedToAccountId32, SovereignSignedViaLocation, StartsWith, TakeWeightCredit, - TrailingSetTopicAsId, UsingComponents, WithComputedOrigin, WithUniqueTopic, - XcmFeeManagerFromComponents, XcmFeeToAccount, + AccountId32Aliases, AllowHrmpNotificationsFromRelayChain, AllowKnownQueryResponses, + AllowSubscriptionsFrom, AllowTopLevelPaidExecutionFrom, AsPrefixedGeneralIndex, + ConvertedConcreteId, EnsureXcmOrigin, FixedWeightBounds, FrameTransactionalProcessor, + FungibleAdapter, FungiblesAdapter, IsConcrete, LocalMint, NativeAsset, NoChecking, + ParentAsSuperuser, ParentIsPreset, RelayChainAsNative, SiblingParachainAsNative, + SiblingParachainConvertsVia, SignedAccountId32AsNative, SignedToAccountId32, + SovereignSignedViaLocation, StartsWith, TakeWeightCredit, TrailingSetTopicAsId, + UsingComponents, WithComputedOrigin, WithUniqueTopic, XcmFeeManagerFromComponents, + XcmFeeToAccount, }; use xcm_executor::{traits::JustTry, XcmExecutor}; @@ -217,6 +218,8 @@ pub type Barrier = TrailingSetTopicAsId<( AllowTopLevelPaidExecutionFrom, // Subscriptions for version tracking are OK. AllowSubscriptionsFrom, + // HRMP notifications from the relay chain are OK. + AllowHrmpNotificationsFromRelayChain, ), UniversalLocation, ConstU32<8>, @@ -359,6 +362,7 @@ impl xcm_executor::Config for XcmConfig { type HrmpNewChannelOpenRequestHandler = (); type HrmpChannelAcceptedHandler = (); type HrmpChannelClosingHandler = (); + type XcmRecorder = PolkadotXcm; } /// Multiplier used for dedicated `TakeFirstAssetTrader` with `ForeignAssets` instance. diff --git a/cumulus/parachains/runtimes/testing/rococo-parachain/Cargo.toml b/cumulus/parachains/runtimes/testing/rococo-parachain/Cargo.toml index df3aaa92c79e78e5dfb9043db69778db051b3053..e74caf6b1f470ccc4f650ca375222f0b85233cea 100644 --- a/cumulus/parachains/runtimes/testing/rococo-parachain/Cargo.toml +++ b/cumulus/parachains/runtimes/testing/rococo-parachain/Cargo.toml @@ -10,7 +10,7 @@ license = "Apache-2.0" workspace = true [dependencies] -codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = ["derive"] } +codec = { package = "parity-scale-codec", version = "3.6.12", default-features = false, features = ["derive"] } scale-info = { version = "2.11.1", default-features = false, features = ["derive"] } # Substrate diff --git a/cumulus/parachains/runtimes/testing/rococo-parachain/build.rs b/cumulus/parachains/runtimes/testing/rococo-parachain/build.rs index 60f8a125129ff1344a1799246e931acdb1d139d5..239ccac19ec7778039fb1ee56f4e772b3ddd3711 100644 --- a/cumulus/parachains/runtimes/testing/rococo-parachain/build.rs +++ b/cumulus/parachains/runtimes/testing/rococo-parachain/build.rs @@ -15,11 +15,7 @@ #[cfg(feature = "std")] fn main() { - substrate_wasm_builder::WasmBuilder::new() - .with_current_project() - .export_heap_base() - .import_memory() - .build() + substrate_wasm_builder::WasmBuilder::build_using_defaults(); } #[cfg(not(feature = "std"))] diff --git a/cumulus/parachains/runtimes/testing/rococo-parachain/src/lib.rs b/cumulus/parachains/runtimes/testing/rococo-parachain/src/lib.rs index df335368be1ca29d40ed4c9fd32b6e385b33b66e..b515e8ec5c9c75851f1152908f1664d92a4d262a 100644 --- a/cumulus/parachains/runtimes/testing/rococo-parachain/src/lib.rs +++ b/cumulus/parachains/runtimes/testing/rococo-parachain/src/lib.rs @@ -74,9 +74,9 @@ use parachains_common::{ AccountId, AssetIdForTrustBackedAssets, Signature, }; use xcm_builder::{ - AllowKnownQueryResponses, AllowSubscriptionsFrom, AsPrefixedGeneralIndex, ConvertedConcreteId, - FrameTransactionalProcessor, FungiblesAdapter, LocalMint, TrailingSetTopicAsId, - WithUniqueTopic, + AllowHrmpNotificationsFromRelayChain, AllowKnownQueryResponses, AllowSubscriptionsFrom, + AsPrefixedGeneralIndex, ConvertedConcreteId, FrameTransactionalProcessor, FungiblesAdapter, + LocalMint, TrailingSetTopicAsId, WithUniqueTopic, }; use xcm_executor::traits::JustTry; @@ -107,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_010_000, + spec_version: 1_011_000, impl_version: 0, apis: RUNTIME_API_VERSIONS, transaction_version: 6, @@ -317,7 +317,7 @@ impl pallet_message_queue::Config for Runtime { // The XCMP queue pallet is only ever able to handle the `Sibling(ParaId)` origin: type QueueChangeHandler = NarrowOriginToSibling; type QueuePausedQuery = NarrowOriginToSibling; - type HeapSize = sp_core::ConstU32<{ 64 * 1024 }>; + type HeapSize = sp_core::ConstU32<{ 103 * 1024 }>; type MaxStale = sp_core::ConstU32<8>; type ServiceWeight = MessageQueueServiceWeight; type IdleMaxServiceWeight = (); @@ -327,9 +327,9 @@ impl cumulus_pallet_aura_ext::Config for Runtime {} parameter_types! { pub const RocLocation: Location = Location::parent(); - pub const RococoNetwork: Option = Some(NetworkId::Rococo); + pub const RococoNetwork: NetworkId = NetworkId::Rococo; pub RelayChainOrigin: RuntimeOrigin = cumulus_pallet_xcm::Origin::Relay.into(); - pub UniversalLocation: InteriorLocation = [Parachain(ParachainInfo::parachain_id().into())].into(); + pub UniversalLocation: InteriorLocation = [GlobalConsensus(RococoNetwork::get()), Parachain(ParachainInfo::parachain_id().into())].into(); pub CheckingAccount: AccountId = PolkadotXcm::check_account(); } @@ -444,6 +444,8 @@ pub type Barrier = TrailingSetTopicAsId<( AllowKnownQueryResponses, // Subscriptions for version tracking are OK. AllowSubscriptionsFrom, + // HRMP notifications from the relay chain are OK. + AllowHrmpNotificationsFromRelayChain, )>; parameter_types! { @@ -488,6 +490,7 @@ impl xcm_executor::Config for XcmConfig { type HrmpNewChannelOpenRequestHandler = (); type HrmpChannelAcceptedHandler = (); type HrmpChannelClosingHandler = (); + type XcmRecorder = PolkadotXcm; } /// Local origins on this chain are allowed to dispatch XCM sends/executions. @@ -539,7 +542,11 @@ impl cumulus_pallet_xcmp_queue::Config for Runtime { type VersionWrapper = (); // Enqueue XCMP messages from siblings for later processing. type XcmpQueue = TransformOrigin; - type MaxInboundSuspended = sp_core::ConstU32<1_000>; + type MaxInboundSuspended = ConstU32<1_000>; + type MaxActiveOutboundChannels = ConstU32<128>; + // Most on-chain HRMP channels are configured to use 102400 bytes of max message size, so we + // need to set the page size larger than that until we reduce the channel size on-chain. + type MaxPageSize = ConstU32<{ 103 * 1024 }>; type ControllerOrigin = EnsureRoot; type ControllerOriginConverter = XcmOriginToTransactDispatchOrigin; type WeightInfo = cumulus_pallet_xcmp_queue::weights::SubstrateWeight; diff --git a/cumulus/polkadot-parachain/Cargo.toml b/cumulus/polkadot-parachain/Cargo.toml index 280ece30fb6834c2a5031f33cd316b5a137f65f5..a22606edb6c5c0013a10094a06efbac5ae486170 100644 --- a/cumulus/polkadot-parachain/Cargo.toml +++ b/cumulus/polkadot-parachain/Cargo.toml @@ -17,7 +17,7 @@ path = "src/main.rs" [dependencies] async-trait = "0.1.79" clap = { version = "4.5.3", features = ["derive"] } -codec = { package = "parity-scale-codec", version = "3.0.0" } +codec = { package = "parity-scale-codec", version = "3.6.12" } futures = "0.3.28" hex-literal = "0.4.1" log = { workspace = true, default-features = true } @@ -118,7 +118,7 @@ substrate-build-script-utils = { path = "../../substrate/utils/build-script-util [dev-dependencies] assert_cmd = "2.0" -nix = { version = "0.26.1", features = ["signal"] } +nix = { version = "0.28.0", features = ["signal"] } tempfile = "3.8.0" tokio = { version = "1.32.0", features = ["macros", "parking_lot", "time"] } wait-timeout = "0.2" diff --git a/cumulus/polkadot-parachain/src/chain_spec/mod.rs b/cumulus/polkadot-parachain/src/chain_spec/mod.rs index bbda334e4c66e0d9f8fcb7434bc4f218d81dc6e5..136a19e3166bd255e6eb7c95f07ee4613aa61e89 100644 --- a/cumulus/polkadot-parachain/src/chain_spec/mod.rs +++ b/cumulus/polkadot-parachain/src/chain_spec/mod.rs @@ -37,11 +37,12 @@ const SAFE_XCM_VERSION: u32 = xcm::prelude::XCM_VERSION; /// Generic extensions for Parachain ChainSpecs. #[derive(Debug, Clone, PartialEq, Serialize, Deserialize, ChainSpecGroup, ChainSpecExtension)] -#[serde(deny_unknown_fields)] pub struct Extensions { /// The relay chain of the Parachain. + #[serde(alias = "relayChain", alias = "RelayChain")] pub relay_chain: String, /// The id of the Parachain. + #[serde(alias = "paraId", alias = "ParaId")] pub para_id: u32, } @@ -78,3 +79,22 @@ where pub fn get_collator_keys_from_seed(seed: &str) -> ::Public { get_from_seed::(seed) } + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn can_decode_extension_camel_and_snake_case() { + let camel_case = r#"{"relayChain":"relay","paraId":1}"#; + let snake_case = r#"{"relay_chain":"relay","para_id":1}"#; + let pascal_case = r#"{"RelayChain":"relay","ParaId":1}"#; + + let camel_case_extension: Extensions = serde_json::from_str(camel_case).unwrap(); + let snake_case_extension: Extensions = serde_json::from_str(snake_case).unwrap(); + let pascal_case_extension: Extensions = serde_json::from_str(pascal_case).unwrap(); + + assert_eq!(camel_case_extension, snake_case_extension); + assert_eq!(snake_case_extension, pascal_case_extension); + } +} diff --git a/cumulus/polkadot-parachain/src/chain_spec/people.rs b/cumulus/polkadot-parachain/src/chain_spec/people.rs index 1408ef0aff67adf4942b8dcd8d4198c8cd60910b..db8756e68819b3f7abaeeea9e8b684f75beda5dc 100644 --- a/cumulus/polkadot-parachain/src/chain_spec/people.rs +++ b/cumulus/polkadot-parachain/src/chain_spec/people.rs @@ -60,8 +60,9 @@ impl PeopleRuntimeType { pub fn load_config(&self) -> Result, String> { match self { - PeopleRuntimeType::Kusama => - todo!("Update chain-spec: ../../chain-specs/people-kusama.json - https://github.com/paritytech/polkadot-sdk/pull/3961#issuecomment-2037438431"), + PeopleRuntimeType::Kusama => Ok(Box::new(GenericChainSpec::from_json_bytes( + &include_bytes!("../../chain-specs/people-kusama.json")[..], + )?)), PeopleRuntimeType::Polkadot => todo!("Generate chain-spec: ../../chain-specs/people-polkadot.json"), PeopleRuntimeType::Rococo => Ok(Box::new(GenericChainSpec::from_json_bytes( diff --git a/cumulus/primitives/aura/Cargo.toml b/cumulus/primitives/aura/Cargo.toml index 21c06ef22d9a13bf8361156ea5e1af1216aa3e28..ef96f334d63753c73de669ddcd98b6868a88389b 100644 --- a/cumulus/primitives/aura/Cargo.toml +++ b/cumulus/primitives/aura/Cargo.toml @@ -10,7 +10,7 @@ description = "Core primitives for Aura in Cumulus" workspace = true [dependencies] -codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = ["derive"] } +codec = { package = "parity-scale-codec", version = "3.6.12", default-features = false, features = ["derive"] } # Substrate sp-api = { path = "../../../substrate/primitives/api", default-features = false } diff --git a/cumulus/primitives/core/Cargo.toml b/cumulus/primitives/core/Cargo.toml index 62c3f6751917ad4aaaaec6509c852a5cfd75d7f8..595aa5f72bf2453edea23e372865de95e9e46699 100644 --- a/cumulus/primitives/core/Cargo.toml +++ b/cumulus/primitives/core/Cargo.toml @@ -10,7 +10,7 @@ description = "Cumulus related core primitive types and traits" workspace = true [dependencies] -codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = ["derive"] } +codec = { package = "parity-scale-codec", version = "3.6.12", default-features = false, features = ["derive"] } scale-info = { version = "2.11.1", default-features = false, features = ["derive"] } # Substrate diff --git a/cumulus/primitives/core/src/lib.rs b/cumulus/primitives/core/src/lib.rs index 7f7353685657e7bf6bfb2c05faba32315bbbb706..29216d513465160eb94db76faedb6e7fd992b461 100644 --- a/cumulus/primitives/core/src/lib.rs +++ b/cumulus/primitives/core/src/lib.rs @@ -64,6 +64,8 @@ pub enum MessageSendError { TooBig, /// Some other error. Other, + /// There are too many channels open at once. + TooManyChannels, } impl From for &'static str { @@ -74,6 +76,7 @@ impl From for &'static str { NoChannel => "NoChannel", TooBig => "TooBig", Other => "Other", + TooManyChannels => "TooManyChannels", } } } @@ -135,6 +138,11 @@ pub trait GetChannelInfo { fn get_channel_info(id: ParaId) -> Option; } +/// List all open outgoing channels. +pub trait ListChannelInfos { + fn outgoing_channels() -> Vec; +} + /// Something that should be called when sending an upward message. pub trait UpwardMessageSender { /// Send the given UMP message; return the expected number of blocks before the message will diff --git a/cumulus/primitives/parachain-inherent/Cargo.toml b/cumulus/primitives/parachain-inherent/Cargo.toml index fcf4c93bc2f01dc9e60f5ad2d74e302f5247b955..0156eb02e2b4aaa9ee02e4e237f305c20792569d 100644 --- a/cumulus/primitives/parachain-inherent/Cargo.toml +++ b/cumulus/primitives/parachain-inherent/Cargo.toml @@ -11,14 +11,14 @@ workspace = true [dependencies] async-trait = { version = "0.1.79", optional = true } -codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = ["derive"] } +codec = { package = "parity-scale-codec", version = "3.6.12", default-features = false, features = ["derive"] } scale-info = { version = "2.11.1", default-features = false, features = ["derive"] } # Substrate sp-core = { path = "../../../substrate/primitives/core", default-features = false } sp-inherents = { path = "../../../substrate/primitives/inherents", default-features = false } -sp-runtime = { path = "../../../substrate/primitives/runtime", optional = true } -sp-state-machine = { path = "../../../substrate/primitives/state-machine", optional = true } +sp-runtime = { path = "../../../substrate/primitives/runtime", optional = true, default-features = false } +sp-state-machine = { path = "../../../substrate/primitives/state-machine", optional = true, default-features = false } sp-std = { path = "../../../substrate/primitives/std", default-features = false } sp-trie = { path = "../../../substrate/primitives/trie", default-features = false } @@ -34,6 +34,8 @@ std = [ "scale-info/std", "sp-core/std", "sp-inherents/std", + "sp-runtime?/std", + "sp-state-machine?/std", "sp-std/std", "sp-trie/std", ] diff --git a/cumulus/primitives/storage-weight-reclaim/Cargo.toml b/cumulus/primitives/storage-weight-reclaim/Cargo.toml index 6dbf7904bf796e81415b967637d9770356142603..bdfb83ad72a96930c1dae2d2c054a2c19c5cfcb2 100644 --- a/cumulus/primitives/storage-weight-reclaim/Cargo.toml +++ b/cumulus/primitives/storage-weight-reclaim/Cargo.toml @@ -10,7 +10,7 @@ license = "Apache-2.0" workspace = true [dependencies] -codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = ["derive"] } +codec = { package = "parity-scale-codec", version = "3.6.12", default-features = false, features = ["derive"] } log = { workspace = true } scale-info = { version = "2.11.1", default-features = false, features = ["derive"] } diff --git a/cumulus/primitives/timestamp/Cargo.toml b/cumulus/primitives/timestamp/Cargo.toml index 59f327b2642a292db56708f5770ebb35b1b82d1d..7a6f4787ba3121cf0c9c7eec3b9f3794c870037d 100644 --- a/cumulus/primitives/timestamp/Cargo.toml +++ b/cumulus/primitives/timestamp/Cargo.toml @@ -10,7 +10,7 @@ license = "Apache-2.0" workspace = true [dependencies] -codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = ["derive"] } +codec = { package = "parity-scale-codec", version = "3.6.12", default-features = false, features = ["derive"] } futures = "0.3.28" # Substrate diff --git a/cumulus/primitives/utility/Cargo.toml b/cumulus/primitives/utility/Cargo.toml index 1e2c300b9ba257d2c8fb998689ae45847099dd63..85e3ac2f7606c9e12aa4d38f0c44c3fe1818b107 100644 --- a/cumulus/primitives/utility/Cargo.toml +++ b/cumulus/primitives/utility/Cargo.toml @@ -10,7 +10,7 @@ description = "Helper datatypes for Cumulus" workspace = true [dependencies] -codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = ["derive"] } +codec = { package = "parity-scale-codec", version = "3.6.12", default-features = false, features = ["derive"] } log = { workspace = true } # Substrate diff --git a/cumulus/primitives/utility/src/lib.rs b/cumulus/primitives/utility/src/lib.rs index d5d411356dc385948f31730ba65dcd26074d0336..64784eb36f846f7b325aaaa5ed72966e3d59a1b8 100644 --- a/cumulus/primitives/utility/src/lib.rs +++ b/cumulus/primitives/utility/src/lib.rs @@ -34,8 +34,8 @@ use sp_runtime::{ SaturatedConversion, }; use sp_std::{marker::PhantomData, prelude::*}; -use xcm::{latest::prelude::*, WrapVersion}; -use xcm_builder::TakeRevenue; +use xcm::{latest::prelude::*, VersionedLocation, VersionedXcm, WrapVersion}; +use xcm_builder::{InspectMessageQueues, TakeRevenue}; use xcm_executor::{ traits::{MatchesFungibles, TransactAsset, WeightTrader}, AssetsInHolding, @@ -69,6 +69,9 @@ where let price = P::price_for_delivery((), &xcm); let versioned_xcm = W::wrap_version(&d, xcm).map_err(|()| SendError::DestinationUnsupported)?; + versioned_xcm + .validate_xcm_nesting() + .map_err(|()| SendError::ExceedsMaxMessageSize)?; let data = versioned_xcm.encode(); Ok((data, price)) @@ -90,6 +93,14 @@ where } } +impl InspectMessageQueues + for ParentAsUmp +{ + fn get_messages() -> Vec<(VersionedLocation, Vec>)> { + T::get_messages() + } +} + /// Contains information to handle refund/payment for xcm-execution #[derive(Clone, Eq, PartialEq, Debug)] struct AssetTraderRefunder { @@ -526,6 +537,8 @@ impl< mod test_xcm_router { use super::*; use cumulus_primitives_core::UpwardMessage; + use frame_support::assert_ok; + use xcm::MAX_XCM_DECODE_DEPTH; /// Validates [`validate`] for required Some(destination) and Some(message) struct OkFixedXcmHashWithAssertingRequiredInputsSender; @@ -621,6 +634,29 @@ mod test_xcm_router { )>(dest.into(), message) ); } + + #[test] + fn parent_as_ump_validate_nested_xcm_works() { + let dest = Parent; + + type Router = ParentAsUmp<(), (), ()>; + + // Message that is not too deeply nested: + let mut good = Xcm(vec![ClearOrigin]); + for _ in 0..MAX_XCM_DECODE_DEPTH - 1 { + good = Xcm(vec![SetAppendix(good)]); + } + + // Check that the good message is validated: + assert_ok!(::validate(&mut Some(dest.into()), &mut Some(good.clone()))); + + // Nesting the message one more time should reject it: + let bad = Xcm(vec![SetAppendix(good)]); + assert_eq!( + Err(SendError::ExceedsMaxMessageSize), + ::validate(&mut Some(dest.into()), &mut Some(bad)) + ); + } } #[cfg(test)] mod test_trader { diff --git a/cumulus/test/client/Cargo.toml b/cumulus/test/client/Cargo.toml index 254361e85420de982a984f76d76b96a5c7d3b4a4..120983eb9390e9007c13b08c763f13446011f98e 100644 --- a/cumulus/test/client/Cargo.toml +++ b/cumulus/test/client/Cargo.toml @@ -9,7 +9,7 @@ publish = false workspace = true [dependencies] -codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = ["derive"] } +codec = { package = "parity-scale-codec", version = "3.6.12", default-features = false, features = ["derive"] } # Substrate sc-service = { path = "../../../substrate/client/service" } diff --git a/cumulus/test/client/src/lib.rs b/cumulus/test/client/src/lib.rs index a39a662553b0853ec810a7b5091d521b3e3b40bb..d233ad2691768c0c1d563c3a0f4c62b44f4c9b23 100644 --- a/cumulus/test/client/src/lib.rs +++ b/cumulus/test/client/src/lib.rs @@ -45,33 +45,18 @@ pub use substrate_test_client::*; pub type ParachainBlockData = cumulus_primitives_core::ParachainBlockData; -mod local_executor { - /// Native executor instance. - pub struct LocalExecutor; - - impl sc_executor::NativeExecutionDispatch for LocalExecutor { - type ExtendHostFunctions = - cumulus_primitives_proof_size_hostfunction::storage_proof_size::HostFunctions; - - fn dispatch(method: &str, data: &[u8]) -> Option> { - cumulus_test_runtime::api::dispatch(method, data) - } - - fn native_version() -> sc_executor::NativeVersion { - cumulus_test_runtime::native_version() - } - } -} - -/// Native executor used for tests. -pub use local_executor::LocalExecutor; - /// Test client database backend. pub type Backend = substrate_test_client::Backend; /// Test client executor. -pub type Executor = - client::LocalCallExecutor>; +pub type Executor = client::LocalCallExecutor< + Block, + Backend, + WasmExecutor<( + sp_io::SubstrateHostFunctions, + cumulus_primitives_proof_size_hostfunction::storage_proof_size::HostFunctions, + )>, +>; /// Test client builder for Cumulus pub type TestClientBuilder = @@ -100,7 +85,7 @@ impl substrate_test_client::GenesisInit for GenesisParameters { } } -/// A `test-runtime` extensions to `TestClientBuilder`. +/// A `test-runtime` extensions to [`TestClientBuilder`]. pub trait TestClientBuilderExt: Sized { /// Build the test client. fn build(self) -> Client { diff --git a/cumulus/test/relay-sproof-builder/Cargo.toml b/cumulus/test/relay-sproof-builder/Cargo.toml index ff5c4bd66b9742383bcd170f0012695d7f0c72d2..d775c61f7801e98b4c8e8436eb95c1ec86854d77 100644 --- a/cumulus/test/relay-sproof-builder/Cargo.toml +++ b/cumulus/test/relay-sproof-builder/Cargo.toml @@ -10,7 +10,7 @@ description = "Mocked relay state proof builder for testing Cumulus." workspace = true [dependencies] -codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = ["derive"] } +codec = { package = "parity-scale-codec", version = "3.6.12", default-features = false, features = ["derive"] } # Substrate sp-runtime = { path = "../../../substrate/primitives/runtime", default-features = false } diff --git a/cumulus/test/runtime/Cargo.toml b/cumulus/test/runtime/Cargo.toml index 1969045640ed1e8c95b828fb5f4073875c3e63b0..eb160bd3355e1ac409117b361688a953fb6bb1d3 100644 --- a/cumulus/test/runtime/Cargo.toml +++ b/cumulus/test/runtime/Cargo.toml @@ -9,7 +9,7 @@ publish = false workspace = true [dependencies] -codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = ["derive"] } +codec = { package = "parity-scale-codec", version = "3.6.12", default-features = false, features = ["derive"] } scale-info = { version = "2.11.1", default-features = false, features = ["derive"] } # Substrate diff --git a/cumulus/test/runtime/build.rs b/cumulus/test/runtime/build.rs index 5e5f6a35a505a957a3494285b7b649e6ee4e61f7..ebd5c178cba07e2889b6501a9be490344467d228 100644 --- a/cumulus/test/runtime/build.rs +++ b/cumulus/test/runtime/build.rs @@ -18,16 +18,10 @@ fn main() { use substrate_wasm_builder::WasmBuilder; - WasmBuilder::new() - .with_current_project() - .export_heap_base() - .import_memory() - .build(); + WasmBuilder::build_using_defaults(); - WasmBuilder::new() - .with_current_project() + WasmBuilder::init_with_defaults() .enable_feature("increment-spec-version") - .import_memory() .set_file_name("wasm_binary_spec_version_incremented.rs") .build(); } diff --git a/cumulus/test/service/Cargo.toml b/cumulus/test/service/Cargo.toml index 18213b2f6326c4d755e07d66cb13ed4424226fc7..c54e19d0238034d83d5dd77164bbdc017ef4e728 100644 --- a/cumulus/test/service/Cargo.toml +++ b/cumulus/test/service/Cargo.toml @@ -15,7 +15,7 @@ path = "src/main.rs" [dependencies] async-trait = "0.1.79" clap = { version = "4.5.3", features = ["derive"] } -codec = { package = "parity-scale-codec", version = "3.0.0" } +codec = { package = "parity-scale-codec", version = "3.6.12" } criterion = { version = "0.5.1", features = ["async_tokio"] } jsonrpsee = { version = "0.22", features = ["server"] } rand = "0.8.5" diff --git a/cumulus/test/service/src/lib.rs b/cumulus/test/service/src/lib.rs index 11aa2e5b9f35c353bb4602385a28e41f3caab261..f2a612803861ce143aa08d6ae7abbf8963c31ef3 100644 --- a/cumulus/test/service/src/lib.rs +++ b/cumulus/test/service/src/lib.rs @@ -824,6 +824,8 @@ pub fn node_config( rpc_message_buffer_capacity: Default::default(), rpc_batch_config: RpcBatchRequestConfig::Unlimited, rpc_rate_limit: None, + rpc_rate_limit_whitelisted_ips: Default::default(), + rpc_rate_limit_trust_proxy_headers: Default::default(), prometheus_config: None, telemetry_endpoints: None, default_heap_pages: None, diff --git a/cumulus/xcm/xcm-emulator/Cargo.toml b/cumulus/xcm/xcm-emulator/Cargo.toml index 6b45770a8e3df47cb083dba5a8a0eeed1759e338..0ed77bf5b7073bc9e3041388206203ce7c1829a2 100644 --- a/cumulus/xcm/xcm-emulator/Cargo.toml +++ b/cumulus/xcm/xcm-emulator/Cargo.toml @@ -10,7 +10,7 @@ license = "Apache-2.0" workspace = true [dependencies] -codec = { package = "parity-scale-codec", version = "3.0.0" } +codec = { package = "parity-scale-codec", version = "3.6.12" } paste = "1.0.14" log = { workspace = true } lazy_static = "1.4.0" diff --git a/cumulus/xcm/xcm-emulator/src/lib.rs b/cumulus/xcm/xcm-emulator/src/lib.rs index babb318a99500932dd8a2e42a2b443944751d286..a50f33951d056d56ab281934cc7987018d91f7c6 100644 --- a/cumulus/xcm/xcm-emulator/src/lib.rs +++ b/cumulus/xcm/xcm-emulator/src/lib.rs @@ -34,7 +34,9 @@ pub use frame_support::{ }, weights::{Weight, WeightMeter}, }; -pub use frame_system::{Config as SystemConfig, Pallet as SystemPallet}; +pub use frame_system::{ + pallet_prelude::BlockNumberFor, Config as SystemConfig, Pallet as SystemPallet, +}; pub use pallet_balances::AccountData; pub use pallet_message_queue; pub use sp_arithmetic::traits::Bounded; @@ -54,7 +56,7 @@ pub use cumulus_primitives_core::{ pub use cumulus_primitives_parachain_inherent::ParachainInherentData; pub use cumulus_test_relay_sproof_builder::RelayStateSproofBuilder; pub use pallet_message_queue::{Config as MessageQueueConfig, Pallet as MessageQueuePallet}; -pub use parachains_common::{AccountId, Balance, BlockNumber}; +pub use parachains_common::{AccountId, Balance}; pub use polkadot_primitives; pub use polkadot_runtime_parachains::inclusion::{AggregateMessageOrigin, UmpQueueId}; @@ -657,7 +659,7 @@ macro_rules! decl_test_parachains { .clone() ); ::System::initialize(&block_number, &parent_head_data.hash(), &Default::default()); - <::ParachainSystem as Hooks<$crate::BlockNumber>>::on_initialize(block_number); + <::ParachainSystem as Hooks<$crate::BlockNumberFor>>::on_initialize(block_number); let _ = ::ParachainSystem::set_validation_data( ::RuntimeOrigin::none(), diff --git a/docker/dockerfiles/bridges_zombienet_tests_injected.Dockerfile b/docker/dockerfiles/bridges_zombienet_tests_injected.Dockerfile index 938f5cc45a1141a344c223a16a026c5b86494096..196ba861f503c0fc82b6eb0e428df600ce6bfd49 100644 --- a/docker/dockerfiles/bridges_zombienet_tests_injected.Dockerfile +++ b/docker/dockerfiles/bridges_zombienet_tests_injected.Dockerfile @@ -1,7 +1,7 @@ # this image is built on top of existing Zombienet image ARG ZOMBIENET_IMAGE # this image uses substrate-relay image built elsewhere -ARG SUBSTRATE_RELAY_IMAGE=docker.io/paritytech/substrate-relay:v1.2.1 +ARG SUBSTRATE_RELAY_IMAGE=docker.io/paritytech/substrate-relay:v1.5.0 # metadata ARG VCS_REF diff --git a/docs/contributor/container.md b/docs/contributor/container.md index 9c542f411c81f4237e69ffaf63d4686eeac204e4..ec51b8b9d7ccd1b4933c3977ce92c7f0f96966a6 100644 --- a/docs/contributor/container.md +++ b/docs/contributor/container.md @@ -24,7 +24,7 @@ The command below allows building a Linux binary without having to even install docker run --rm -it \ -w /polkadot-sdk \ -v $(pwd):/polkadot-sdk \ - paritytech/ci-unified:bullseye-1.75.0-2024-01-22-v20240222 \ + docker.io/paritytech/ci-unified:bullseye-1.77.0-2024-04-10-v20240408 \ cargo build --release --locked -p polkadot-parachain-bin --bin polkadot-parachain sudo chown -R $(id -u):$(id -g) target/ ``` diff --git a/docs/contributor/prdoc.md b/docs/contributor/prdoc.md index af0ede5107a6cb1ea31d8b81fe16b06553ef64ac..0c8165af40f4d4f0438ab780c5f87eb5fe2ad62e 100644 --- a/docs/contributor/prdoc.md +++ b/docs/contributor/prdoc.md @@ -1,55 +1,31 @@ # PRDoc -## Intro - -With the merge of [PR #1946](https://github.com/paritytech/polkadot-sdk/pull/1946), a new method for -documenting changes has been introduced: `prdoc`. The [prdoc repository](https://github.com/paritytech/prdoc) -contains more documentation and tooling. - -The current document describes how to quickly get started authoring `PRDoc` files. +A [prdoc](https://github.com/paritytech/prdoc) is like a changelog but for a Pull Request. We use this approach to +record changes on a crate level. This information is then processed by the release team to apply the correct crate +version bumps and to generate the CHANGELOG of the next release. ## Requirements -When creating a PR, the author needs to decides with the `R0` label whether the change (PR) should -appear in the release notes or not. - -Labelling a PR with `R0` means that no `PRDoc` is required. - -A PR without the `R0` label **does** require a valid `PRDoc` file to be introduced in the PR. - -## PRDoc how-to - -A `.prdoc` file is a YAML file with a defined structure (ie JSON Schema). - -For significant changes, a `.prdoc` file is mandatory and the file must meet the following -requirements: -- file named `pr_NNNN.prdoc` where `NNNN` is the PR number. - For convenience, those file can also contain a short description: `pr_NNNN_foobar.prdoc`. -- located under the [`prdoc` folder](https://github.com/paritytech/polkadot-sdk/tree/master/prdoc) of the repository -- compliant with the [JSON schema](https://json-schema.org/) defined in `prdoc/schema_user.json` - -Those requirements can be fulfilled manually without any tooling but a text editor. - -## Tooling - -Users might find the following helpers convenient: -- Setup VSCode to be aware of the prdoc schema: see [using VSCode](https://github.com/paritytech/prdoc#using-vscode) -- Using the `prdoc` cli to: - - generate a `PRDoc` file from a [template defined in the Polkadot SDK - repo](https://github.com/paritytech/polkadot-sdk/blob/master/prdoc/.template.prdoc) simply providing a PR number - - check the validity of one or more `PRDoc` files +When creating a PR, the author needs to decide with the `R0-silent` label whether the PR has to contain a prdoc. The +`R0` label should only be placed for No-OP changes like correcting a typo in a comment or CI stuff. If unsure, ping +the [CODEOWNERS](../../.github/CODEOWNERS) for advice. -## `prdoc` cli usage +## PRDoc How-To -The `prdoc` cli documentation can be found at https://github.com/paritytech/prdoc#prdoc +A `.prdoc` file is a YAML file with a defined structure (ie JSON Schema). Please follow these steps to generate one: -tldr: -- `prdoc generate ` -- `prdoc check -n ` +1. Install the [`prdoc` CLI](https://github.com/paritytech/prdoc) by running `cargo install prdoc`. +1. Open a Pull Request and get the PR number. +1. Generate the file with `prdoc generate `. The output filename will be printed. +1. Optional: Install the `prdoc/schema_user.json` schema in your editor, for example +[VsCode](https://github.com/paritytech/prdoc?tab=readme-ov-file#schemas). +1. Edit your `.prdoc` file according to the [Audience](#pick-an-audience) and [SemVer](#record-semver-changes) sections. +1. Check your prdoc with `prdoc check -n `. This is optional since the CI will also check it. -where is the PR number. +> **Tip:** GitHub CLI and jq can be used to provide the number of your PR to generate the correct file: +> `prdoc generate $(gh pr view --json number | jq '.number') -o prdoc` -## Pick an audience +## Pick An Audience While describing a PR, the author needs to consider which audience(s) need to be addressed. The list of valid audiences is described and documented in the JSON schema as follow: @@ -65,7 +41,41 @@ The list of valid audiences is described and documented in the JSON schema as fo - `Runtime User`: Anyone using the runtime. This can be a token holder or a dev writing a front end for a chain. -## Tips +If you have a change that affects multiple audiences, you can either list them all, or write multiple sections and +re-phrase the changes for each audience. + +## Record SemVer Changes + +All published crates that got modified need to have an entry in the `crates` section of your `PRDoc`. This entry tells +the release team how to bump the crate version prior to the next release. It is very important that this information is +correct, otherwise it could break the code of downstream teams. + +The bump can either be `major`, `minor`, `patch` or `none`. The three first options are defined by +[rust-lang.org](https://doc.rust-lang.org/cargo/reference/semver.html), whereas `None` should be picked if no other +applies. The `None` option is equivalent to the `R0-silent` label, but on a crate level. Experimental and private APIs +are exempt from bumping and can be broken at any time. Please read the [Crate Section](../RELEASE.md) of the RELEASE doc +about them. + +> **Note**: There is currently no CI in place to sanity check this information, but should be added soon. + +### Example + +For example when you modified two crates and record the changes: + +```yaml +crates: +- name: frame-example + bump: major +- name: frame-example-pallet + bump: minor +``` + +It means that downstream code using `frame-example-pallet` is still guaranteed to work as before, while code using +`frame-example` might break. + +### Dependencies -The PRDoc schema is defined in each repo and usually is quite restrictive. -You cannot simply add a new property to a `PRDoc` file unless the Schema allows it. +A crate that depends on another crate will automatically inherit its `major` bumps. This means that you do not need to +bump a crate that had a SemVer breaking change only from re-exporting another crate with a breaking change. +`minor` an `patch` bumps do not need to be inherited, since `cargo` will automatically update them to the latest +compatible version. diff --git a/docs/sdk/Cargo.toml b/docs/sdk/Cargo.toml index 426c5d9de4a022093c5e3c792722021601817c69..269ed4d012c8366bf5d7d9ae4bd18803dd0dea79 100644 --- a/docs/sdk/Cargo.toml +++ b/docs/sdk/Cargo.toml @@ -15,7 +15,7 @@ workspace = true [dependencies] # Needed for all FRAME-based code -parity-scale-codec = { version = "3.0.0", default-features = false } +parity-scale-codec = { version = "3.6.12", default-features = false } scale-info = { version = "2.6.0", default-features = false } frame = { package = "polkadot-sdk-frame", path = "../../substrate/frame", features = [ "experimental", @@ -51,6 +51,8 @@ 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" } +sc-executor = { path = "../../substrate/client/executor" } +sc-service = { path = "../../substrate/client/service" } substrate-wasm-builder = { path = "../../substrate/utils/wasm-builder" } @@ -60,9 +62,12 @@ cumulus-pallet-parachain-system = { path = "../../cumulus/pallets/parachain-syst "parameterized-consensus-hook", ] } parachain-info = { package = "staging-parachain-info", path = "../../cumulus/parachains/pallets/parachain-info" } -pallet-aura = { path = "../../substrate/frame/aura", default-features = false } +cumulus-primitives-proof-size-hostfunction = { path = "../../cumulus/primitives/proof-size-hostfunction" } +cumulus-client-service = { path = "../../cumulus/client/service" } +cumulus-primitives-storage-weight-reclaim = { path = "../../cumulus/primitives/storage-weight-reclaim" } # Pallets and FRAME internals +pallet-aura = { path = "../../substrate/frame/aura" } pallet-timestamp = { path = "../../substrate/frame/timestamp" } pallet-balances = { path = "../../substrate/frame/balances" } pallet-assets = { path = "../../substrate/frame/assets" } diff --git a/docs/sdk/src/guides/enable_pov_reclaim.rs b/docs/sdk/src/guides/enable_pov_reclaim.rs new file mode 100644 index 0000000000000000000000000000000000000000..3c0c5fba2158691b51abdcceed5db5130e58c9b4 --- /dev/null +++ b/docs/sdk/src/guides/enable_pov_reclaim.rs @@ -0,0 +1,84 @@ +//! This guide will teach you how to enable storage weight reclaiming for a parachain. The +//! explanations in this guide assume a project structure similar to the one detailed in +//! the [substrate documentation](crate::polkadot_sdk::substrate#anatomy-of-a-binary-crate). Full +//! technical details are available in the original [pull request](https://github.com/paritytech/polkadot-sdk/pull/3002). +//! +//! # What is PoV reclaim? +//! When a parachain submits a block to a relay chain like Polkadot or Kusama, it sends the block +//! itself and a storage proof. Together they form the Proof-of-Validity (PoV). The PoV allows the +//! relay chain to validate the parachain block by re-executing it. Relay chain +//! validators distribute this PoV among themselves over the network. This distribution is costly +//! and limits the size of the storage proof. The storage weight dimension of FRAME weights reflects +//! this cost and limits the size of the storage proof. However, the storage weight determined +//! during [benchmarking](crate::reference_docs::frame_benchmarking_weight) represents the worst +//! case. In reality, runtime operations often consume less space in the storage proof. PoV reclaim +//! offers a mechanism to reclaim the difference between the benchmarked worst-case and the real +//! proof-size consumption. +//! +//! +//! # How to enable PoV reclaim +//! ## 1. Add the host function to your node +//! +//! To reclaim excess storage weight, a parachain runtime needs the +//! ability to fetch the size of the storage proof from the node. The reclaim +//! mechanism uses the +//! [`storage_proof_size`](cumulus_primitives_proof_size_hostfunction::storage_proof_size) +//! host function for this purpose. For convenience, cumulus provides +//! [`ParachainHostFunctions`](cumulus_client_service::ParachainHostFunctions), a set of +//! host functions typically used by cumulus-based parachains. In the binary crate of your +//! parachain, find the instantiation of the [`WasmExecutor`](sc_executor::WasmExecutor) and set the +//! correct generic type. +//! +//! This example from the parachain-template shows a type definition that includes the correct +//! host functions. +#![doc = docify::embed!("../../templates/parachain/node/src/service.rs", wasm_executor)] +//! +//! > **Note:** +//! > +//! > If you see error `runtime requires function imports which are not present on the host: +//! > 'env:ext_storage_proof_size_storage_proof_size_version_1'`, it is likely +//! > that this step in the guide was not set up correctly. +//! +//! ## 2. Enable storage proof recording during import +//! +//! The reclaim mechanism reads the size of the currently recorded storage proof multiple times +//! during block authoring and block import. Proof recording during authoring is already enabled on +//! parachains. You must also ensure that storage proof recording is enabled during block import. +//! Find where your node builds the fundamental substrate components by calling +//! [`new_full_parts`](sc_service::new_full_parts). Replace this +//! with [`new_full_parts_record_import`](sc_service::new_full_parts_record_import) and +//! pass `true` as the last parameter to enable import recording. +#![doc = docify::embed!("../../templates/parachain/node/src/service.rs", component_instantiation)] +//! +//! > **Note:** +//! > +//! > If you see error `Storage root must match that calculated.` during block import, it is likely +//! > that this step in the guide was not +//! > set up correctly. +//! +//! ## 3. Add the SignedExtension to your runtime +//! +//! In your runtime, you will find a list of SignedExtensions. +//! To enable the reclaiming, +//! add [`StorageWeightReclaim`](cumulus_primitives_storage_weight_reclaim::StorageWeightReclaim) +//! to that list. For maximum efficiency, make sure that `StorageWeightReclaim` is last in the list. +//! The extension will check the size of the storage proof before and after an extrinsic execution. +//! It reclaims the difference between the calculated size and the benchmarked size. +#![doc = docify::embed!("../../templates/parachain/runtime/src/lib.rs", template_signed_extra)] +//! +//! ## Optional: Verify that reclaim works +//! +//! Start your node with the log target `runtime::storage_reclaim` set to `trace` to enable full +//! logging for `StorageWeightReclaim`. The following log is an example from a local testnet. To +//! trigger the log, execute any extrinsic on the network. +//! +//! ```ignore +//! ... +//! 2024-04-22 17:31:48.014 TRACE runtime::storage_reclaim: [ferdie] Reclaiming storage weight. benchmarked: 3593, consumed: 265 unspent: 0 +//! ... +//! ``` +//! +//! In the above example we see a benchmarked size of 3593 bytes, while the extrinsic only consumed +//! 265 bytes of proof size. This results in 3328 bytes of reclaim. +#![deny(rustdoc::broken_intra_doc_links)] +#![deny(rustdoc::private_intra_doc_links)] diff --git a/docs/sdk/src/guides/mod.rs b/docs/sdk/src/guides/mod.rs index 3120f25331099263087d3804d324e71555c0813d..2dc807af8eaed45d78109bd1b22528d94e24bf06 100644 --- a/docs/sdk/src/guides/mod.rs +++ b/docs/sdk/src/guides/mod.rs @@ -23,3 +23,6 @@ pub mod cumulus_enabled_parachain; /// How to make a given runtime XCM-enabled, capable of sending messages (`Transact`) between itself /// and the relay chain to which it is connected. pub mod xcm_enabled_parachain; + +/// How to enable storage weight reclaiming in a parachain node and runtime. +pub mod enable_pov_reclaim; diff --git a/docs/sdk/src/meta_contributing.rs b/docs/sdk/src/meta_contributing.rs index fcdcea9934bb6b8cf7ee6ec090ebd0939888238c..a029595254c84dfa58639279b4fcd486f25c3f0e 100644 --- a/docs/sdk/src/meta_contributing.rs +++ b/docs/sdk/src/meta_contributing.rs @@ -139,7 +139,7 @@ //! //! ```sh //! 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" \ +//! RUSTDOCFLAGS="--html-in-header $(pwd)/docs/sdk/assets/header.html --extend-css $(pwd)/docs/sdk/assets/theme.css --default-theme=ayu" \ //! cargo doc -p polkadot-sdk-docs --no-deps --open //! ``` //! diff --git a/docs/sdk/src/reference_docs/development_environment_advice.rs b/docs/sdk/src/reference_docs/development_environment_advice.rs index 21bbe78836c44b8afd70cab68e4b9b2f929fb4a0..9ba95dfa032945ac684f13b1c3961d4f8d0f649e 100644 --- a/docs/sdk/src/reference_docs/development_environment_advice.rs +++ b/docs/sdk/src/reference_docs/development_environment_advice.rs @@ -38,7 +38,7 @@ //! // Use nightly formatting. //! // See the polkadot-sdk CI job that checks formatting for the current version used in //! // polkadot-sdk. -//! "rust-analyzer.rustfmt.extraArgs": ["+nightly-2024-01-22"], +//! "rust-analyzer.rustfmt.extraArgs": ["+nightly-2024-04-10"], //! } //! ``` //! @@ -79,7 +79,7 @@ //! # Use nightly formatting. //! # See the polkadot-sdk CI job that checks formatting for the current version used in //! # polkadot-sdk. -//! extraArgs = { "+nightly-2024-01-22" }, +//! extraArgs = { "+nightly-2024-04-10" }, //! }, //! }, //! ``` diff --git a/polkadot/Cargo.toml b/polkadot/Cargo.toml index 659edcb041c35625b6f7c6ee7841eab27c4c1175..3aeec8d5961e35133233c35c38f57c2145c7f62c 100644 --- a/polkadot/Cargo.toml +++ b/polkadot/Cargo.toml @@ -43,7 +43,7 @@ tikv-jemallocator = { version = "0.5.0", features = ["unprefixed_malloc_on_suppo [dev-dependencies] assert_cmd = "2.0.4" -nix = { version = "0.26.1", features = ["signal"] } +nix = { version = "0.28.0", features = ["signal"] } tempfile = "3.2.0" tokio = "1.37" substrate-rpc-client = { path = "../substrate/utils/frame/rpc/client" } diff --git a/polkadot/cli/src/cli.rs b/polkadot/cli/src/cli.rs index 3737942e6e53fb61133cf66227129dedd4bf885c..3e5a6ccdd3c25519e7890f73c3d5a1a49e41c9c8 100644 --- a/polkadot/cli/src/cli.rs +++ b/polkadot/cli/src/cli.rs @@ -131,6 +131,23 @@ pub struct RunCmd { #[arg(long, value_name = "PATH")] pub workers_path: Option, + /// Override the maximum number of pvf execute workers. + /// + /// **Dangerous!** Do not touch unless explicitly advised to. + #[arg(long)] + pub execute_workers_max_num: Option, + /// Override the maximum number of pvf workers that can be spawned in the pvf prepare + /// pool for tasks with the priority below critical. + /// + /// **Dangerous!** Do not touch unless explicitly advised to. + + #[arg(long)] + pub prepare_workers_soft_max_num: Option, + /// Override the absolute number of pvf workers that can be spawned in the pvf prepare pool. + /// + /// **Dangerous!** Do not touch unless explicitly advised to. + #[arg(long)] + pub prepare_workers_hard_max_num: Option, /// TESTING ONLY: disable the version check between nodes and workers. #[arg(long, hide = true)] pub disable_worker_version_check: bool, diff --git a/polkadot/cli/src/command.rs b/polkadot/cli/src/command.rs index 6af93a75638891f0499029574da93dc57a291212..f5ee538e8cec5f418c0f2bb06336f78a81425cae 100644 --- a/polkadot/cli/src/command.rs +++ b/polkadot/cli/src/command.rs @@ -253,6 +253,9 @@ where .overseer_channel_capacity_override, malus_finality_delay: maybe_malus_finality_delay, hwbench, + execute_workers_max_num: cli.run.execute_workers_max_num, + prepare_workers_hard_max_num: cli.run.prepare_workers_hard_max_num, + prepare_workers_soft_max_num: cli.run.prepare_workers_soft_max_num, }, ) .map(|full| full.task_manager)?; diff --git a/polkadot/core-primitives/Cargo.toml b/polkadot/core-primitives/Cargo.toml index 8dfa0b87328b1af0bc4cbc1bcd677919acaaf892..9794f8286ac324b3f0fde27cb13db9d8d1cb8941 100644 --- a/polkadot/core-primitives/Cargo.toml +++ b/polkadot/core-primitives/Cargo.toml @@ -14,7 +14,7 @@ sp-core = { path = "../../substrate/primitives/core", default-features = false } sp-std = { path = "../../substrate/primitives/std", default-features = false } sp-runtime = { path = "../../substrate/primitives/runtime", default-features = false } scale-info = { version = "2.11.1", default-features = false, features = ["derive"] } -parity-scale-codec = { version = "3.6.1", default-features = false, features = ["derive"] } +parity-scale-codec = { version = "3.6.12", default-features = false, features = ["derive"] } [features] default = ["std"] diff --git a/polkadot/erasure-coding/Cargo.toml b/polkadot/erasure-coding/Cargo.toml index 677f15c4b9a1446c7828c78f92933f7811733ee8..b230631f72b0486a94990d575673990e81c20e66 100644 --- a/polkadot/erasure-coding/Cargo.toml +++ b/polkadot/erasure-coding/Cargo.toml @@ -13,13 +13,13 @@ workspace = true polkadot-primitives = { path = "../primitives" } polkadot-node-primitives = { package = "polkadot-node-primitives", path = "../node/primitives" } novelpoly = { package = "reed-solomon-novelpoly", version = "2.0.0" } -parity-scale-codec = { version = "3.6.1", default-features = false, features = ["derive", "std"] } +parity-scale-codec = { version = "3.6.12", default-features = false, features = ["derive", "std"] } sp-core = { path = "../../substrate/primitives/core" } sp-trie = { path = "../../substrate/primitives/trie" } thiserror = { workspace = true } [dev-dependencies] -criterion = { version = "0.4.0", default-features = false, features = ["cargo_bench_support"] } +criterion = { version = "0.5.1", default-features = false, features = ["cargo_bench_support"] } [[bench]] name = "scaling_with_validators" diff --git a/polkadot/node/collation-generation/Cargo.toml b/polkadot/node/collation-generation/Cargo.toml index ebc53a9e01bbe5abc6ba18e500ad3bafcf35ead3..0a28c3a830d101a08a49a3c9eda3dc0f60c9665d 100644 --- a/polkadot/node/collation-generation/Cargo.toml +++ b/polkadot/node/collation-generation/Cargo.toml @@ -20,7 +20,7 @@ polkadot-primitives = { path = "../../primitives" } sp-core = { path = "../../../substrate/primitives/core" } sp-maybe-compressed-blob = { path = "../../../substrate/primitives/maybe-compressed-blob" } thiserror = { workspace = true } -parity-scale-codec = { version = "3.6.1", default-features = false, features = ["bit-vec", "derive"] } +parity-scale-codec = { version = "3.6.12", default-features = false, features = ["bit-vec", "derive"] } [dev-dependencies] polkadot-node-subsystem-test-helpers = { path = "../subsystem-test-helpers" } diff --git a/polkadot/node/core/approval-voting/Cargo.toml b/polkadot/node/core/approval-voting/Cargo.toml index ced7706c40a288759dd0f5336a8389c60c8e533a..5bf80d59ede93b9fb3cab3ffdf409f895d24dbe4 100644 --- a/polkadot/node/core/approval-voting/Cargo.toml +++ b/polkadot/node/core/approval-voting/Cargo.toml @@ -12,7 +12,7 @@ workspace = true [dependencies] futures = "0.3.30" futures-timer = "3.0.2" -parity-scale-codec = { version = "3.6.1", default-features = false, features = ["bit-vec", "derive"] } +parity-scale-codec = { version = "3.6.12", default-features = false, features = ["bit-vec", "derive"] } gum = { package = "tracing-gum", path = "../../gum" } bitvec = { version = "1.0.0", default-features = false, features = ["alloc"] } schnellru = "0.2.1" @@ -21,7 +21,7 @@ schnorrkel = "0.11.4" kvdb = "0.13.0" derive_more = "0.99.17" thiserror = { workspace = true } -itertools = "0.10.5" +itertools = "0.11" polkadot-node-subsystem = { path = "../../subsystem" } polkadot-node-subsystem-util = { path = "../../subsystem-util" } @@ -53,3 +53,14 @@ kvdb-memorydb = "0.13.0" test-helpers = { package = "polkadot-primitives-test-helpers", path = "../../../primitives/test-helpers" } log = { workspace = true, default-features = true } env_logger = "0.11" + +polkadot-subsystem-bench = { path = "../../subsystem-bench" } + +[[bench]] +name = "approval-voting-regression-bench" +path = "benches/approval-voting-regression-bench.rs" +harness = false +required-features = ["subsystem-benchmarks"] + +[features] +subsystem-benchmarks = [] diff --git a/polkadot/node/core/approval-voting/benches/approval-voting-regression-bench.rs b/polkadot/node/core/approval-voting/benches/approval-voting-regression-bench.rs new file mode 100644 index 0000000000000000000000000000000000000000..9a5f0d29dbd3180676a01eba0b382dbb26ef11ea --- /dev/null +++ b/polkadot/node/core/approval-voting/benches/approval-voting-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 . + +//! approval-voting throughput test +//! +//! Approval Voting benchmark based on Kusama parameters and scale. +//! +//! Subsystems involved: +//! - approval-distribution +//! - approval-voting + +use polkadot_subsystem_bench::{ + self, + approval::{bench_approvals, prepare_test, ApprovalsOptions}, + configuration::TestConfiguration, + usage::BenchmarkUsage, + utils::save_to_file, +}; +use std::io::Write; + +const BENCH_COUNT: usize = 10; + +fn main() -> Result<(), String> { + let mut messages = vec![]; + let mut config = TestConfiguration::default(); + config.n_cores = 100; + config.n_validators = 500; + config.num_blocks = 10; + config.peer_bandwidth = 524288000000; + config.bandwidth = 524288000000; + config.latency = None; + config.connectivity = 100; + config.generate_pov_sizes(); + let options = ApprovalsOptions { + last_considered_tranche: 89, + coalesce_mean: 3.0, + coalesce_std_dev: 1.0, + coalesce_tranche_diff: 12, + enable_assignments_v2: true, + stop_when_approved: false, + workdir_prefix: "/tmp".to_string(), + num_no_shows_per_candidate: 0, + }; + + println!("Benchmarking..."); + let usages: Vec = (0..BENCH_COUNT) + .map(|n| { + print!("\r[{}{}]", "#".repeat(n), "_".repeat(BENCH_COUNT - n)); + std::io::stdout().flush().unwrap(); + let (mut env, state) = prepare_test(config.clone(), options.clone(), false); + env.runtime().block_on(bench_approvals("approvals_throughput", &mut env, state)) + }) + .collect(); + println!("\rDone!{}", " ".repeat(BENCH_COUNT)); + + let average_usage = BenchmarkUsage::average(&usages); + save_to_file( + "charts/approval-voting-regression-bench.json", + average_usage.to_chart_json().map_err(|e| e.to_string())?, + ) + .map_err(|e| e.to_string())?; + println!("{}", average_usage); + + // We expect no variance for received and sent + // but use 0.001 because we operate with floats + messages.extend(average_usage.check_network_usage(&[ + ("Received from peers", 52942.4600, 0.001), + ("Sent to peers", 63547.0330, 0.001), + ])); + messages.extend(average_usage.check_cpu_usage(&[ + ("approval-distribution", 7.0317, 0.1), + ("approval-voting", 9.5751, 0.1), + ])); + + if messages.is_empty() { + Ok(()) + } else { + eprintln!("{}", messages.join("\n")); + Err("Regressions found".to_string()) + } +} diff --git a/polkadot/node/core/approval-voting/src/lib.rs b/polkadot/node/core/approval-voting/src/lib.rs index 7ecc2b2595bce78c3c65569369a932c847552b1c..b5ed92fa39c873c0a1e5f40c52705a5803971b60 100644 --- a/polkadot/node/core/approval-voting/src/lib.rs +++ b/polkadot/node/core/approval-voting/src/lib.rs @@ -978,6 +978,7 @@ where woken_block, woken_candidate, &subsystem.metrics, + &wakeups, ).await? } next_msg = ctx.recv().fuse() => { @@ -1152,6 +1153,7 @@ async fn handle_actions( candidate_hash, delayed_approvals_timers, approval_request, + &wakeups, ) .await? .into_iter() @@ -1663,6 +1665,7 @@ async fn handle_from_overseer( |r| { let _ = res.send(r); }, + &wakeups, ) .await? .0, @@ -2477,6 +2480,7 @@ async fn check_and_import_approval( metrics: &Metrics, approval: IndirectSignedApprovalVoteV2, with_response: impl FnOnce(ApprovalCheckResult) -> T, + wakeups: &Wakeups, ) -> SubsystemResult<(Vec, T)> where Sender: SubsystemSender, @@ -2655,6 +2659,7 @@ where approved_candidate_hash, candidate_entry, ApprovalStateTransition::RemoteApproval(approval.validator), + wakeups, ) .await; actions.extend(new_actions); @@ -2689,6 +2694,10 @@ impl ApprovalStateTransition { ApprovalStateTransition::WakeupProcessed => false, } } + + fn is_remote_approval(&self) -> bool { + matches!(*self, ApprovalStateTransition::RemoteApproval(_)) + } } // Advance the approval state, either by importing an approval vote which is already checked to be @@ -2705,6 +2714,7 @@ async fn advance_approval_state( candidate_hash: CandidateHash, mut candidate_entry: CandidateEntry, transition: ApprovalStateTransition, + wakeups: &Wakeups, ) -> Vec where Sender: SubsystemSender, @@ -2835,6 +2845,43 @@ where status.required_tranches, )); + if is_approved && transition.is_remote_approval() { + // Make sure we wake other blocks in case they have + // a no-show that might be covered by this approval. + for (fork_block_hash, fork_approval_entry) in candidate_entry + .block_assignments + .iter() + .filter(|(hash, _)| **hash != block_hash) + { + let assigned_on_fork_block = validator_index + .as_ref() + .map(|validator_index| fork_approval_entry.is_assigned(*validator_index)) + .unwrap_or_default(); + if wakeups.wakeup_for(*fork_block_hash, candidate_hash).is_none() && + !fork_approval_entry.is_approved() && + assigned_on_fork_block + { + let fork_block_entry = db.load_block_entry(fork_block_hash); + if let Ok(Some(fork_block_entry)) = fork_block_entry { + actions.push(Action::ScheduleWakeup { + block_hash: *fork_block_hash, + block_number: fork_block_entry.block_number(), + candidate_hash, + // Schedule the wakeup next tick, since the assignment must be a + // no-show, because there is no-wakeup scheduled. + tick: tick_now + 1, + }) + } else { + gum::debug!( + target: LOG_TARGET, + ?fork_block_entry, + ?fork_block_hash, + "Failed to load block entry" + ) + } + } + } + } // We have no need to write the candidate entry if all of the following // is true: // @@ -2896,6 +2943,7 @@ async fn process_wakeup( relay_block: Hash, candidate_hash: CandidateHash, metrics: &Metrics, + wakeups: &Wakeups, ) -> SubsystemResult> { let mut span = state .spans @@ -3064,6 +3112,7 @@ async fn process_wakeup( candidate_hash, candidate_entry, ApprovalStateTransition::WakeupProcessed, + wakeups, ) .await, ); @@ -3294,6 +3343,7 @@ async fn issue_approval( candidate_hash: CandidateHash, delayed_approvals_timers: &mut DelayedApprovalTimer, ApprovalVoteRequest { validator_index, block_hash }: ApprovalVoteRequest, + wakeups: &Wakeups, ) -> SubsystemResult> { let mut issue_approval_span = state .spans @@ -3415,6 +3465,7 @@ async fn issue_approval( candidate_hash, candidate_entry, ApprovalStateTransition::LocalApproval(validator_index as _), + wakeups, ) .await; diff --git a/polkadot/node/core/approval-voting/src/tests.rs b/polkadot/node/core/approval-voting/src/tests.rs index f7bbbca4b8a1c0c5609898d714ad045dfd33f3ef..312d805bbefb7b2b2605093fa2cadde0a1f10511 100644 --- a/polkadot/node/core/approval-voting/src/tests.rs +++ b/polkadot/node/core/approval-voting/src/tests.rs @@ -834,7 +834,6 @@ impl ChainBuilder { cur_hash = cur_header.parent_hash; } ancestry.reverse(); - import_block( overseer, ancestry.as_ref(), @@ -1922,6 +1921,187 @@ fn subsystem_assignment_import_updates_candidate_entry_and_schedules_wakeup() { }); } +#[test] +fn subsystem_always_has_a_wakeup_when_pending() { + // Approvals sent after all assignments are no-show, the approval + // should be counted on the fork relay chain on the next tick. + test_approvals_on_fork_are_always_considered_after_no_show( + 30, + vec![(29, false), (30, false), (31, true)], + ); + // Approvals sent before fork no-shows, the approval + // should be counted on the fork relay chain when it no-shows. + test_approvals_on_fork_are_always_considered_after_no_show( + 8, // a tick smaller than the no-show tick which is 30. + vec![(7, false), (8, false), (29, false), (30, true), (31, true)], + ); +} + +fn test_approvals_on_fork_are_always_considered_after_no_show( + tick_to_send_approval: Tick, + expected_approval_status: Vec<(Tick, bool)>, +) { + let config = HarnessConfig::default(); + 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; + + assert_matches!( + overseer_recv(&mut virtual_overseer).await, + AllMessages::ChainApi(ChainApiMessage::FinalizedBlockNumber(rx)) => { + rx.send(Ok(0)).unwrap(); + } + ); + let candidate_hash = Hash::repeat_byte(0x04); + + let candidate_descriptor = make_candidate(ParaId::from(1_u32), &candidate_hash); + let candidate_hash = candidate_descriptor.hash(); + + let block_hash = Hash::repeat_byte(0x01); + let block_hash_fork = Hash::repeat_byte(0x02); + + let candidate_index = 0; + let validator = ValidatorIndex(0); + let validators = vec![ + Sr25519Keyring::Alice, + Sr25519Keyring::Bob, + Sr25519Keyring::Charlie, + Sr25519Keyring::Dave, + Sr25519Keyring::Eve, + ]; + // Add block hash 0x01 and for 0x02 + ChainBuilder::new() + .add_block( + block_hash, + ChainBuilder::GENESIS_HASH, + 1, + BlockConfig { + slot: Slot::from(1), + candidates: Some(vec![( + candidate_descriptor.clone(), + CoreIndex(0), + GroupIndex(0), + )]), + session_info: Some(SessionInfo { + validator_groups: IndexedVec::>::from( + vec![ + vec![ValidatorIndex(0), ValidatorIndex(1)], + vec![ValidatorIndex(2)], + vec![ValidatorIndex(3), ValidatorIndex(4)], + ], + ), + needed_approvals: 1, + ..session_info(&validators) + }), + end_syncing: false, + }, + ) + .add_block( + block_hash_fork, + ChainBuilder::GENESIS_HASH, + 1, + BlockConfig { + slot: Slot::from(1), + candidates: Some(vec![(candidate_descriptor, CoreIndex(0), GroupIndex(0))]), + session_info: Some(SessionInfo { + validator_groups: IndexedVec::>::from( + vec![ + vec![ValidatorIndex(0), ValidatorIndex(1)], + vec![ValidatorIndex(2)], + vec![ValidatorIndex(3), ValidatorIndex(4)], + ], + ), + needed_approvals: 1, + ..session_info(&validators) + }), + end_syncing: false, + }, + ) + .build(&mut virtual_overseer) + .await; + + // Send assignments for the same candidate on both forks + let rx = check_and_import_assignment( + &mut virtual_overseer, + block_hash, + candidate_index, + validator, + ) + .await; + assert_eq!(rx.await, Ok(AssignmentCheckResult::Accepted)); + + let rx = check_and_import_assignment( + &mut virtual_overseer, + block_hash_fork, + candidate_index, + validator, + ) + .await; + + assert_eq!(rx.await, Ok(AssignmentCheckResult::Accepted)); + // Wake on APPROVAL_DELAY first + assert!(clock.inner.lock().current_wakeup_is(2)); + clock.inner.lock().set_tick(2); + futures_timer::Delay::new(Duration::from_millis(100)).await; + + // Wake up on no-show + assert!(clock.inner.lock().current_wakeup_is(30)); + + for (tick, status) in expected_approval_status + .iter() + .filter(|(tick, _)| *tick < tick_to_send_approval) + { + // Wake up on no-show + clock.inner.lock().set_tick(*tick); + futures_timer::Delay::new(Duration::from_millis(100)).await; + let block_entry = store.load_block_entry(&block_hash).unwrap().unwrap(); + let block_entry_fork = store.load_block_entry(&block_hash_fork).unwrap().unwrap(); + assert!(!block_entry.is_fully_approved()); + assert_eq!(block_entry_fork.is_fully_approved(), *status); + } + + clock.inner.lock().set_tick(tick_to_send_approval); + futures_timer::Delay::new(Duration::from_millis(100)).await; + + // Send the approval for candidate just in the context of 0x01 block. + let rx = check_and_import_approval( + &mut virtual_overseer, + block_hash, + candidate_index, + validator, + candidate_hash, + 1, + false, + None, + ) + .await; + + assert_eq!(rx.await, Ok(ApprovalCheckResult::Accepted),); + + // Check approval status for the fork_block is correctly transitioned. + for (tick, status) in expected_approval_status + .iter() + .filter(|(tick, _)| *tick >= tick_to_send_approval) + { + // Wake up on no-show + clock.inner.lock().set_tick(*tick); + futures_timer::Delay::new(Duration::from_millis(100)).await; + let block_entry = store.load_block_entry(&block_hash).unwrap().unwrap(); + let block_entry_fork = store.load_block_entry(&block_hash_fork).unwrap().unwrap(); + assert!(block_entry.is_fully_approved()); + assert_eq!(block_entry_fork.is_fully_approved(), *status); + } + + virtual_overseer + }); +} + #[test] fn subsystem_process_wakeup_schedules_wakeup() { test_harness(HarnessConfig::default(), |test_harness| async move { diff --git a/polkadot/node/core/av-store/Cargo.toml b/polkadot/node/core/av-store/Cargo.toml index bc9b979228a1db8c4adfc01bd2d60470721bfcac..c5b3c382011b12ac80e130500d7c64b481989331 100644 --- a/polkadot/node/core/av-store/Cargo.toml +++ b/polkadot/node/core/av-store/Cargo.toml @@ -17,7 +17,7 @@ thiserror = { workspace = true } gum = { package = "tracing-gum", path = "../../gum" } bitvec = "1.0.0" -parity-scale-codec = { version = "3.6.1", features = ["derive"] } +parity-scale-codec = { version = "3.6.12", features = ["derive"] } erasure = { package = "polkadot-erasure-coding", path = "../../../erasure-coding" } polkadot-node-subsystem = { path = "../../subsystem" } polkadot-node-subsystem-util = { path = "../../subsystem-util" } diff --git a/polkadot/node/core/backing/Cargo.toml b/polkadot/node/core/backing/Cargo.toml index 26fa54470fbda6c1e5a22999a34022173b003fe6..f426f73284e8c36d7bc11eef051c8dddbbf40518 100644 --- a/polkadot/node/core/backing/Cargo.toml +++ b/polkadot/node/core/backing/Cargo.toml @@ -21,7 +21,7 @@ statement-table = { package = "polkadot-statement-table", path = "../../../state bitvec = { version = "1.0.0", default-features = false, features = ["alloc"] } gum = { package = "tracing-gum", path = "../../gum" } thiserror = { workspace = true } -fatality = "0.0.6" +fatality = "0.1.1" schnellru = "0.2.1" [dev-dependencies] diff --git a/polkadot/node/core/backing/src/lib.rs b/polkadot/node/core/backing/src/lib.rs index 23acb0450944e8eedea437da545830174ed84449..a45edcbef52a91009e670cc5bb2c6a1a5923fa9e 100644 --- a/polkadot/node/core/backing/src/lib.rs +++ b/polkadot/node/core/backing/src/lib.rs @@ -30,7 +30,7 @@ //! assigned group of validators may be backed on-chain and proceed to the availability //! stage. //! -//! Depth is a concept relating to asynchronous backing, by which validators +//! Depth is a concept relating to asynchronous backing, by which //! short sub-chains of candidates are backed and extended off-chain, and then placed //! asynchronously into blocks of the relay chain as those are authored and as the //! relay-chain state becomes ready for them. Asynchronous backing allows parachains to @@ -66,7 +66,7 @@ #![deny(unused_crate_dependencies)] use std::{ - collections::{BTreeMap, HashMap, HashSet}, + collections::{HashMap, HashSet}, sync::Arc, }; @@ -88,7 +88,7 @@ use polkadot_node_subsystem::{ messages::{ AvailabilityDistributionMessage, AvailabilityStoreMessage, CanSecondRequest, CandidateBackingMessage, CandidateValidationMessage, CollatorProtocolMessage, - HypotheticalCandidate, HypotheticalFrontierRequest, IntroduceCandidateRequest, + HypotheticalCandidate, HypotheticalMembershipRequest, IntroduceSecondedCandidateRequest, ProspectiveParachainsMessage, ProvisionableData, ProvisionerMessage, RuntimeApiMessage, RuntimeApiRequest, StatementDistributionMessage, StoreAvailableDataError, }, @@ -242,20 +242,44 @@ struct PerRelayParentState { struct PerCandidateState { persisted_validation_data: PersistedValidationData, seconded_locally: bool, - para_id: ParaId, relay_parent: Hash, } -struct ActiveLeafState { - prospective_parachains_mode: ProspectiveParachainsMode, - /// The candidates seconded at various depths under this active - /// leaf with respect to parachain id. A candidate can only be - /// seconded when its hypothetical frontier under every active leaf - /// has an empty entry in this map. - /// - /// When prospective parachains are disabled, the only depth - /// which is allowed is 0. - seconded_at_depth: HashMap>, +enum ActiveLeafState { + // If prospective-parachains is disabled, one validator may only back one candidate per + // paraid. + ProspectiveParachainsDisabled { seconded: HashSet }, + ProspectiveParachainsEnabled { max_candidate_depth: usize, allowed_ancestry_len: usize }, +} + +impl ActiveLeafState { + fn new(mode: ProspectiveParachainsMode) -> Self { + match mode { + ProspectiveParachainsMode::Disabled => + Self::ProspectiveParachainsDisabled { seconded: HashSet::new() }, + ProspectiveParachainsMode::Enabled { max_candidate_depth, allowed_ancestry_len } => + Self::ProspectiveParachainsEnabled { max_candidate_depth, allowed_ancestry_len }, + } + } + + fn add_seconded_candidate(&mut self, para_id: ParaId) { + if let Self::ProspectiveParachainsDisabled { seconded } = self { + seconded.insert(para_id); + } + } +} + +impl From<&ActiveLeafState> for ProspectiveParachainsMode { + fn from(state: &ActiveLeafState) -> Self { + match *state { + ActiveLeafState::ProspectiveParachainsDisabled { .. } => + ProspectiveParachainsMode::Disabled, + ActiveLeafState::ProspectiveParachainsEnabled { + max_candidate_depth, + allowed_ancestry_len, + } => ProspectiveParachainsMode::Enabled { max_candidate_depth, allowed_ancestry_len }, + } + } } /// The state of the subsystem. @@ -277,11 +301,11 @@ struct State { /// parachains. /// /// Relay-chain blocks which don't support prospective parachains are - /// never included in the fragment trees of active leaves which do. + /// never included in the fragment chains of active leaves which do. /// /// While it would be technically possible to support such leaves in - /// fragment trees, it only benefits the transition period when asynchronous - /// backing is being enabled and complicates code complexity. + /// fragment chains, it only benefits the transition period when asynchronous + /// backing is being enabled and complicates code. per_relay_parent: HashMap, /// State tracked for all candidates relevant to the implicit view. /// @@ -864,17 +888,9 @@ async fn handle_active_leaves_update( return Ok(()) } - state.per_leaf.insert( - leaf.hash, - ActiveLeafState { - prospective_parachains_mode: ProspectiveParachainsMode::Disabled, - // This is empty because the only allowed relay-parent and depth - // when prospective parachains are disabled is the leaf hash and 0, - // respectively. We've just learned about the leaf hash, so we cannot - // have any candidates seconded with it as a relay-parent yet. - seconded_at_depth: HashMap::new(), - }, - ); + state + .per_leaf + .insert(leaf.hash, ActiveLeafState::new(ProspectiveParachainsMode::Disabled)); (vec![leaf.hash], ProspectiveParachainsMode::Disabled) }, @@ -882,63 +898,9 @@ async fn handle_active_leaves_update( let fresh_relay_parents = state.implicit_view.known_allowed_relay_parents_under(&leaf.hash, None); - // At this point, all candidates outside of the implicit view - // have been cleaned up. For all which remain, which we've seconded, - // we ask the prospective parachains subsystem where they land in the fragment - // tree for the given active leaf. This comprises our `seconded_at_depth`. - - let remaining_seconded = state - .per_candidate - .iter() - .filter(|(_, cd)| cd.seconded_locally) - .map(|(c_hash, cd)| (*c_hash, cd.para_id)); - - // one-to-one correspondence to remaining_seconded - let mut membership_answers = FuturesOrdered::new(); - - for (candidate_hash, para_id) in remaining_seconded { - let (tx, rx) = oneshot::channel(); - membership_answers - .push_back(rx.map_ok(move |membership| (para_id, candidate_hash, membership))); - - ctx.send_message(ProspectiveParachainsMessage::GetTreeMembership( - para_id, - candidate_hash, - tx, - )) - .await; - } - - let mut seconded_at_depth = HashMap::new(); - while let Some(response) = membership_answers.next().await { - match response { - Err(oneshot::Canceled) => { - gum::warn!( - target: LOG_TARGET, - "Prospective parachains subsystem unreachable for membership request", - ); - }, - Ok((para_id, candidate_hash, membership)) => { - // This request gives membership in all fragment trees. We have some - // wasted data here, and it can be optimized if it proves - // relevant to performance. - if let Some((_, depths)) = - membership.into_iter().find(|(leaf_hash, _)| leaf_hash == &leaf.hash) - { - let para_entry: &mut BTreeMap = - seconded_at_depth.entry(para_id).or_default(); - for depth in depths { - para_entry.insert(depth, candidate_hash); - } - } - }, - } - } + let active_leaf_state = ActiveLeafState::new(prospective_parachains_mode); - state.per_leaf.insert( - leaf.hash, - ActiveLeafState { prospective_parachains_mode, seconded_at_depth }, - ); + state.per_leaf.insert(leaf.hash, active_leaf_state); let fresh_relay_parent = match fresh_relay_parents { Some(f) => f.to_vec(), @@ -981,7 +943,7 @@ async fn handle_active_leaves_update( // block itself did. leaf_mode }, - Some(l) => l.prospective_parachains_mode, + Some(l) => l.into(), }; // construct a `PerRelayParent` from the runtime API @@ -1247,20 +1209,20 @@ async fn construct_per_relay_parent_state( enum SecondingAllowed { No, - Yes(Vec<(Hash, Vec)>), + // On which leaves is seconding allowed. + Yes(Vec), } -/// Checks whether a candidate can be seconded based on its hypothetical frontiers in the fragment -/// tree and what we've already seconded in all active leaves. +/// Checks whether a candidate can be seconded based on its hypothetical membership in the fragment +/// chain. #[overseer::contextbounds(CandidateBacking, prefix = self::overseer)] async fn seconding_sanity_check( ctx: &mut Context, active_leaves: &HashMap, implicit_view: &ImplicitView, hypothetical_candidate: HypotheticalCandidate, - backed_in_path_only: bool, ) -> SecondingAllowed { - let mut membership = Vec::new(); + let mut leaves_for_seconding = Vec::new(); let mut responses = FuturesOrdered::>>::new(); let candidate_para = hypothetical_candidate.candidate_para(); @@ -1268,7 +1230,7 @@ async fn seconding_sanity_check( let candidate_hash = hypothetical_candidate.candidate_hash(); for (head, leaf_state) in active_leaves { - if leaf_state.prospective_parachains_mode.is_enabled() { + if ProspectiveParachainsMode::from(leaf_state).is_enabled() { // Check that the candidate relay parent is allowed for para, skip the // leaf otherwise. let allowed_parents_for_para = @@ -1278,40 +1240,36 @@ async fn seconding_sanity_check( } let (tx, rx) = oneshot::channel(); - ctx.send_message(ProspectiveParachainsMessage::GetHypotheticalFrontier( - HypotheticalFrontierRequest { + ctx.send_message(ProspectiveParachainsMessage::GetHypotheticalMembership( + HypotheticalMembershipRequest { candidates: vec![hypothetical_candidate.clone()], - fragment_tree_relay_parent: Some(*head), - backed_in_path_only, + fragment_chain_relay_parent: Some(*head), }, tx, )) .await; - let response = rx.map_ok(move |frontiers| { - let depths: Vec = frontiers + let response = rx.map_ok(move |candidate_memberships| { + let is_member_or_potential = candidate_memberships .into_iter() - .flat_map(|(candidate, memberships)| { - debug_assert_eq!(candidate.candidate_hash(), candidate_hash); - memberships.into_iter().flat_map(|(relay_parent, depths)| { - debug_assert_eq!(relay_parent, *head); - depths - }) + .find_map(|(candidate, leaves)| { + (candidate.candidate_hash() == candidate_hash).then_some(leaves) }) - .collect(); - (depths, head, leaf_state) + .and_then(|leaves| leaves.into_iter().find(|leaf| leaf == head)) + .is_some(); + + (is_member_or_potential, head) }); responses.push_back(response.boxed()); } else { if *head == candidate_relay_parent { - if leaf_state - .seconded_at_depth - .get(&candidate_para) - .map_or(false, |occupied| occupied.contains_key(&0)) - { - // The leaf is already occupied. - return SecondingAllowed::No + if let ActiveLeafState::ProspectiveParachainsDisabled { seconded } = leaf_state { + if seconded.contains(&candidate_para) { + // The leaf is already occupied. For non-prospective parachains, we only + // second one candidate. + return SecondingAllowed::No + } } - responses.push_back(futures::future::ok((vec![0], head, leaf_state)).boxed()); + responses.push_back(futures::future::ok((true, head)).boxed()); } } } @@ -1325,38 +1283,32 @@ async fn seconding_sanity_check( Err(oneshot::Canceled) => { gum::warn!( target: LOG_TARGET, - "Failed to reach prospective parachains subsystem for hypothetical frontiers", + "Failed to reach prospective parachains subsystem for hypothetical membership", ); return SecondingAllowed::No }, - Ok((depths, head, leaf_state)) => { - for depth in &depths { - if leaf_state - .seconded_at_depth - .get(&candidate_para) - .map_or(false, |occupied| occupied.contains_key(&depth)) - { - gum::debug!( - target: LOG_TARGET, - ?candidate_hash, - depth, - leaf_hash = ?head, - "Refusing to second candidate at depth - already occupied." - ); - - return SecondingAllowed::No - } - } - - membership.push((*head, depths)); + Ok((is_member_or_potential, head)) => match is_member_or_potential { + false => { + gum::debug!( + target: LOG_TARGET, + ?candidate_hash, + leaf_hash = ?head, + "Refusing to second candidate at leaf. Is not a potential member.", + ); + }, + true => { + leaves_for_seconding.push(*head); + }, }, } } - // At this point we've checked the depths of the candidate against all active - // leaves. - SecondingAllowed::Yes(membership) + if leaves_for_seconding.is_empty() { + SecondingAllowed::No + } else { + SecondingAllowed::Yes(leaves_for_seconding) + } } /// Performs seconding sanity check for an advertisement. @@ -1385,16 +1337,12 @@ async fn handle_can_second_request( &state.per_leaf, &state.implicit_view, hypothetical_candidate, - true, ) .await; match result { SecondingAllowed::No => false, - SecondingAllowed::Yes(membership) => { - // Candidate should be recognized by at least some fragment tree. - membership.iter().any(|(_, m)| !m.is_empty()) - }, + SecondingAllowed::Yes(leaves) => !leaves.is_empty(), } } else { // Relay parent is unknown or async backing is disabled. @@ -1435,20 +1383,6 @@ async fn handle_validated_candidate_command( commitments, }; - let parent_head_data_hash = persisted_validation_data.parent_head.hash(); - // Note that `GetHypotheticalFrontier` doesn't account for recursion, - // i.e. candidates can appear at multiple depths in the tree and in fact - // at all depths, and we don't know what depths a candidate will ultimately - // occupy because that's dependent on other candidates we haven't yet - // received. - // - // The only way to effectively rule this out is to have candidate receipts - // directly commit to the parachain block number or some other incrementing - // counter. That requires a major primitives format upgrade, so for now - // we just rule out trivial cycles. - if parent_head_data_hash == receipt.commitments.head_data.hash() { - return Ok(()) - } let hypothetical_candidate = HypotheticalCandidate::Complete { candidate_hash, receipt: Arc::new(receipt.clone()), @@ -1457,12 +1391,11 @@ async fn handle_validated_candidate_command( // sanity check that we're allowed to second the candidate // and that it doesn't conflict with other candidates we've // seconded. - let fragment_tree_membership = match seconding_sanity_check( + let hypothetical_membership = match seconding_sanity_check( ctx, &state.per_leaf, &state.implicit_view, hypothetical_candidate, - false, ) .await { @@ -1517,8 +1450,8 @@ async fn handle_validated_candidate_command( Some(p) => p.seconded_locally = true, } - // update seconded depths in active leaves. - for (leaf, depths) in fragment_tree_membership { + // record seconded candidates for non-prospective-parachains mode. + for leaf in hypothetical_membership { let leaf_data = match state.per_leaf.get_mut(&leaf) { None => { gum::warn!( @@ -1532,14 +1465,7 @@ async fn handle_validated_candidate_command( Some(d) => d, }; - let seconded_at_depth = leaf_data - .seconded_at_depth - .entry(candidate.descriptor().para_id) - .or_default(); - - for depth in depths { - seconded_at_depth.insert(depth, candidate_hash); - } + leaf_data.add_seconded_candidate(candidate.descriptor().para_id); } rp_state.issued_statements.insert(candidate_hash); @@ -1650,7 +1576,7 @@ fn sign_statement( /// and any of the following are true: /// 1. There is no `PersistedValidationData` attached. /// 2. Prospective parachains are enabled for the relay parent and the prospective parachains -/// subsystem returned an empty `FragmentTreeMembership` i.e. did not recognize the candidate as +/// subsystem returned an empty `HypotheticalMembership` i.e. did not recognize the candidate as /// being applicable to any of the active leaves. #[overseer::contextbounds(CandidateBacking, prefix = self::overseer)] async fn import_statement( @@ -1686,8 +1612,8 @@ async fn import_statement( if !per_candidate.contains_key(&candidate_hash) { if rp_state.prospective_parachains_mode.is_enabled() { let (tx, rx) = oneshot::channel(); - ctx.send_message(ProspectiveParachainsMessage::IntroduceCandidate( - IntroduceCandidateRequest { + ctx.send_message(ProspectiveParachainsMessage::IntroduceSecondedCandidate( + IntroduceSecondedCandidateRequest { candidate_para: candidate.descriptor().para_id, candidate_receipt: candidate.clone(), persisted_validation_data: pvd.clone(), @@ -1705,17 +1631,9 @@ async fn import_statement( return Err(Error::RejectedByProspectiveParachains) }, - Ok(membership) => - if membership.is_empty() { - return Err(Error::RejectedByProspectiveParachains) - }, + Ok(false) => return Err(Error::RejectedByProspectiveParachains), + Ok(true) => {}, } - - ctx.send_message(ProspectiveParachainsMessage::CandidateSeconded( - candidate.descriptor().para_id, - candidate_hash, - )) - .await; } // Only save the candidate if it was approved by prospective parachains. @@ -1725,7 +1643,6 @@ async fn import_statement( persisted_validation_data: pvd.clone(), // This is set after importing when seconding locally. seconded_locally: false, - para_id: candidate.descriptor().para_id, relay_parent: candidate.descriptor().relay_parent, }, ); @@ -1786,13 +1703,6 @@ async fn post_import_statement_actions( candidate_hash, )) .await; - // Backed candidate potentially unblocks new advertisements, - // notify collator protocol. - ctx.send_message(CollatorProtocolMessage::Backed { - para_id, - para_head: backed.candidate().descriptor.para_head, - }) - .await; // Notify statement distribution of backed candidate. ctx.send_message(StatementDistributionMessage::Backed(candidate_hash)).await; } else { @@ -2016,7 +1926,7 @@ async fn maybe_validate_and_import( if let Some(summary) = summary { // import_statement already takes care of communicating with the // prospective parachains subsystem. At this point, the candidate - // has already been accepted into the fragment trees. + // has already been accepted by the subsystem. let candidate_hash = summary.candidate; diff --git a/polkadot/node/core/backing/src/tests/prospective_parachains.rs b/polkadot/node/core/backing/src/tests/prospective_parachains.rs index 94310d2aa164650db84b78ddf361a9f465ac207d..8a72902f0815030bf2d5d13d3f04fdb1763254aa 100644 --- a/polkadot/node/core/backing/src/tests/prospective_parachains.rs +++ b/polkadot/node/core/backing/src/tests/prospective_parachains.rs @@ -17,7 +17,7 @@ //! Tests for the backing subsystem with enabled prospective parachains. use polkadot_node_subsystem::{ - messages::{ChainApiMessage, FragmentTreeMembership}, + messages::{ChainApiMessage, HypotheticalMembership}, ActivatedLeaf, TimeoutExt, }; use polkadot_primitives::{AsyncBackingParams, BlockNumber, Header, OccupiedCore}; @@ -40,7 +40,6 @@ async fn activate_leaf( virtual_overseer: &mut VirtualOverseer, leaf: TestLeaf, test_state: &TestState, - seconded_in_view: usize, ) { let TestLeaf { activated, min_relay_parents } = leaf; let leaf_hash = activated.hash; @@ -122,21 +121,6 @@ async fn activate_leaf( } } - for _ in 0..seconded_in_view { - let msg = match next_overseer_message.take() { - Some(msg) => msg, - None => virtual_overseer.recv().await, - }; - assert_matches!( - msg, - AllMessages::ProspectiveParachains( - ProspectiveParachainsMessage::GetTreeMembership(.., tx), - ) => { - tx.send(Vec::new()).unwrap(); - } - ); - } - for (hash, number) in ancestry_iter.take(requested_len) { let msg = match next_overseer_message.take() { Some(msg) => msg, @@ -297,11 +281,11 @@ async fn assert_validate_seconded_candidate( ); } -async fn assert_hypothetical_frontier_requests( +async fn assert_hypothetical_membership_requests( virtual_overseer: &mut VirtualOverseer, mut expected_requests: Vec<( - HypotheticalFrontierRequest, - Vec<(HypotheticalCandidate, FragmentTreeMembership)>, + HypotheticalMembershipRequest, + Vec<(HypotheticalCandidate, HypotheticalMembership)>, )>, ) { // Requests come with no particular order. @@ -311,13 +295,13 @@ async fn assert_hypothetical_frontier_requests( assert_matches!( virtual_overseer.recv().await, AllMessages::ProspectiveParachains( - ProspectiveParachainsMessage::GetHypotheticalFrontier(request, tx), + ProspectiveParachainsMessage::GetHypotheticalMembership(request, tx), ) => { let idx = match expected_requests.iter().position(|r| r.0 == request) { Some(idx) => idx, None => panic!( - "unexpected hypothetical frontier request, no match found for {:?}", + "unexpected hypothetical membership request, no match found for {:?}", request ), }; @@ -330,18 +314,17 @@ async fn assert_hypothetical_frontier_requests( } } -fn make_hypothetical_frontier_response( - depths: Vec, +fn make_hypothetical_membership_response( hypothetical_candidate: HypotheticalCandidate, relay_parent_hash: Hash, -) -> Vec<(HypotheticalCandidate, FragmentTreeMembership)> { - vec![(hypothetical_candidate, vec![(relay_parent_hash, depths)])] +) -> Vec<(HypotheticalCandidate, HypotheticalMembership)> { + vec![(hypothetical_candidate, vec![relay_parent_hash])] } // Test that `seconding_sanity_check` works when a candidate is allowed // for all leaves. #[test] -fn seconding_sanity_check_allowed() { +fn seconding_sanity_check_allowed_on_all() { let test_state = TestState::default(); test_harness(test_state.keystore.clone(), |mut virtual_overseer| async move { // Candidate is seconded in a parent of the activated `leaf_a`. @@ -364,8 +347,8 @@ fn seconding_sanity_check_allowed() { let min_relay_parents = vec![(para_id, LEAF_B_BLOCK_NUMBER - LEAF_B_ANCESTRY_LEN)]; let test_leaf_b = TestLeaf { activated, min_relay_parents }; - activate_leaf(&mut virtual_overseer, test_leaf_a, &test_state, 0).await; - activate_leaf(&mut virtual_overseer, test_leaf_b, &test_state, 0).await; + activate_leaf(&mut virtual_overseer, test_leaf_a, &test_state).await; + activate_leaf(&mut virtual_overseer, test_leaf_b, &test_state).await; let pov = PoV { block_data: BlockData(vec![42, 43, 44]) }; let pvd = dummy_pvd(); @@ -412,24 +395,19 @@ fn seconding_sanity_check_allowed() { receipt: Arc::new(candidate.clone()), persisted_validation_data: pvd.clone(), }; - let expected_request_a = HypotheticalFrontierRequest { + let expected_request_a = HypotheticalMembershipRequest { candidates: vec![hypothetical_candidate.clone()], - fragment_tree_relay_parent: Some(leaf_a_hash), - backed_in_path_only: false, + fragment_chain_relay_parent: Some(leaf_a_hash), }; - let expected_response_a = make_hypothetical_frontier_response( - vec![0, 1, 2, 3], - hypothetical_candidate.clone(), - leaf_a_hash, - ); - let expected_request_b = HypotheticalFrontierRequest { + let expected_response_a = + make_hypothetical_membership_response(hypothetical_candidate.clone(), leaf_a_hash); + let expected_request_b = HypotheticalMembershipRequest { candidates: vec![hypothetical_candidate.clone()], - fragment_tree_relay_parent: Some(leaf_b_hash), - backed_in_path_only: false, + fragment_chain_relay_parent: Some(leaf_b_hash), }; let expected_response_b = - make_hypothetical_frontier_response(vec![3], hypothetical_candidate, leaf_b_hash); - assert_hypothetical_frontier_requests( + make_hypothetical_membership_response(hypothetical_candidate, leaf_b_hash); + assert_hypothetical_membership_requests( &mut virtual_overseer, vec![ (expected_request_a, expected_response_a), @@ -441,7 +419,7 @@ fn seconding_sanity_check_allowed() { assert_matches!( virtual_overseer.recv().await, AllMessages::ProspectiveParachains( - ProspectiveParachainsMessage::IntroduceCandidate( + ProspectiveParachainsMessage::IntroduceSecondedCandidate( req, tx, ), @@ -449,19 +427,10 @@ fn seconding_sanity_check_allowed() { req.candidate_receipt == candidate && req.candidate_para == para_id && pvd == req.persisted_validation_data => { - // Any non-empty response will do. - tx.send(vec![(leaf_a_hash, vec![0, 1, 2, 3])]).unwrap(); + tx.send(true).unwrap(); } ); - assert_matches!( - virtual_overseer.recv().await, - AllMessages::ProspectiveParachains(ProspectiveParachainsMessage::CandidateSeconded( - _, - _ - )) - ); - assert_matches!( virtual_overseer.recv().await, AllMessages::StatementDistribution( @@ -484,8 +453,8 @@ fn seconding_sanity_check_allowed() { }); } -// Test that `seconding_sanity_check` works when a candidate is disallowed -// for at least one leaf. +// Test that `seconding_sanity_check` disallows seconding when a candidate is disallowed +// for all leaves. #[test] fn seconding_sanity_check_disallowed() { let test_state = TestState::default(); @@ -510,7 +479,7 @@ fn seconding_sanity_check_disallowed() { let min_relay_parents = vec![(para_id, LEAF_B_BLOCK_NUMBER - LEAF_B_ANCESTRY_LEN)]; let test_leaf_b = TestLeaf { activated, min_relay_parents }; - activate_leaf(&mut virtual_overseer, test_leaf_a, &test_state, 0).await; + activate_leaf(&mut virtual_overseer, test_leaf_a, &test_state).await; let pov = PoV { block_data: BlockData(vec![42, 43, 44]) }; let pvd = dummy_pvd(); @@ -557,17 +526,13 @@ fn seconding_sanity_check_disallowed() { receipt: Arc::new(candidate.clone()), persisted_validation_data: pvd.clone(), }; - let expected_request_a = HypotheticalFrontierRequest { + let expected_request_a = HypotheticalMembershipRequest { candidates: vec![hypothetical_candidate.clone()], - fragment_tree_relay_parent: Some(leaf_a_hash), - backed_in_path_only: false, + fragment_chain_relay_parent: Some(leaf_a_hash), }; - let expected_response_a = make_hypothetical_frontier_response( - vec![0, 1, 2, 3], - hypothetical_candidate, - leaf_a_hash, - ); - assert_hypothetical_frontier_requests( + let expected_response_a = + make_hypothetical_membership_response(hypothetical_candidate, leaf_a_hash); + assert_hypothetical_membership_requests( &mut virtual_overseer, vec![(expected_request_a, expected_response_a)], ) @@ -576,7 +541,7 @@ fn seconding_sanity_check_disallowed() { assert_matches!( virtual_overseer.recv().await, AllMessages::ProspectiveParachains( - ProspectiveParachainsMessage::IntroduceCandidate( + ProspectiveParachainsMessage::IntroduceSecondedCandidate( req, tx, ), @@ -584,19 +549,10 @@ fn seconding_sanity_check_disallowed() { req.candidate_receipt == candidate && req.candidate_para == para_id && pvd == req.persisted_validation_data => { - // Any non-empty response will do. - tx.send(vec![(leaf_a_hash, vec![0, 2, 3])]).unwrap(); + tx.send(true).unwrap(); } ); - assert_matches!( - virtual_overseer.recv().await, - AllMessages::ProspectiveParachains(ProspectiveParachainsMessage::CandidateSeconded( - _, - _ - )) - ); - assert_matches!( virtual_overseer.recv().await, AllMessages::StatementDistribution( @@ -615,10 +571,7 @@ fn seconding_sanity_check_disallowed() { } ); - // A seconded candidate occupies a depth, try to second another one. - // It is allowed in a new leaf but not allowed in the old one. - // Expect it to be rejected. - activate_leaf(&mut virtual_overseer, test_leaf_b, &test_state, 1).await; + activate_leaf(&mut virtual_overseer, test_leaf_b, &test_state).await; let leaf_a_grandparent = get_parent_hash(leaf_a_parent); let candidate = TestCandidateBuilder { para_id, @@ -659,28 +612,20 @@ fn seconding_sanity_check_disallowed() { receipt: Arc::new(candidate), persisted_validation_data: pvd, }; - let expected_request_a = HypotheticalFrontierRequest { + let expected_request_a = HypotheticalMembershipRequest { candidates: vec![hypothetical_candidate.clone()], - fragment_tree_relay_parent: Some(leaf_a_hash), - backed_in_path_only: false, + fragment_chain_relay_parent: Some(leaf_a_hash), }; - let expected_response_a = make_hypothetical_frontier_response( - vec![3], - hypothetical_candidate.clone(), - leaf_a_hash, - ); - let expected_request_b = HypotheticalFrontierRequest { + let expected_empty_response = vec![(hypothetical_candidate.clone(), vec![])]; + let expected_request_b = HypotheticalMembershipRequest { candidates: vec![hypothetical_candidate.clone()], - fragment_tree_relay_parent: Some(leaf_b_hash), - backed_in_path_only: false, + fragment_chain_relay_parent: Some(leaf_b_hash), }; - let expected_response_b = - make_hypothetical_frontier_response(vec![1], hypothetical_candidate, leaf_b_hash); - assert_hypothetical_frontier_requests( + assert_hypothetical_membership_requests( &mut virtual_overseer, vec![ - (expected_request_a, expected_response_a), // All depths are occupied. - (expected_request_b, expected_response_b), + (expected_request_a, expected_empty_response.clone()), + (expected_request_b, expected_empty_response), ], ) .await; @@ -695,6 +640,137 @@ fn seconding_sanity_check_disallowed() { }); } +// Test that `seconding_sanity_check` allows seconding a candidate when it's allowed on at least one +// leaf. +#[test] +fn seconding_sanity_check_allowed_on_at_least_one_leaf() { + let test_state = TestState::default(); + test_harness(test_state.keystore.clone(), |mut virtual_overseer| async move { + // Candidate is seconded in a parent of the activated `leaf_a`. + const LEAF_A_BLOCK_NUMBER: BlockNumber = 100; + const LEAF_A_ANCESTRY_LEN: BlockNumber = 3; + let para_id = test_state.chain_ids[0]; + + // `a` is grandparent of `b`. + let leaf_a_hash = Hash::from_low_u64_be(130); + let leaf_a_parent = get_parent_hash(leaf_a_hash); + let activated = new_leaf(leaf_a_hash, LEAF_A_BLOCK_NUMBER); + let min_relay_parents = vec![(para_id, LEAF_A_BLOCK_NUMBER - LEAF_A_ANCESTRY_LEN)]; + let test_leaf_a = TestLeaf { activated, min_relay_parents }; + + const LEAF_B_BLOCK_NUMBER: BlockNumber = LEAF_A_BLOCK_NUMBER + 2; + const LEAF_B_ANCESTRY_LEN: BlockNumber = 4; + + let leaf_b_hash = Hash::from_low_u64_be(128); + let activated = new_leaf(leaf_b_hash, LEAF_B_BLOCK_NUMBER); + let min_relay_parents = vec![(para_id, LEAF_B_BLOCK_NUMBER - LEAF_B_ANCESTRY_LEN)]; + let test_leaf_b = TestLeaf { activated, min_relay_parents }; + + activate_leaf(&mut virtual_overseer, test_leaf_a, &test_state).await; + activate_leaf(&mut virtual_overseer, test_leaf_b, &test_state).await; + + let pov = PoV { block_data: BlockData(vec![42, 43, 44]) }; + let pvd = dummy_pvd(); + let validation_code = ValidationCode(vec![1, 2, 3]); + + let expected_head_data = test_state.head_data.get(¶_id).unwrap(); + + let pov_hash = pov.hash(); + let candidate = TestCandidateBuilder { + para_id, + relay_parent: leaf_a_parent, + pov_hash, + head_data: expected_head_data.clone(), + erasure_root: make_erasure_root(&test_state, pov.clone(), pvd.clone()), + persisted_validation_data_hash: pvd.hash(), + validation_code: validation_code.0.clone(), + } + .build(); + + let second = CandidateBackingMessage::Second( + leaf_a_hash, + candidate.to_plain(), + pvd.clone(), + pov.clone(), + ); + + virtual_overseer.send(FromOrchestra::Communication { msg: second }).await; + + assert_validate_seconded_candidate( + &mut virtual_overseer, + leaf_a_parent, + &candidate, + &pov, + &pvd, + &validation_code, + expected_head_data, + false, + ) + .await; + + // `seconding_sanity_check` + let hypothetical_candidate = HypotheticalCandidate::Complete { + candidate_hash: candidate.hash(), + receipt: Arc::new(candidate.clone()), + persisted_validation_data: pvd.clone(), + }; + let expected_request_a = HypotheticalMembershipRequest { + candidates: vec![hypothetical_candidate.clone()], + fragment_chain_relay_parent: Some(leaf_a_hash), + }; + let expected_response_a = + make_hypothetical_membership_response(hypothetical_candidate.clone(), leaf_a_hash); + let expected_request_b = HypotheticalMembershipRequest { + candidates: vec![hypothetical_candidate.clone()], + fragment_chain_relay_parent: Some(leaf_b_hash), + }; + let expected_response_b = vec![(hypothetical_candidate.clone(), vec![])]; + assert_hypothetical_membership_requests( + &mut virtual_overseer, + vec![ + (expected_request_a, expected_response_a), + (expected_request_b, expected_response_b), + ], + ) + .await; + // Prospective parachains are notified. + assert_matches!( + virtual_overseer.recv().await, + AllMessages::ProspectiveParachains( + ProspectiveParachainsMessage::IntroduceSecondedCandidate( + req, + tx, + ), + ) if + req.candidate_receipt == candidate + && req.candidate_para == para_id + && pvd == req.persisted_validation_data => { + tx.send(true).unwrap(); + } + ); + + assert_matches!( + virtual_overseer.recv().await, + AllMessages::StatementDistribution( + StatementDistributionMessage::Share( + parent_hash, + _signed_statement, + ) + ) if parent_hash == leaf_a_parent => {} + ); + + assert_matches!( + virtual_overseer.recv().await, + AllMessages::CollatorProtocol(CollatorProtocolMessage::Seconded(hash, statement)) => { + assert_eq!(leaf_a_parent, hash); + assert_matches!(statement.payload(), Statement::Seconded(_)); + } + ); + + virtual_overseer + }); +} + // Test that a seconded candidate which is not approved by prospective parachains // subsystem doesn't change the view. #[test] @@ -712,7 +788,7 @@ fn prospective_parachains_reject_candidate() { let min_relay_parents = vec![(para_id, LEAF_A_BLOCK_NUMBER - LEAF_A_ANCESTRY_LEN)]; let test_leaf_a = TestLeaf { activated, min_relay_parents }; - activate_leaf(&mut virtual_overseer, test_leaf_a, &test_state, 0).await; + activate_leaf(&mut virtual_overseer, test_leaf_a, &test_state).await; let pov = PoV { block_data: BlockData(vec![42, 43, 44]) }; let pvd = dummy_pvd(); @@ -760,25 +836,20 @@ fn prospective_parachains_reject_candidate() { persisted_validation_data: pvd.clone(), }; let expected_request_a = vec![( - HypotheticalFrontierRequest { + HypotheticalMembershipRequest { candidates: vec![hypothetical_candidate.clone()], - fragment_tree_relay_parent: Some(leaf_a_hash), - backed_in_path_only: false, + fragment_chain_relay_parent: Some(leaf_a_hash), }, - make_hypothetical_frontier_response( - vec![0, 1, 2, 3], - hypothetical_candidate, - leaf_a_hash, - ), + make_hypothetical_membership_response(hypothetical_candidate, leaf_a_hash), )]; - assert_hypothetical_frontier_requests(&mut virtual_overseer, expected_request_a.clone()) + assert_hypothetical_membership_requests(&mut virtual_overseer, expected_request_a.clone()) .await; // Prospective parachains are notified. assert_matches!( virtual_overseer.recv().await, AllMessages::ProspectiveParachains( - ProspectiveParachainsMessage::IntroduceCandidate( + ProspectiveParachainsMessage::IntroduceSecondedCandidate( req, tx, ), @@ -787,7 +858,7 @@ fn prospective_parachains_reject_candidate() { && req.candidate_para == para_id && pvd == req.persisted_validation_data => { // Reject it. - tx.send(Vec::new()).unwrap(); + tx.send(false).unwrap(); } ); @@ -825,12 +896,12 @@ fn prospective_parachains_reject_candidate() { .await; // `seconding_sanity_check` - assert_hypothetical_frontier_requests(&mut virtual_overseer, expected_request_a).await; + assert_hypothetical_membership_requests(&mut virtual_overseer, expected_request_a).await; // Prospective parachains are notified. assert_matches!( virtual_overseer.recv().await, AllMessages::ProspectiveParachains( - ProspectiveParachainsMessage::IntroduceCandidate( + ProspectiveParachainsMessage::IntroduceSecondedCandidate( req, tx, ), @@ -838,19 +909,10 @@ fn prospective_parachains_reject_candidate() { req.candidate_receipt == candidate && req.candidate_para == para_id && pvd == req.persisted_validation_data => { - // Any non-empty response will do. - tx.send(vec![(leaf_a_hash, vec![0, 2, 3])]).unwrap(); + tx.send(true).unwrap(); } ); - assert_matches!( - virtual_overseer.recv().await, - AllMessages::ProspectiveParachains(ProspectiveParachainsMessage::CandidateSeconded( - _, - _ - )) - ); - assert_matches!( virtual_overseer.recv().await, AllMessages::StatementDistribution( @@ -890,7 +952,7 @@ fn second_multiple_candidates_per_relay_parent() { let min_relay_parents = vec![(para_id, LEAF_BLOCK_NUMBER - LEAF_ANCESTRY_LEN)]; let test_leaf_a = TestLeaf { activated, min_relay_parents }; - activate_leaf(&mut virtual_overseer, test_leaf_a, &test_state, 0).await; + activate_leaf(&mut virtual_overseer, test_leaf_a, &test_state).await; let pov = PoV { block_data: BlockData(vec![42, 43, 44]) }; let pvd = dummy_pvd(); @@ -911,12 +973,10 @@ fn second_multiple_candidates_per_relay_parent() { let mut candidate_b = candidate_a.clone(); candidate_b.relay_parent = leaf_grandparent; - // With depths. - let candidate_a = (candidate_a.build(), 1); - let candidate_b = (candidate_b.build(), 2); + let candidate_a = candidate_a.build(); + let candidate_b = candidate_b.build(); for candidate in &[candidate_a, candidate_b] { - let (candidate, depth) = candidate; let second = CandidateBackingMessage::Second( leaf_hash, candidate.to_plain(), @@ -945,46 +1005,33 @@ fn second_multiple_candidates_per_relay_parent() { persisted_validation_data: pvd.clone(), }; let expected_request_a = vec![( - HypotheticalFrontierRequest { + HypotheticalMembershipRequest { candidates: vec![hypothetical_candidate.clone()], - fragment_tree_relay_parent: Some(leaf_hash), - backed_in_path_only: false, + fragment_chain_relay_parent: Some(leaf_hash), }, - make_hypothetical_frontier_response( - vec![*depth], - hypothetical_candidate, - leaf_hash, - ), + make_hypothetical_membership_response(hypothetical_candidate, leaf_hash), )]; - assert_hypothetical_frontier_requests( + assert_hypothetical_membership_requests( &mut virtual_overseer, expected_request_a.clone(), ) .await; // Prospective parachains are notified. - assert_matches!( - virtual_overseer.recv().await, - AllMessages::ProspectiveParachains( - ProspectiveParachainsMessage::IntroduceCandidate( - req, - tx, - ), - ) if - &req.candidate_receipt == candidate - && req.candidate_para == para_id - && pvd == req.persisted_validation_data - => { - // Any non-empty response will do. - tx.send(vec![(leaf_hash, vec![0, 2, 3])]).unwrap(); - } - ); - assert_matches!( virtual_overseer.recv().await, AllMessages::ProspectiveParachains( - ProspectiveParachainsMessage::CandidateSeconded(_, _) - ) + ProspectiveParachainsMessage::IntroduceSecondedCandidate( + req, + tx, + ), + ) if + &req.candidate_receipt == candidate + && req.candidate_para == para_id + && pvd == req.persisted_validation_data + => { + tx.send(true).unwrap(); + } ); assert_matches!( @@ -1026,7 +1073,7 @@ fn backing_works() { let min_relay_parents = vec![(para_id, LEAF_BLOCK_NUMBER - LEAF_ANCESTRY_LEN)]; let test_leaf_a = TestLeaf { activated, min_relay_parents }; - activate_leaf(&mut virtual_overseer, test_leaf_a, &test_state, 0).await; + activate_leaf(&mut virtual_overseer, test_leaf_a, &test_state).await; let pov = PoV { block_data: BlockData(vec![42, 43, 44]) }; let pvd = dummy_pvd(); @@ -1048,7 +1095,6 @@ fn backing_works() { .build(); let candidate_a_hash = candidate_a.hash(); - let candidate_a_para_head = candidate_a.descriptor().para_head; let public1 = Keystore::sr25519_generate_new( &*test_state.keystore, @@ -1096,7 +1142,7 @@ fn backing_works() { assert_matches!( virtual_overseer.recv().await, AllMessages::ProspectiveParachains( - ProspectiveParachainsMessage::IntroduceCandidate( + ProspectiveParachainsMessage::IntroduceSecondedCandidate( req, tx, ), @@ -1104,19 +1150,10 @@ fn backing_works() { req.candidate_receipt == candidate_a && req.candidate_para == para_id && pvd == req.persisted_validation_data => { - // Any non-empty response will do. - tx.send(vec![(leaf_hash, vec![0, 2, 3])]).unwrap(); + tx.send(true).unwrap(); } ); - assert_matches!( - virtual_overseer.recv().await, - AllMessages::ProspectiveParachains(ProspectiveParachainsMessage::CandidateSeconded( - _, - _ - )) - ); - assert_validate_seconded_candidate( &mut virtual_overseer, candidate_a.descriptor().relay_parent, @@ -1147,13 +1184,6 @@ fn backing_works() { ), ) if candidate_a_hash == candidate_hash && candidate_para_id == para_id ); - assert_matches!( - virtual_overseer.recv().await, - AllMessages::CollatorProtocol(CollatorProtocolMessage::Backed { - para_id: _para_id, - para_head, - }) if para_id == _para_id && candidate_a_para_head == para_head - ); assert_matches!( virtual_overseer.recv().await, AllMessages::StatementDistribution(StatementDistributionMessage::Backed ( @@ -1187,7 +1217,7 @@ fn concurrent_dependent_candidates() { let min_relay_parents = vec![(para_id, LEAF_BLOCK_NUMBER - LEAF_ANCESTRY_LEN)]; let test_leaf_a = TestLeaf { activated, min_relay_parents }; - activate_leaf(&mut virtual_overseer, test_leaf_a, &test_state, 0).await; + activate_leaf(&mut virtual_overseer, test_leaf_a, &test_state).await; let head_data = &[ HeadData(vec![10, 20, 30]), // Before `a`. @@ -1299,13 +1329,10 @@ fn concurrent_dependent_candidates() { // Order is not guaranteed since we have 2 statements being handled concurrently. match msg { AllMessages::ProspectiveParachains( - ProspectiveParachainsMessage::IntroduceCandidate(_, tx), + ProspectiveParachainsMessage::IntroduceSecondedCandidate(_, tx), ) => { - tx.send(vec![(leaf_hash, vec![0, 2, 3])]).unwrap(); + tx.send(true).unwrap(); }, - AllMessages::ProspectiveParachains( - ProspectiveParachainsMessage::CandidateSeconded(_, _), - ) => {}, AllMessages::RuntimeApi(RuntimeApiMessage::Request( _, RuntimeApiRequest::ValidationCodeByHash(_, tx), @@ -1362,7 +1389,6 @@ fn concurrent_dependent_candidates() { AllMessages::ProspectiveParachains( ProspectiveParachainsMessage::CandidateBacked(..), ) => {}, - AllMessages::CollatorProtocol(CollatorProtocolMessage::Backed { .. }) => {}, AllMessages::StatementDistribution(StatementDistributionMessage::Share( _, statement, @@ -1447,7 +1473,7 @@ fn seconding_sanity_check_occupy_same_depth() { let min_relay_parents = vec![(para_id_a, min_block_number), (para_id_b, min_block_number)]; let test_leaf_a = TestLeaf { activated, min_relay_parents }; - activate_leaf(&mut virtual_overseer, test_leaf_a, &test_state, 0).await; + activate_leaf(&mut virtual_overseer, test_leaf_a, &test_state).await; let pov = PoV { block_data: BlockData(vec![42, 43, 44]) }; let pvd = dummy_pvd(); @@ -1506,44 +1532,35 @@ fn seconding_sanity_check_occupy_same_depth() { persisted_validation_data: pvd.clone(), }; let expected_request_a = vec![( - HypotheticalFrontierRequest { + HypotheticalMembershipRequest { candidates: vec![hypothetical_candidate.clone()], - fragment_tree_relay_parent: Some(leaf_hash), - backed_in_path_only: false, + fragment_chain_relay_parent: Some(leaf_hash), }, // Send the same membership for both candidates. - make_hypothetical_frontier_response(vec![0, 1], hypothetical_candidate, leaf_hash), + make_hypothetical_membership_response(hypothetical_candidate, leaf_hash), )]; - assert_hypothetical_frontier_requests( + assert_hypothetical_membership_requests( &mut virtual_overseer, expected_request_a.clone(), ) .await; // Prospective parachains are notified. - assert_matches!( - virtual_overseer.recv().await, - AllMessages::ProspectiveParachains( - ProspectiveParachainsMessage::IntroduceCandidate( - req, - tx, - ), - ) if - &req.candidate_receipt == candidate - && &req.candidate_para == para_id - && pvd == req.persisted_validation_data - => { - // Any non-empty response will do. - tx.send(vec![(leaf_hash, vec![0, 2, 3])]).unwrap(); - } - ); - assert_matches!( virtual_overseer.recv().await, AllMessages::ProspectiveParachains( - ProspectiveParachainsMessage::CandidateSeconded(_, _) - ) + ProspectiveParachainsMessage::IntroduceSecondedCandidate( + req, + tx, + ), + ) if + &req.candidate_receipt == candidate + && &req.candidate_para == para_id + && pvd == req.persisted_validation_data + => { + tx.send(true).unwrap(); + } ); assert_matches!( @@ -1600,7 +1617,7 @@ fn occupied_core_assignment() { let min_relay_parents = vec![(para_id, LEAF_A_BLOCK_NUMBER - LEAF_A_ANCESTRY_LEN)]; let test_leaf_a = TestLeaf { activated, min_relay_parents }; - activate_leaf(&mut virtual_overseer, test_leaf_a, &test_state, 0).await; + activate_leaf(&mut virtual_overseer, test_leaf_a, &test_state).await; let pov = PoV { block_data: BlockData(vec![42, 43, 44]) }; let pvd = dummy_pvd(); @@ -1648,23 +1665,18 @@ fn occupied_core_assignment() { persisted_validation_data: pvd.clone(), }; let expected_request = vec![( - HypotheticalFrontierRequest { + HypotheticalMembershipRequest { candidates: vec![hypothetical_candidate.clone()], - fragment_tree_relay_parent: Some(leaf_a_hash), - backed_in_path_only: false, + fragment_chain_relay_parent: Some(leaf_a_hash), }, - make_hypothetical_frontier_response( - vec![0, 1, 2, 3], - hypothetical_candidate, - leaf_a_hash, - ), + make_hypothetical_membership_response(hypothetical_candidate, leaf_a_hash), )]; - assert_hypothetical_frontier_requests(&mut virtual_overseer, expected_request).await; + assert_hypothetical_membership_requests(&mut virtual_overseer, expected_request).await; // Prospective parachains are notified. assert_matches!( virtual_overseer.recv().await, AllMessages::ProspectiveParachains( - ProspectiveParachainsMessage::IntroduceCandidate( + ProspectiveParachainsMessage::IntroduceSecondedCandidate( req, tx, ), @@ -1673,19 +1685,10 @@ fn occupied_core_assignment() { && req.candidate_para == para_id && pvd == req.persisted_validation_data => { - // Any non-empty response will do. - tx.send(vec![(leaf_a_hash, vec![0, 1, 2, 3])]).unwrap(); + tx.send(true).unwrap(); } ); - assert_matches!( - virtual_overseer.recv().await, - AllMessages::ProspectiveParachains(ProspectiveParachainsMessage::CandidateSeconded( - _, - _ - )) - ); - assert_matches!( virtual_overseer.recv().await, AllMessages::StatementDistribution( diff --git a/polkadot/node/core/bitfield-signing/src/lib.rs b/polkadot/node/core/bitfield-signing/src/lib.rs index 0fc0bb3d27887d1257b3473d4ff2b80aff8db42d..89851c4a033b58428fa8eac366aafcd5f7144140 100644 --- a/polkadot/node/core/bitfield-signing/src/lib.rs +++ b/polkadot/node/core/bitfield-signing/src/lib.rs @@ -38,7 +38,7 @@ use polkadot_node_subsystem::{ use polkadot_node_subsystem_util::{self as util, Validator}; use polkadot_primitives::{AvailabilityBitfield, CoreState, Hash, ValidatorIndex}; use sp_keystore::{Error as KeystoreError, KeystorePtr}; -use std::{collections::HashMap, iter::FromIterator, time::Duration}; +use std::{collections::HashMap, time::Duration}; use wasm_timer::{Delay, Instant}; mod metrics; diff --git a/polkadot/node/core/candidate-validation/Cargo.toml b/polkadot/node/core/candidate-validation/Cargo.toml index 0cf4707aad29b3931cab7d65005799cf58c8c38e..e79b3a734b8f6ed1f0d18c92a0697a8a5ba2e255 100644 --- a/polkadot/node/core/candidate-validation/Cargo.toml +++ b/polkadot/node/core/candidate-validation/Cargo.toml @@ -16,7 +16,7 @@ futures-timer = "3.0.2" gum = { package = "tracing-gum", path = "../../gum" } sp-maybe-compressed-blob = { package = "sp-maybe-compressed-blob", path = "../../../../substrate/primitives/maybe-compressed-blob" } -parity-scale-codec = { version = "3.6.1", default-features = false, features = ["bit-vec", "derive"] } +parity-scale-codec = { version = "3.6.12", default-features = false, features = ["bit-vec", "derive"] } polkadot-primitives = { path = "../../../primitives" } polkadot-parachain-primitives = { path = "../../../parachain" } diff --git a/polkadot/node/core/candidate-validation/src/lib.rs b/polkadot/node/core/candidate-validation/src/lib.rs index ec24434db24c30713e106b99b3238f997ba4765f..08881dad1961f4beb4249c632f3a82c8f86cc68c 100644 --- a/polkadot/node/core/candidate-validation/src/lib.rs +++ b/polkadot/node/core/candidate-validation/src/lib.rs @@ -100,6 +100,13 @@ pub struct Config { pub prep_worker_path: PathBuf, /// Path to the execution worker binary pub exec_worker_path: PathBuf, + /// The maximum number of pvf execution workers. + pub pvf_execute_workers_max_num: usize, + /// The maximum number of pvf workers that can be spawned in the pvf prepare pool for tasks + /// with the priority below critical. + pub pvf_prepare_workers_soft_max_num: usize, + /// The absolute number of pvf workers that can be spawned in the pvf prepare pool. + pub pvf_prepare_workers_hard_max_num: usize, } /// The candidate validation subsystem. @@ -224,6 +231,9 @@ async fn run( secure_validator_mode, prep_worker_path, exec_worker_path, + pvf_execute_workers_max_num, + pvf_prepare_workers_soft_max_num, + pvf_prepare_workers_hard_max_num, }: Config, ) -> SubsystemResult<()> { let (validation_host, task) = polkadot_node_core_pvf::start( @@ -233,6 +243,9 @@ async fn run( secure_validator_mode, prep_worker_path, exec_worker_path, + pvf_execute_workers_max_num, + pvf_prepare_workers_soft_max_num, + pvf_prepare_workers_hard_max_num, ), pvf_metrics, ) @@ -657,7 +670,14 @@ async fn validate_candidate_exhaustive( PrepareJobKind::Compilation, ); - validation_backend.validate_candidate(pvf, exec_timeout, params.encode()).await + validation_backend + .validate_candidate( + pvf, + exec_timeout, + params.encode(), + polkadot_node_core_pvf::Priority::Normal, + ) + .await }, PvfExecKind::Approval => validation_backend @@ -667,6 +687,7 @@ async fn validate_candidate_exhaustive( params, executor_params, PVF_APPROVAL_EXECUTION_RETRY_DELAY, + polkadot_node_core_pvf::Priority::Critical, ) .await, }; @@ -749,10 +770,15 @@ trait ValidationBackend { pvf: PvfPrepData, exec_timeout: Duration, encoded_params: Vec, + // The priority for the preparation job. + prepare_priority: polkadot_node_core_pvf::Priority, ) -> Result; - /// Tries executing a PVF for the approval subsystem. Will retry once if an error is encountered - /// that may have been transient. + /// Tries executing a PVF. Will retry once if an error is encountered that may have + /// been transient. + /// + /// The `prepare_priority` is relevant in the context of the caller. Currently we expect + /// that `approval` context has priority over `backing` context. /// /// NOTE: Should retry only on errors that are a result of execution itself, and not of /// preparation. @@ -763,6 +789,8 @@ trait ValidationBackend { params: ValidationParams, executor_params: ExecutorParams, retry_delay: Duration, + // The priority for the preparation job. + prepare_priority: polkadot_node_core_pvf::Priority, ) -> Result { let prep_timeout = pvf_prep_timeout(&executor_params, PvfPrepKind::Prepare); // Construct the PVF a single time, since it is an expensive operation. Cloning it is cheap. @@ -776,8 +804,10 @@ trait ValidationBackend { // long. let total_time_start = Instant::now(); - let mut validation_result = - self.validate_candidate(pvf.clone(), exec_timeout, params.encode()).await; + // Use `Priority::Critical` as finality trumps parachain liveliness. + let mut validation_result = self + .validate_candidate(pvf.clone(), exec_timeout, params.encode(), prepare_priority) + .await; if validation_result.is_ok() { return validation_result } @@ -851,8 +881,9 @@ trait ValidationBackend { // Encode the params again when re-trying. We expect the retry case to be relatively // rare, and we want to avoid unconditionally cloning data. - validation_result = - self.validate_candidate(pvf.clone(), new_timeout, params.encode()).await; + validation_result = self + .validate_candidate(pvf.clone(), new_timeout, params.encode(), prepare_priority) + .await; } } @@ -870,11 +901,13 @@ impl ValidationBackend for ValidationHost { pvf: PvfPrepData, exec_timeout: Duration, encoded_params: Vec, + // The priority for the preparation job. + prepare_priority: polkadot_node_core_pvf::Priority, ) -> Result { - let priority = polkadot_node_core_pvf::Priority::Normal; - let (tx, rx) = oneshot::channel(); - if let Err(err) = self.execute_pvf(pvf, exec_timeout, encoded_params, priority, tx).await { + if let Err(err) = + self.execute_pvf(pvf, exec_timeout, encoded_params, prepare_priority, tx).await + { return Err(InternalValidationError::HostCommunication(format!( "cannot send pvf to the validation host, it might have shut down: {:?}", err diff --git a/polkadot/node/core/candidate-validation/src/tests.rs b/polkadot/node/core/candidate-validation/src/tests.rs index f646f8535495b74128f829359214018c4fb01ac2..e492d51e239ed4bcdfd3a239f635fcd0b0f2154b 100644 --- a/polkadot/node/core/candidate-validation/src/tests.rs +++ b/polkadot/node/core/candidate-validation/src/tests.rs @@ -368,6 +368,7 @@ impl ValidationBackend for MockValidateCandidateBackend { _pvf: PvfPrepData, _timeout: Duration, _encoded_params: Vec, + _prepare_priority: polkadot_node_core_pvf::Priority, ) -> Result { // This is expected to panic if called more times than expected, indicating an error in the // test. @@ -1044,6 +1045,7 @@ impl ValidationBackend for MockPreCheckBackend { _pvf: PvfPrepData, _timeout: Duration, _encoded_params: Vec, + _prepare_priority: polkadot_node_core_pvf::Priority, ) -> Result { unreachable!() } diff --git a/polkadot/node/core/chain-api/Cargo.toml b/polkadot/node/core/chain-api/Cargo.toml index f4d02d3f47b23ac4e71fa44c790bf4b0d1538902..bd8531c207847142a3b2ecd4407ef11253251034 100644 --- a/polkadot/node/core/chain-api/Cargo.toml +++ b/polkadot/node/core/chain-api/Cargo.toml @@ -21,7 +21,7 @@ sc-consensus-babe = { path = "../../../../substrate/client/consensus/babe" } [dev-dependencies] futures = { version = "0.3.30", features = ["thread-pool"] } maplit = "1.0.2" -parity-scale-codec = "3.6.1" +parity-scale-codec = "3.6.12" polkadot-node-primitives = { path = "../../primitives" } polkadot-primitives = { path = "../../../primitives" } polkadot-node-subsystem-test-helpers = { path = "../../subsystem-test-helpers" } diff --git a/polkadot/node/core/chain-selection/Cargo.toml b/polkadot/node/core/chain-selection/Cargo.toml index 318f27a43086e4c6bee0bf0a0b18a78c9cf525be..b58053b5417eceb0bddfc2f34df5f1d84126c1c0 100644 --- a/polkadot/node/core/chain-selection/Cargo.toml +++ b/polkadot/node/core/chain-selection/Cargo.toml @@ -19,7 +19,7 @@ polkadot-node-subsystem = { path = "../../subsystem" } polkadot-node-subsystem-util = { path = "../../subsystem-util" } kvdb = "0.13.0" thiserror = { workspace = true } -parity-scale-codec = "3.6.1" +parity-scale-codec = "3.6.12" [dev-dependencies] polkadot-node-subsystem-test-helpers = { path = "../../subsystem-test-helpers" } diff --git a/polkadot/node/core/chain-selection/src/lib.rs b/polkadot/node/core/chain-selection/src/lib.rs index 6f864fefb6110184233d52620dea923f8f0b1e4a..07c245e839bf18a55f5ec61f02824fa87e9c6ed9 100644 --- a/polkadot/node/core/chain-selection/src/lib.rs +++ b/polkadot/node/core/chain-selection/src/lib.rs @@ -619,7 +619,7 @@ async fn handle_active_leaf( // Extract all reversion logs from a header in ascending order. // -// Ignores logs with number >= the block header number. +// Ignores logs with number > the block header number. fn extract_reversion_logs(header: &Header) -> Vec { let number = header.number; let mut logs = header @@ -639,14 +639,14 @@ fn extract_reversion_logs(header: &Header) -> Vec { None }, - Ok(Some(ConsensusLog::Revert(b))) if b < number => Some(b), + Ok(Some(ConsensusLog::Revert(b))) if b <= number => Some(b), Ok(Some(ConsensusLog::Revert(b))) => { gum::warn!( target: LOG_TARGET, revert_target = b, block_number = number, block_hash = ?header.hash(), - "Block issued invalid revert digest targeting itself or future" + "Block issued invalid revert digest targeting future" ); None diff --git a/polkadot/node/core/chain-selection/src/tests.rs b/polkadot/node/core/chain-selection/src/tests.rs index bc998f268a0da6a4ca3703f929be3e1c19677b35..1fe87f04cd585abc1674d3a20766e7172fd819fa 100644 --- a/polkadot/node/core/chain-selection/src/tests.rs +++ b/polkadot/node/core/chain-selection/src/tests.rs @@ -966,19 +966,54 @@ fn ancestor_of_unviable_is_not_leaf_if_has_children() { } #[test] -fn self_and_future_reversions_are_ignored() { +fn self_reversions_are_not_ignored() { test_harness(|backend, _, mut virtual_overseer| async move { let finalized_number = 0; let finalized_hash = Hash::repeat_byte(0); // F <- A1 <- A2 <- A3. // - // A3 reverts itself and future blocks. ignored. + // A3 reverts itself + + let (_, chain_a) = + construct_chain_on_base(vec![1, 2, 3], finalized_number, finalized_hash, |h| { + if h.number == 3 { + add_reversions(h, vec![3]) + } + }); + + let a2_hash = chain_a.iter().rev().nth(1).unwrap().0.hash(); + + import_blocks_into( + &mut virtual_overseer, + &backend, + Some((finalized_number, finalized_hash)), + chain_a.clone(), + ) + .await; + + assert_backend_contains(&backend, chain_a.iter().map(|(h, _)| h)); + assert_leaves(&backend, vec![a2_hash]); + assert_leaves_query(&mut virtual_overseer, vec![a2_hash]).await; + + virtual_overseer + }); +} + +#[test] +fn future_reversions_are_ignored() { + test_harness(|backend, _, mut virtual_overseer| async move { + let finalized_number = 0; + let finalized_hash = Hash::repeat_byte(0); + + // F <- A1 <- A2 <- A3. + // + // A3 reverts future blocks. ignored. let (a3_hash, chain_a) = construct_chain_on_base(vec![1, 2, 3], finalized_number, finalized_hash, |h| { if h.number == 3 { - add_reversions(h, vec![3, 4, 100]) + add_reversions(h, vec![4, 100]) } }); @@ -1006,7 +1041,7 @@ fn revert_finalized_is_ignored() { // F <- A1 <- A2 <- A3. // - // A3 reverts itself and future blocks. ignored. + // A3 reverts finalized F and its ancestors. ignored. let (a3_hash, chain_a) = construct_chain_on_base(vec![1, 2, 3], finalized_number, finalized_hash, |h| { diff --git a/polkadot/node/core/chain-selection/src/tree.rs b/polkadot/node/core/chain-selection/src/tree.rs index b4aba30368a621c1f1eaa5f1834fdb3343427d2f..1eb6c13a7f8232a66a2f0c4b89543f8e79690bce 100644 --- a/polkadot/node/core/chain-selection/src/tree.rs +++ b/polkadot/node/core/chain-selection/src/tree.rs @@ -236,7 +236,7 @@ fn propagate_viability_update( Ok(()) } -/// Imports a new block and applies any reversions to ancestors. +/// Imports a new block and applies any reversions to ancestors or the block itself. pub(crate) fn import_block( backend: &mut OverlayedBackend, block_hash: Hash, @@ -246,25 +246,29 @@ pub(crate) fn import_block( weight: BlockWeight, stagnant_at: Timestamp, ) -> Result<(), Error> { - add_block(backend, block_hash, block_number, parent_hash, weight, stagnant_at)?; - apply_ancestor_reversions(backend, block_hash, block_number, reversion_logs)?; + let block_entry = + add_block(backend, block_hash, block_number, parent_hash, weight, stagnant_at)?; + apply_reversions(backend, block_entry, reversion_logs)?; Ok(()) } // Load the given ancestor's block entry, in descending order from the `block_hash`. -// The ancestor_number must be at least one block less than the `block_number`. +// The ancestor_number must be not higher than the `block_entry`'s. // // The returned entry will be `None` if the range is invalid or any block in the path had // no entry present. If any block entry was missing, it can safely be assumed to // be finalized. fn load_ancestor( backend: &mut OverlayedBackend, - block_hash: Hash, - block_number: BlockNumber, + block_entry: &BlockEntry, ancestor_number: BlockNumber, ) -> Result, Error> { - if block_number <= ancestor_number { + let block_hash = block_entry.block_hash; + let block_number = block_entry.block_number; + if block_number == ancestor_number { + return Ok(Some(block_entry.clone())) + } else if block_number < ancestor_number { return Ok(None) } @@ -300,7 +304,7 @@ fn add_block( parent_hash: Hash, weight: BlockWeight, stagnant_at: Timestamp, -) -> Result<(), Error> { +) -> Result { let mut leaves = backend.load_leaves()?; let parent_entry = backend.load_block_entry(&parent_hash)?; @@ -308,7 +312,7 @@ fn add_block( parent_entry.as_ref().and_then(|parent| parent.non_viable_ancestor_for_child()); // 1. Add the block to the DB assuming it's not reverted. - backend.write_block_entry(BlockEntry { + let block_entry = BlockEntry { block_hash, block_number, parent_hash, @@ -319,7 +323,8 @@ fn add_block( approval: Approval::Unapproved, }, weight, - }); + }; + backend.write_block_entry(block_entry.clone()); // 2. Update leaves if inherited viability is fine. if inherited_viability.is_none() { @@ -344,26 +349,25 @@ fn add_block( stagnant_at_list.push(block_hash); backend.write_stagnant_at(stagnant_at, stagnant_at_list); - Ok(()) + Ok(block_entry) } /// Assuming that a block is already imported, accepts the number of the block /// as well as a list of reversions triggered by the block in ascending order. -fn apply_ancestor_reversions( +fn apply_reversions( backend: &mut OverlayedBackend, - block_hash: Hash, - block_number: BlockNumber, + block_entry: BlockEntry, reversions: Vec, ) -> Result<(), Error> { // Note: since revert numbers are in ascending order, the expensive propagation // of unviability is only heavy on the first log. for revert_number in reversions { - let maybe_block_entry = load_ancestor(backend, block_hash, block_number, revert_number)?; - if let Some(block_entry) = &maybe_block_entry { + let maybe_block_entry = load_ancestor(backend, &block_entry, revert_number)?; + if let Some(entry) = &maybe_block_entry { gum::trace!( target: LOG_TARGET, ?revert_number, - revert_hash = ?block_entry.block_hash, + revert_hash = ?entry.block_hash, "Block marked as reverted via scraped on-chain reversions" ); } @@ -372,8 +376,8 @@ fn apply_ancestor_reversions( maybe_block_entry, None, revert_number, - Some(block_hash), - Some(block_number), + Some(block_entry.block_hash), + Some(block_entry.block_number), )?; } diff --git a/polkadot/node/core/dispute-coordinator/Cargo.toml b/polkadot/node/core/dispute-coordinator/Cargo.toml index cd3238449bea9d19ec65f418237282523ff3448a..8bd510697c913f10020605d335fb1748a2bb43c3 100644 --- a/polkadot/node/core/dispute-coordinator/Cargo.toml +++ b/polkadot/node/core/dispute-coordinator/Cargo.toml @@ -12,11 +12,11 @@ workspace = true [dependencies] futures = "0.3.30" gum = { package = "tracing-gum", path = "../../gum" } -parity-scale-codec = "3.6.1" +parity-scale-codec = "3.6.12" kvdb = "0.13.0" thiserror = { workspace = true } schnellru = "0.2.1" -fatality = "0.0.6" +fatality = "0.1.1" polkadot-primitives = { path = "../../../primitives" } polkadot-node-primitives = { path = "../../primitives" } diff --git a/polkadot/node/core/prospective-parachains/Cargo.toml b/polkadot/node/core/prospective-parachains/Cargo.toml index ab3cef99e54ff6da279ec30728c308ed8bbf3da6..5b4f12a5fbdaffd345cc8f01d92691232deb5046 100644 --- a/polkadot/node/core/prospective-parachains/Cargo.toml +++ b/polkadot/node/core/prospective-parachains/Cargo.toml @@ -12,9 +12,9 @@ workspace = true [dependencies] futures = "0.3.30" gum = { package = "tracing-gum", path = "../../gum" } -parity-scale-codec = "3.6.4" +parity-scale-codec = "3.6.12" thiserror = { workspace = true } -fatality = "0.0.6" +fatality = "0.1.1" bitvec = "1" polkadot-primitives = { path = "../../../primitives" } @@ -23,7 +23,6 @@ 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_chain/mod.rs b/polkadot/node/core/prospective-parachains/src/fragment_chain/mod.rs new file mode 100644 index 0000000000000000000000000000000000000000..f87d4820ff9af242bf28ca7170527ec72d1963b8 --- /dev/null +++ b/polkadot/node/core/prospective-parachains/src/fragment_chain/mod.rs @@ -0,0 +1,992 @@ +// 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 . + +//! Utility for managing parachain fragments not referenced by the relay-chain. +//! +//! # Overview +//! +//! This module exposes two main types: [`FragmentChain`] and [`CandidateStorage`] which are meant +//! to be used in close conjunction. Each fragment chain is associated with a particular +//! relay-parent and each node in the chain represents a candidate. Each parachain has a single +//! candidate storage, but can have one chain for each relay chain block in the view. +//! Therefore, the same candidate can be present in multiple fragment chains of a parachain. One of +//! the purposes of the candidate storage is to deduplicate the large candidate data that is being +//! referenced from multiple fragment chains. +//! +//! A chain has an associated [`Scope`] which defines limits on candidates within the chain. +//! Candidates themselves have their own [`Constraints`] which are either the constraints from the +//! scope, or, if there are previous nodes in the chain, a modified version of the previous +//! candidate's constraints. +//! +//! Another use of the `CandidateStorage` is to keep a record of candidates which may not be yet +//! included in any chain, but which may become part of a chain in the future. This is needed for +//! elastic scaling, so that we may parallelise the backing process across different groups. As long +//! as some basic constraints are not violated by an unconnected candidate (like the relay parent +//! being in scope), we proceed with the backing process, hoping that its predecessors will be +//! backed soon enough. This is commonly called a potential candidate. Note that not all potential +//! candidates will be maintained in the CandidateStorage. The total number of connected + potential +//! candidates will be at most max_candidate_depth + 1. +//! +//! This module also makes use of types provided by the Inclusion Emulator module, such as +//! [`Fragment`] and [`Constraints`]. These perform the actual job of checking for validity of +//! prospective fragments. +//! +//! # Parachain forks +//! +//! Parachains are expected to not create forks, hence the use of fragment chains as opposed to +//! fragment trees. If parachains do create forks, their performance in regards to async backing and +//! elastic scaling will suffer, because different validators will have different views of the +//! future. +//! +//! This is a compromise we can make - collators which want to use async backing and elastic scaling +//! need to cooperate for the highest throughput. +//! +//! # Parachain cycles +//! +//! Parachains can create cycles, because: +//! 1. There's no requirement that head-data is unique for a parachain. Furthermore, a parachain +//! is under no obligation to be acyclic, and this is mostly just because it's totally +//! inefficient to enforce it. Practical use-cases are acyclic, but there is still more than +//! one way to reach the same head-data. +//! 2. and candidates only refer to their parent by its head-data. This whole issue could be +//! resolved by having candidates reference their parent by candidate hash. +//! +//! However, dealing with cycles increases complexity during the backing/inclusion process for no +//! practical reason. Therefore, fragment chains will not accept such candidates. +//! +//! On the other hand, enforcing that a parachain will NEVER be acyclic would be very complicated +//! (looping through the entire parachain's history on every new candidate or changing the candidate +//! receipt to reference the parent's candidate hash). +//! +//! # Spam protection +//! +//! As long as the [`CandidateStorage`] has bounded input on the number of candidates supplied, +//! [`FragmentChain`] complexity is bounded. This means that higher-level code needs to be selective +//! about limiting the amount of candidates that are considered. +//! +//! The code in this module is not designed for speed or efficiency, but conceptual simplicity. +//! Our assumption is that the amount of candidates and parachains we consider will be reasonably +//! bounded and in practice will not exceed a few thousand at any time. This naive implementation +//! will still perform fairly well under these conditions, despite being somewhat wasteful of +//! memory. + +#[cfg(test)] +mod tests; + +use std::{ + collections::{ + hash_map::{Entry, HashMap}, + BTreeMap, HashSet, + }, + sync::Arc, +}; + +use super::LOG_TARGET; +use polkadot_node_subsystem::messages::{Ancestors, HypotheticalCandidate}; +use polkadot_node_subsystem_util::inclusion_emulator::{ + ConstraintModifications, Constraints, Fragment, ProspectiveCandidate, RelayChainBlockInfo, +}; +use polkadot_primitives::{ + BlockNumber, CandidateHash, CommittedCandidateReceipt, Hash, HeadData, Id as ParaId, + PersistedValidationData, +}; + +/// Kinds of failures to import a candidate into storage. +#[derive(Debug, Clone, PartialEq)] +pub enum CandidateStorageInsertionError { + /// An error indicating that a supplied candidate didn't match the persisted + /// validation data provided alongside it. + PersistedValidationDataMismatch, + /// The candidate was already known. + CandidateAlreadyKnown(CandidateHash), +} + +/// Stores candidates and information about them such as their relay-parents and their backing +/// states. +#[derive(Clone, Default)] +pub(crate) struct CandidateStorage { + // Index from head data hash to candidate hashes with that head data as a parent. Purely for + // efficiency when responding to `ProspectiveValidationDataRequest`s or when trying to find a + // new candidate to push to a chain. + // Even though having multiple candidates with same parent would be invalid for a parachain, it + // could happen across different relay chain forks, hence the HashSet. + by_parent_head: HashMap>, + + // Index from head data hash to candidate hashes outputting that head data. Purely for + // efficiency when responding to `ProspectiveValidationDataRequest`s. + // Even though having multiple candidates with same output would be invalid for a parachain, + // it could happen across different relay chain forks. + by_output_head: HashMap>, + + // Index from candidate hash to fragment node. + by_candidate_hash: HashMap, +} + +impl CandidateStorage { + /// Introduce a new candidate. + pub fn add_candidate( + &mut self, + candidate: CommittedCandidateReceipt, + persisted_validation_data: PersistedValidationData, + state: CandidateState, + ) -> Result { + let candidate_hash = candidate.hash(); + if self.by_candidate_hash.contains_key(&candidate_hash) { + return Err(CandidateStorageInsertionError::CandidateAlreadyKnown(candidate_hash)) + } + + if persisted_validation_data.hash() != candidate.descriptor.persisted_validation_data_hash { + return Err(CandidateStorageInsertionError::PersistedValidationDataMismatch) + } + + let entry = CandidateEntry { + candidate_hash, + parent_head_data_hash: persisted_validation_data.parent_head.hash(), + output_head_data_hash: candidate.commitments.head_data.hash(), + relay_parent: candidate.descriptor.relay_parent, + state, + candidate: Arc::new(ProspectiveCandidate { + commitments: candidate.commitments, + collator: candidate.descriptor.collator, + collator_signature: candidate.descriptor.signature, + persisted_validation_data, + pov_hash: candidate.descriptor.pov_hash, + validation_code_hash: candidate.descriptor.validation_code_hash, + }), + }; + + self.by_parent_head + .entry(entry.parent_head_data_hash()) + .or_default() + .insert(candidate_hash); + self.by_output_head + .entry(entry.output_head_data_hash()) + .or_default() + .insert(candidate_hash); + // sanity-checked already. + self.by_candidate_hash.insert(candidate_hash, entry); + + Ok(candidate_hash) + } + + /// Remove a candidate from the store. + pub fn remove_candidate(&mut self, candidate_hash: &CandidateHash) { + if let Some(entry) = self.by_candidate_hash.remove(candidate_hash) { + if let Entry::Occupied(mut e) = self.by_parent_head.entry(entry.parent_head_data_hash()) + { + e.get_mut().remove(&candidate_hash); + if e.get().is_empty() { + e.remove(); + } + } + + if let Entry::Occupied(mut e) = self.by_output_head.entry(entry.output_head_data_hash()) + { + e.get_mut().remove(&candidate_hash); + if e.get().is_empty() { + e.remove(); + } + } + } + } + + /// Note that an existing candidate has been backed. + pub fn mark_backed(&mut self, candidate_hash: &CandidateHash) { + if let Some(entry) = self.by_candidate_hash.get_mut(candidate_hash) { + gum::trace!(target: LOG_TARGET, ?candidate_hash, "Candidate marked as backed"); + entry.state = CandidateState::Backed; + } else { + gum::trace!(target: LOG_TARGET, ?candidate_hash, "Candidate not found while marking as backed"); + } + } + + /// Whether a candidate is recorded as being backed. + pub fn is_backed(&self, candidate_hash: &CandidateHash) -> bool { + self.by_candidate_hash + .get(candidate_hash) + .map_or(false, |e| e.state == CandidateState::Backed) + } + + /// Whether a candidate is contained within the storage already. + pub fn contains(&self, candidate_hash: &CandidateHash) -> bool { + self.by_candidate_hash.contains_key(candidate_hash) + } + + /// Return an iterator over the stored candidates. + pub fn candidates(&self) -> impl Iterator { + self.by_candidate_hash.values() + } + + /// Retain only candidates which pass the predicate. + pub(crate) fn retain(&mut self, pred: impl Fn(&CandidateHash) -> bool) { + self.by_candidate_hash.retain(|h, _v| pred(h)); + self.by_parent_head.retain(|_parent, children| { + children.retain(|h| pred(h)); + !children.is_empty() + }); + self.by_output_head.retain(|_output, candidates| { + candidates.retain(|h| pred(h)); + !candidates.is_empty() + }); + } + + /// Get head-data by hash. + pub(crate) fn head_data_by_hash(&self, hash: &Hash) -> Option<&HeadData> { + // First, search for candidates outputting this head data and extract the head data + // from their commitments if they exist. + // + // Otherwise, search for candidates building upon this head data and extract the head data + // from their persisted validation data if they exist. + self.by_output_head + .get(hash) + .and_then(|m| m.iter().next()) + .and_then(|a_candidate| self.by_candidate_hash.get(a_candidate)) + .map(|e| &e.candidate.commitments.head_data) + .or_else(|| { + self.by_parent_head + .get(hash) + .and_then(|m| m.iter().next()) + .and_then(|a_candidate| self.by_candidate_hash.get(a_candidate)) + .map(|e| &e.candidate.persisted_validation_data.parent_head) + }) + } + + /// Returns candidate's relay parent, if present. + pub(crate) fn relay_parent_of_candidate(&self, candidate_hash: &CandidateHash) -> Option { + self.by_candidate_hash.get(candidate_hash).map(|entry| entry.relay_parent) + } + + /// Returns the candidates which have the given head data hash as parent. + /// We don't allow forks in a parachain, but we may have multiple candidates with same parent + /// across different relay chain forks. That's why it returns an iterator (but only one will be + /// valid and used in the end). + fn possible_para_children<'a>( + &'a self, + parent_head_hash: &'a Hash, + ) -> impl Iterator + 'a { + let by_candidate_hash = &self.by_candidate_hash; + self.by_parent_head + .get(parent_head_hash) + .into_iter() + .flat_map(|hashes| hashes.iter()) + .filter_map(move |h| by_candidate_hash.get(h)) + } + + #[cfg(test)] + pub fn len(&self) -> (usize, usize) { + (self.by_parent_head.len(), self.by_candidate_hash.len()) + } +} + +/// The state of a candidate. +/// +/// Candidates aren't even considered until they've at least been seconded. +#[derive(Debug, PartialEq, Clone)] +pub(crate) enum CandidateState { + /// The candidate has been seconded. + Seconded, + /// The candidate has been completely backed by the group. + Backed, +} + +#[derive(Debug, Clone)] +pub(crate) struct CandidateEntry { + candidate_hash: CandidateHash, + parent_head_data_hash: Hash, + output_head_data_hash: Hash, + relay_parent: Hash, + candidate: Arc, + state: CandidateState, +} + +impl CandidateEntry { + pub fn hash(&self) -> CandidateHash { + self.candidate_hash + } + + pub fn parent_head_data_hash(&self) -> Hash { + self.parent_head_data_hash + } + + pub fn output_head_data_hash(&self) -> Hash { + self.output_head_data_hash + } +} + +/// A candidate existing on-chain but pending availability, for special treatment +/// in the [`Scope`]. +#[derive(Debug, Clone)] +pub(crate) struct PendingAvailability { + /// The candidate hash. + pub candidate_hash: CandidateHash, + /// The block info of the relay parent. + pub relay_parent: RelayChainBlockInfo, +} + +/// The scope of a [`FragmentChain`]. +#[derive(Debug, Clone)] +pub(crate) struct Scope { + /// The assigned para id of this `FragmentChain`. + para: ParaId, + /// The relay parent we're currently building on top of. + relay_parent: RelayChainBlockInfo, + /// The other relay parents candidates are allowed to build upon, mapped by the block number. + ancestors: BTreeMap, + /// The other relay parents candidates are allowed to build upon, mapped by the block hash. + ancestors_by_hash: HashMap, + /// The candidates pending availability at this block. + pending_availability: Vec, + /// The base constraints derived from the latest included candidate. + base_constraints: Constraints, + /// Equal to `max_candidate_depth`. + max_depth: usize, +} + +/// An error variant indicating that ancestors provided to a scope +/// had unexpected order. +#[derive(Debug)] +pub struct UnexpectedAncestor { + /// The block number that this error occurred at. + pub number: BlockNumber, + /// The previous seen block number, which did not match `number`. + pub prev: BlockNumber, +} + +impl Scope { + /// Define a new [`Scope`]. + /// + /// All arguments are straightforward except the ancestors. + /// + /// Ancestors should be in reverse order, starting with the parent + /// of the `relay_parent`, and proceeding backwards in block number + /// increments of 1. Ancestors not following these conditions will be + /// rejected. + /// + /// This function will only consume ancestors up to the `min_relay_parent_number` of + /// the `base_constraints`. + /// + /// Only ancestors whose children have the same session as the relay-parent's + /// children should be provided. + /// + /// It is allowed to provide zero ancestors. + pub fn with_ancestors( + para: ParaId, + relay_parent: RelayChainBlockInfo, + base_constraints: Constraints, + pending_availability: Vec, + max_depth: usize, + ancestors: impl IntoIterator, + ) -> Result { + let mut ancestors_map = BTreeMap::new(); + let mut ancestors_by_hash = HashMap::new(); + { + let mut prev = relay_parent.number; + for ancestor in ancestors { + if prev == 0 { + return Err(UnexpectedAncestor { number: ancestor.number, prev }) + } else if ancestor.number != prev - 1 { + return Err(UnexpectedAncestor { number: ancestor.number, prev }) + } else if prev == base_constraints.min_relay_parent_number { + break + } else { + prev = ancestor.number; + ancestors_by_hash.insert(ancestor.hash, ancestor.clone()); + ancestors_map.insert(ancestor.number, ancestor); + } + } + } + + Ok(Scope { + para, + relay_parent, + base_constraints, + pending_availability, + max_depth, + ancestors: ancestors_map, + ancestors_by_hash, + }) + } + + /// Get the earliest relay-parent allowed in the scope of the fragment chain. + pub fn earliest_relay_parent(&self) -> RelayChainBlockInfo { + self.ancestors + .iter() + .next() + .map(|(_, v)| v.clone()) + .unwrap_or_else(|| self.relay_parent.clone()) + } + + /// Get the relay ancestor of the fragment chain by hash. + pub fn ancestor(&self, hash: &Hash) -> Option { + if hash == &self.relay_parent.hash { + return Some(self.relay_parent.clone()) + } + + self.ancestors_by_hash.get(hash).map(|info| info.clone()) + } + + /// Whether the candidate in question is one pending availability in this scope. + pub fn get_pending_availability( + &self, + candidate_hash: &CandidateHash, + ) -> Option<&PendingAvailability> { + self.pending_availability.iter().find(|c| &c.candidate_hash == candidate_hash) + } + + /// Get the base constraints of the scope + pub fn base_constraints(&self) -> &Constraints { + &self.base_constraints + } +} + +pub struct FragmentNode { + fragment: Fragment, + candidate_hash: CandidateHash, + cumulative_modifications: ConstraintModifications, +} + +impl FragmentNode { + fn relay_parent(&self) -> Hash { + self.fragment.relay_parent().hash + } +} + +/// Response given by `can_add_candidate_as_potential` +#[derive(PartialEq, Debug)] +pub enum PotentialAddition { + /// Can be added as either connected or unconnected candidate. + Anyhow, + /// Can only be added as a connected candidate to the chain. + IfConnected, + /// Cannot be added. + None, +} + +/// This is a chain of candidates based on some underlying storage of candidates and a scope. +/// +/// All nodes in the chain must be either pending availability or within the scope. Within the scope +/// means it's built off of the relay-parent or an ancestor. +pub(crate) struct FragmentChain { + scope: Scope, + + chain: Vec, + + candidates: HashSet, + + // Index from head data hash to candidate hashes with that head data as a parent. + by_parent_head: HashMap, + // Index from head data hash to candidate hashes outputting that head data. + by_output_head: HashMap, +} + +impl FragmentChain { + /// Create a new [`FragmentChain`] with given scope and populated from the storage. + pub fn populate(scope: Scope, storage: &CandidateStorage) -> Self { + gum::trace!( + target: LOG_TARGET, + relay_parent = ?scope.relay_parent.hash, + relay_parent_num = scope.relay_parent.number, + para_id = ?scope.para, + ancestors = scope.ancestors.len(), + "Instantiating Fragment Chain", + ); + + let mut fragment_chain = Self { + scope, + chain: Vec::new(), + candidates: HashSet::new(), + by_parent_head: HashMap::new(), + by_output_head: HashMap::new(), + }; + + fragment_chain.populate_chain(storage); + + fragment_chain + } + + /// Get the scope of the Fragment Chain. + pub fn scope(&self) -> &Scope { + &self.scope + } + + /// Returns the number of candidates in the chain + pub(crate) fn len(&self) -> usize { + self.candidates.len() + } + + /// Whether the candidate exists. + pub(crate) fn contains_candidate(&self, candidate: &CandidateHash) -> bool { + self.candidates.contains(candidate) + } + + /// Return a vector of the chain's candidate hashes, in-order. + pub(crate) fn to_vec(&self) -> Vec { + self.chain.iter().map(|candidate| candidate.candidate_hash).collect() + } + + /// Try accumulating more candidates onto the chain. + /// + /// Candidates can only be added if they build on the already existing chain. + pub(crate) fn extend_from_storage(&mut self, storage: &CandidateStorage) { + self.populate_chain(storage); + } + + /// Returns the hypothetical state of a candidate with the given hash and parent head data + /// in regards to the existing chain. + /// + /// Returns true if either: + /// - the candidate is already present + /// - the candidate can be added to the chain + /// - the candidate could potentially be added to the chain in the future (its ancestors are + /// still unknown but it doesn't violate other rules). + /// + /// If this returns false, the candidate could never be added to the current chain (not now, not + /// ever) + pub(crate) fn hypothetical_membership( + &self, + candidate: HypotheticalCandidate, + candidate_storage: &CandidateStorage, + ) -> bool { + let candidate_hash = candidate.candidate_hash(); + + // If we've already used this candidate in the chain + if self.candidates.contains(&candidate_hash) { + return true + } + + let can_add_as_potential = self.can_add_candidate_as_potential( + candidate_storage, + &candidate.candidate_hash(), + &candidate.relay_parent(), + candidate.parent_head_data_hash(), + candidate.output_head_data_hash(), + ); + + if can_add_as_potential == PotentialAddition::None { + return false + } + + let Some(candidate_relay_parent) = self.scope.ancestor(&candidate.relay_parent()) else { + // can_add_candidate_as_potential already checked for this, but just to be safe. + return false + }; + + let identity_modifications = ConstraintModifications::identity(); + let cumulative_modifications = if let Some(last_candidate) = self.chain.last() { + &last_candidate.cumulative_modifications + } else { + &identity_modifications + }; + + let child_constraints = + match self.scope.base_constraints.apply_modifications(&cumulative_modifications) { + Err(e) => { + gum::debug!( + target: LOG_TARGET, + new_parent_head = ?cumulative_modifications.required_parent, + ?candidate_hash, + err = ?e, + "Failed to apply modifications", + ); + + return false + }, + Ok(c) => c, + }; + + let parent_head_hash = candidate.parent_head_data_hash(); + if parent_head_hash == child_constraints.required_parent.hash() { + // We do additional checks for complete candidates. + if let HypotheticalCandidate::Complete { + ref receipt, + ref persisted_validation_data, + .. + } = candidate + { + if Fragment::check_against_constraints( + &candidate_relay_parent, + &child_constraints, + &receipt.commitments, + &receipt.descriptor().validation_code_hash, + persisted_validation_data, + ) + .is_err() + { + gum::debug!( + target: LOG_TARGET, + "Fragment::check_against_constraints() returned error", + ); + return false + } + } + + // If we got this far, it can be added to the chain right now. + true + } else if can_add_as_potential == PotentialAddition::Anyhow { + // Otherwise it is or can be an unconnected candidate, but only if PotentialAddition + // does not force us to only add a connected candidate. + true + } else { + false + } + } + + /// Select `count` candidates after the given `ancestors` which pass + /// the predicate and have not already been backed on chain. + /// + /// The intention of the `ancestors` is to allow queries on the basis of + /// one or more candidates which were previously pending availability becoming + /// available or candidates timing out. + pub(crate) fn find_backable_chain( + &self, + ancestors: Ancestors, + count: u32, + pred: impl Fn(&CandidateHash) -> bool, + ) -> Vec { + if count == 0 { + return vec![] + } + let base_pos = self.find_ancestor_path(ancestors); + + let actual_end_index = std::cmp::min(base_pos + (count as usize), self.chain.len()); + let mut res = Vec::with_capacity(actual_end_index - base_pos); + + for elem in &self.chain[base_pos..actual_end_index] { + if self.scope.get_pending_availability(&elem.candidate_hash).is_none() && + pred(&elem.candidate_hash) + { + res.push(elem.candidate_hash); + } else { + break + } + } + + res + } + + // Tries to orders the ancestors into a viable path from root to the last one. + // Stops when the ancestors are all used or when a node in the chain is not present in the + // ancestor set. Returns the index in the chain were the search stopped. + fn find_ancestor_path(&self, mut ancestors: Ancestors) -> usize { + if self.chain.is_empty() { + return 0; + } + + for (index, candidate) in self.chain.iter().enumerate() { + if !ancestors.remove(&candidate.candidate_hash) { + return index + } + } + + // This means that we found the entire chain in the ancestor set. There won't be anything + // left to back. + self.chain.len() + } + + // Return the earliest relay parent a new candidate can have in order to be added to the chain. + // This is the relay parent of the last candidate in the chain. + // The value returned may not be valid if we want to add a candidate pending availability, which + // may have a relay parent which is out of scope. Special handling is needed in that case. + // `None` is returned if the candidate's relay parent info cannot be found. + fn earliest_relay_parent(&self) -> Option { + if let Some(last_candidate) = self.chain.last() { + self.scope.ancestor(&last_candidate.relay_parent()).or_else(|| { + // if the relay-parent is out of scope _and_ it is in the chain, + // it must be a candidate pending availability. + self.scope + .get_pending_availability(&last_candidate.candidate_hash) + .map(|c| c.relay_parent.clone()) + }) + } else { + Some(self.scope.earliest_relay_parent()) + } + } + + // Checks if this candidate could be added in the future to this chain. + // This assumes that the chain does not already contain this candidate. It may or may not be + // present in the `CandidateStorage`. + // Even if the candidate is a potential candidate, this function will indicate that it can be + // kept only if there's enough room for it. + pub(crate) fn can_add_candidate_as_potential( + &self, + storage: &CandidateStorage, + candidate_hash: &CandidateHash, + relay_parent: &Hash, + parent_head_hash: Hash, + output_head_hash: Option, + ) -> PotentialAddition { + // If we've got enough candidates for the configured depth, no point in adding more. + if self.chain.len() > self.scope.max_depth { + return PotentialAddition::None + } + + if !self.check_potential(relay_parent, parent_head_hash, output_head_hash) { + return PotentialAddition::None + } + + let present_in_storage = storage.contains(candidate_hash); + + let unconnected = self + .find_unconnected_potential_candidates( + storage, + present_in_storage.then_some(candidate_hash), + ) + .len(); + + if (self.chain.len() + unconnected) < self.scope.max_depth { + PotentialAddition::Anyhow + } else if (self.chain.len() + unconnected) == self.scope.max_depth { + // If we've only one slot left to fill, it must be filled with a connected candidate. + PotentialAddition::IfConnected + } else { + PotentialAddition::None + } + } + + // The candidates which are present in `CandidateStorage`, are not part of this chain but could + // become part of this chain in the future. Capped at the max depth minus the existing chain + // length. + // If `ignore_candidate` is supplied and found in storage, it won't be counted. + pub(crate) fn find_unconnected_potential_candidates( + &self, + storage: &CandidateStorage, + ignore_candidate: Option<&CandidateHash>, + ) -> Vec { + let mut candidates = vec![]; + for candidate in storage.candidates() { + if let Some(ignore_candidate) = ignore_candidate { + if ignore_candidate == &candidate.candidate_hash { + continue + } + } + // We stop at max_depth + 1 with the search. There's no point in looping further. + if (self.chain.len() + candidates.len()) > self.scope.max_depth { + break + } + if !self.candidates.contains(&candidate.candidate_hash) && + self.check_potential( + &candidate.relay_parent, + candidate.candidate.persisted_validation_data.parent_head.hash(), + Some(candidate.candidate.commitments.head_data.hash()), + ) { + candidates.push(candidate.candidate_hash); + } + } + + candidates + } + + // Check if adding a candidate which transitions `parent_head_hash` to `output_head_hash` would + // introduce a fork or a cycle in the parachain. + // `output_head_hash` is optional because we sometimes make this check before retrieving the + // collation. + fn is_fork_or_cycle(&self, parent_head_hash: Hash, output_head_hash: Option) -> bool { + if self.by_parent_head.contains_key(&parent_head_hash) { + // fork. our parent has another child already + return true + } + + if let Some(output_head_hash) = output_head_hash { + if self.by_output_head.contains_key(&output_head_hash) { + // this is not a chain, there are multiple paths to the same state. + return true + } + + // trivial 0-length cycle. + if parent_head_hash == output_head_hash { + return true + } + + // this should catch any other cycles. our output state cannot already be the parent + // state of another candidate, unless this is a cycle, since the already added + // candidates form a chain. + if self.by_parent_head.contains_key(&output_head_hash) { + return true + } + } + + false + } + + // Checks the potential of a candidate to be added to the chain in the future. + // Verifies that the relay parent is in scope and not moving backwards and that we're not + // introducing forks or cycles with other candidates in the chain. + // `output_head_hash` is optional because we sometimes make this check before retrieving the + // collation. + fn check_potential( + &self, + relay_parent: &Hash, + parent_head_hash: Hash, + output_head_hash: Option, + ) -> bool { + if self.is_fork_or_cycle(parent_head_hash, output_head_hash) { + return false + } + + let Some(earliest_rp) = self.earliest_relay_parent() else { return false }; + + let Some(relay_parent) = self.scope.ancestor(relay_parent) else { return false }; + + if relay_parent.number < earliest_rp.number { + return false // relay parent moved backwards. + } + + true + } + + // Populate the fragment chain with candidates from CandidateStorage. + // Can be called by the constructor or when introducing a new candidate. + // If we're introducing a new candidate onto an existing chain, we may introduce more than one, + // since we may connect already existing candidates to the chain. + fn populate_chain(&mut self, storage: &CandidateStorage) { + let mut cumulative_modifications = if let Some(last_candidate) = self.chain.last() { + last_candidate.cumulative_modifications.clone() + } else { + ConstraintModifications::identity() + }; + let Some(mut earliest_rp) = self.earliest_relay_parent() else { return }; + + loop { + if self.chain.len() > self.scope.max_depth { + break; + } + + let child_constraints = + match self.scope.base_constraints.apply_modifications(&cumulative_modifications) { + Err(e) => { + gum::debug!( + target: LOG_TARGET, + new_parent_head = ?cumulative_modifications.required_parent, + err = ?e, + "Failed to apply modifications", + ); + + break + }, + Ok(c) => c, + }; + + let required_head_hash = child_constraints.required_parent.hash(); + // Even though we don't allow parachain forks under the same active leaf, they may still + // appear under different relay chain forks, hence the iterator below. + let possible_children = storage.possible_para_children(&required_head_hash); + let mut added_child = false; + for candidate in possible_children { + // Add one node to chain if + // 1. it does not introduce a fork or a cycle. + // 2. parent hash is correct. + // 3. relay-parent does not move backwards. + // 4. all non-pending-availability candidates have relay-parent in scope. + // 5. candidate outputs fulfill constraints + + if self.is_fork_or_cycle( + candidate.parent_head_data_hash(), + Some(candidate.output_head_data_hash()), + ) { + continue + } + + let pending = self.scope.get_pending_availability(&candidate.candidate_hash); + let Some(relay_parent) = pending + .map(|p| p.relay_parent.clone()) + .or_else(|| self.scope.ancestor(&candidate.relay_parent)) + else { + continue + }; + + // require: candidates don't move backwards + // and only pending availability candidates can be out-of-scope. + // + // earliest_rp can be before the earliest relay parent in the scope + // when the parent is a pending availability candidate as well, but + // only other pending candidates can have a relay parent out of scope. + let min_relay_parent_number = pending + .map(|p| match self.chain.len() { + 0 => p.relay_parent.number, + _ => earliest_rp.number, + }) + .unwrap_or_else(|| earliest_rp.number); + + if relay_parent.number < min_relay_parent_number { + continue // relay parent moved backwards. + } + + // don't add candidates if they're already present in the chain. + // this can never happen, as candidates can only be duplicated if there's a cycle + // and we shouldn't have allowed for a cycle to be chained. + if self.contains_candidate(&candidate.candidate_hash) { + continue + } + + let fragment = { + let mut constraints = child_constraints.clone(); + if let Some(ref p) = pending { + // overwrite for candidates pending availability as a special-case. + constraints.min_relay_parent_number = p.relay_parent.number; + } + + let f = Fragment::new( + relay_parent.clone(), + constraints, + // It's cheap to clone because it's wrapped in an Arc + candidate.candidate.clone(), + ); + + match f { + Ok(f) => f, + Err(e) => { + gum::debug!( + target: LOG_TARGET, + err = ?e, + ?relay_parent, + candidate_hash = ?candidate.candidate_hash, + "Failed to instantiate fragment", + ); + + break + }, + } + }; + + // Update the cumulative constraint modifications. + cumulative_modifications.stack(fragment.constraint_modifications()); + // Update the earliest rp + earliest_rp = relay_parent; + + let node = FragmentNode { + fragment, + candidate_hash: candidate.candidate_hash, + cumulative_modifications: cumulative_modifications.clone(), + }; + + self.chain.push(node); + self.candidates.insert(candidate.candidate_hash); + // We've already checked for forks and cycles. + self.by_parent_head + .insert(candidate.parent_head_data_hash(), candidate.candidate_hash); + self.by_output_head + .insert(candidate.output_head_data_hash(), candidate.candidate_hash); + added_child = true; + // We can only add one child for a candidate. (it's a chain, not a tree) + break; + } + + if !added_child { + break + } + } + } +} diff --git a/polkadot/node/core/prospective-parachains/src/fragment_chain/tests.rs b/polkadot/node/core/prospective-parachains/src/fragment_chain/tests.rs new file mode 100644 index 0000000000000000000000000000000000000000..26ee94d59d8ebd50bda29218c85b38476f077111 --- /dev/null +++ b/polkadot/node/core/prospective-parachains/src/fragment_chain/tests.rs @@ -0,0 +1,1753 @@ +// Copyright (C) Parity Technologies (UK) Ltd. +// This file is part of Polkadot. + +// Polkadot is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// Polkadot is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with Polkadot. If not, see . + +use super::*; +use assert_matches::assert_matches; +use polkadot_node_subsystem_util::inclusion_emulator::InboundHrmpLimitations; +use polkadot_primitives::{BlockNumber, CandidateCommitments, CandidateDescriptor, HeadData}; +use polkadot_primitives_test_helpers as test_helpers; + +fn make_constraints( + min_relay_parent_number: BlockNumber, + valid_watermarks: Vec, + required_parent: HeadData, +) -> Constraints { + Constraints { + min_relay_parent_number, + max_pov_size: 1_000_000, + max_code_size: 1_000_000, + ump_remaining: 10, + ump_remaining_bytes: 1_000, + max_ump_num_per_candidate: 10, + dmp_remaining_messages: [0; 10].into(), + hrmp_inbound: InboundHrmpLimitations { valid_watermarks }, + hrmp_channels_out: HashMap::new(), + max_hrmp_num_per_candidate: 0, + required_parent, + validation_code_hash: Hash::repeat_byte(42).into(), + upgrade_restriction: None, + future_validation_code: None, + } +} + +fn make_committed_candidate( + para_id: ParaId, + relay_parent: Hash, + relay_parent_number: BlockNumber, + parent_head: HeadData, + para_head: HeadData, + hrmp_watermark: BlockNumber, +) -> (PersistedValidationData, CommittedCandidateReceipt) { + let persisted_validation_data = PersistedValidationData { + parent_head, + relay_parent_number, + relay_parent_storage_root: Hash::repeat_byte(69), + max_pov_size: 1_000_000, + }; + + let candidate = CommittedCandidateReceipt { + descriptor: CandidateDescriptor { + para_id, + relay_parent, + collator: test_helpers::dummy_collator(), + persisted_validation_data_hash: persisted_validation_data.hash(), + pov_hash: Hash::repeat_byte(1), + erasure_root: Hash::repeat_byte(1), + signature: test_helpers::dummy_collator_signature(), + para_head: para_head.hash(), + validation_code_hash: Hash::repeat_byte(42).into(), + }, + commitments: CandidateCommitments { + upward_messages: Default::default(), + horizontal_messages: Default::default(), + new_validation_code: None, + head_data: para_head, + processed_downward_messages: 1, + hrmp_watermark, + }, + }; + + (persisted_validation_data, candidate) +} + +#[test] +fn scope_rejects_ancestors_that_skip_blocks() { + let para_id = ParaId::from(5u32); + let relay_parent = RelayChainBlockInfo { + number: 10, + hash: Hash::repeat_byte(10), + storage_root: Hash::repeat_byte(69), + }; + + let ancestors = vec![RelayChainBlockInfo { + number: 8, + hash: Hash::repeat_byte(8), + storage_root: Hash::repeat_byte(69), + }]; + + let max_depth = 2; + let base_constraints = make_constraints(8, vec![8, 9], vec![1, 2, 3].into()); + let pending_availability = Vec::new(); + + assert_matches!( + Scope::with_ancestors( + para_id, + relay_parent, + base_constraints, + pending_availability, + max_depth, + ancestors + ), + Err(UnexpectedAncestor { number: 8, prev: 10 }) + ); +} + +#[test] +fn scope_rejects_ancestor_for_0_block() { + let para_id = ParaId::from(5u32); + let relay_parent = RelayChainBlockInfo { + number: 0, + hash: Hash::repeat_byte(0), + storage_root: Hash::repeat_byte(69), + }; + + let ancestors = vec![RelayChainBlockInfo { + number: 99999, + hash: Hash::repeat_byte(99), + storage_root: Hash::repeat_byte(69), + }]; + + let max_depth = 2; + let base_constraints = make_constraints(0, vec![], vec![1, 2, 3].into()); + let pending_availability = Vec::new(); + + assert_matches!( + Scope::with_ancestors( + para_id, + relay_parent, + base_constraints, + pending_availability, + max_depth, + ancestors, + ), + Err(UnexpectedAncestor { number: 99999, prev: 0 }) + ); +} + +#[test] +fn scope_only_takes_ancestors_up_to_min() { + let para_id = ParaId::from(5u32); + let relay_parent = RelayChainBlockInfo { + number: 5, + hash: Hash::repeat_byte(0), + storage_root: Hash::repeat_byte(69), + }; + + let ancestors = vec![ + RelayChainBlockInfo { + number: 4, + hash: Hash::repeat_byte(4), + storage_root: Hash::repeat_byte(69), + }, + RelayChainBlockInfo { + number: 3, + hash: Hash::repeat_byte(3), + storage_root: Hash::repeat_byte(69), + }, + RelayChainBlockInfo { + number: 2, + hash: Hash::repeat_byte(2), + storage_root: Hash::repeat_byte(69), + }, + ]; + + let max_depth = 2; + let base_constraints = make_constraints(3, vec![2], vec![1, 2, 3].into()); + let pending_availability = Vec::new(); + + let scope = Scope::with_ancestors( + para_id, + relay_parent, + base_constraints, + pending_availability, + max_depth, + ancestors, + ) + .unwrap(); + + assert_eq!(scope.ancestors.len(), 2); + assert_eq!(scope.ancestors_by_hash.len(), 2); +} + +#[test] +fn scope_rejects_unordered_ancestors() { + let para_id = ParaId::from(5u32); + let relay_parent = RelayChainBlockInfo { + number: 5, + hash: Hash::repeat_byte(0), + storage_root: Hash::repeat_byte(69), + }; + + let ancestors = vec![ + RelayChainBlockInfo { + number: 4, + hash: Hash::repeat_byte(4), + storage_root: Hash::repeat_byte(69), + }, + RelayChainBlockInfo { + number: 2, + hash: Hash::repeat_byte(2), + storage_root: Hash::repeat_byte(69), + }, + RelayChainBlockInfo { + number: 3, + hash: Hash::repeat_byte(3), + storage_root: Hash::repeat_byte(69), + }, + ]; + + let max_depth = 2; + let base_constraints = make_constraints(0, vec![2], vec![1, 2, 3].into()); + let pending_availability = Vec::new(); + + assert_matches!( + Scope::with_ancestors( + para_id, + relay_parent, + base_constraints, + pending_availability, + max_depth, + ancestors, + ), + Err(UnexpectedAncestor { number: 2, prev: 4 }) + ); +} + +#[test] +fn candidate_storage_methods() { + let mut storage = CandidateStorage::default(); + let relay_parent = Hash::repeat_byte(69); + + let (pvd, candidate) = make_committed_candidate( + ParaId::from(5u32), + relay_parent, + 8, + vec![4, 5, 6].into(), + vec![1, 2, 3].into(), + 7, + ); + + let candidate_hash = candidate.hash(); + let parent_head_hash = pvd.parent_head.hash(); + + // Invalid pvd hash + let mut wrong_pvd = pvd.clone(); + wrong_pvd.max_pov_size = 0; + assert_matches!( + storage.add_candidate(candidate.clone(), wrong_pvd, CandidateState::Seconded), + Err(CandidateStorageInsertionError::PersistedValidationDataMismatch) + ); + assert!(!storage.contains(&candidate_hash)); + assert_eq!(storage.possible_para_children(&parent_head_hash).count(), 0); + assert_eq!(storage.relay_parent_of_candidate(&candidate_hash), None); + assert_eq!(storage.head_data_by_hash(&candidate.descriptor.para_head), None); + assert_eq!(storage.head_data_by_hash(&parent_head_hash), None); + assert_eq!(storage.is_backed(&candidate_hash), false); + + // Add a valid candidate + storage + .add_candidate(candidate.clone(), pvd.clone(), CandidateState::Seconded) + .unwrap(); + assert!(storage.contains(&candidate_hash)); + assert_eq!(storage.possible_para_children(&parent_head_hash).count(), 1); + assert_eq!(storage.possible_para_children(&candidate.descriptor.para_head).count(), 0); + assert_eq!(storage.relay_parent_of_candidate(&candidate_hash), Some(relay_parent)); + assert_eq!( + storage.head_data_by_hash(&candidate.descriptor.para_head).unwrap(), + &candidate.commitments.head_data + ); + assert_eq!(storage.head_data_by_hash(&parent_head_hash).unwrap(), &pvd.parent_head); + assert_eq!(storage.is_backed(&candidate_hash), false); + + storage.mark_backed(&candidate_hash); + assert_eq!(storage.is_backed(&candidate_hash), true); + + // Re-adding a candidate fails. + assert_matches!( + storage.add_candidate(candidate.clone(), pvd.clone(), CandidateState::Seconded), + Err(CandidateStorageInsertionError::CandidateAlreadyKnown(hash)) if candidate_hash == hash + ); + + // Remove candidate and re-add it later in backed state. + storage.remove_candidate(&candidate_hash); + assert!(!storage.contains(&candidate_hash)); + assert_eq!(storage.possible_para_children(&parent_head_hash).count(), 0); + assert_eq!(storage.relay_parent_of_candidate(&candidate_hash), None); + assert_eq!(storage.head_data_by_hash(&candidate.descriptor.para_head), None); + assert_eq!(storage.head_data_by_hash(&parent_head_hash), None); + assert_eq!(storage.is_backed(&candidate_hash), false); + + storage + .add_candidate(candidate.clone(), pvd.clone(), CandidateState::Backed) + .unwrap(); + assert_eq!(storage.is_backed(&candidate_hash), true); + + // Test retain + storage.retain(|_| true); + assert!(storage.contains(&candidate_hash)); + storage.retain(|_| false); + assert!(!storage.contains(&candidate_hash)); + assert_eq!(storage.possible_para_children(&parent_head_hash).count(), 0); + assert_eq!(storage.relay_parent_of_candidate(&candidate_hash), None); + assert_eq!(storage.head_data_by_hash(&candidate.descriptor.para_head), None); + assert_eq!(storage.head_data_by_hash(&parent_head_hash), None); + assert_eq!(storage.is_backed(&candidate_hash), false); +} + +#[test] +fn populate_and_extend_from_storage_empty() { + // Empty chain and empty storage. + let storage = CandidateStorage::default(); + let base_constraints = make_constraints(0, vec![0], vec![0x0a].into()); + let pending_availability = Vec::new(); + + let scope = Scope::with_ancestors( + ParaId::from(2), + RelayChainBlockInfo { + number: 1, + hash: Hash::repeat_byte(1), + storage_root: Hash::repeat_byte(2), + }, + base_constraints, + pending_availability, + 4, + vec![], + ) + .unwrap(); + let mut chain = FragmentChain::populate(scope, &storage); + assert!(chain.to_vec().is_empty()); + + chain.extend_from_storage(&storage); + assert!(chain.to_vec().is_empty()); +} + +#[test] +fn populate_and_extend_from_storage_with_existing_empty_to_vec() { + let mut storage = CandidateStorage::default(); + + let para_id = ParaId::from(5u32); + let relay_parent_a = Hash::repeat_byte(1); + let relay_parent_b = Hash::repeat_byte(2); + let relay_parent_c = Hash::repeat_byte(3); + + let (pvd_a, candidate_a) = make_committed_candidate( + para_id, + relay_parent_a, + 0, + vec![0x0a].into(), + vec![0x0b].into(), + 0, + ); + let candidate_a_hash = candidate_a.hash(); + + let (pvd_b, candidate_b) = make_committed_candidate( + para_id, + relay_parent_b, + 1, + vec![0x0b].into(), + vec![0x0c].into(), + 1, + ); + let candidate_b_hash = candidate_b.hash(); + + let (pvd_c, candidate_c) = make_committed_candidate( + para_id, + relay_parent_c, + 2, + vec![0x0c].into(), + vec![0x0d].into(), + 2, + ); + let candidate_c_hash = candidate_c.hash(); + + let relay_parent_a_info = RelayChainBlockInfo { + number: pvd_a.relay_parent_number, + hash: relay_parent_a, + storage_root: pvd_a.relay_parent_storage_root, + }; + let relay_parent_b_info = RelayChainBlockInfo { + number: pvd_b.relay_parent_number, + hash: relay_parent_b, + storage_root: pvd_b.relay_parent_storage_root, + }; + let relay_parent_c_info = RelayChainBlockInfo { + number: pvd_c.relay_parent_number, + hash: relay_parent_c, + storage_root: pvd_c.relay_parent_storage_root, + }; + + let base_constraints = make_constraints(0, vec![0], vec![0x0a].into()); + let pending_availability = Vec::new(); + + let ancestors = vec![ + // These need to be ordered in reverse. + relay_parent_b_info.clone(), + relay_parent_a_info.clone(), + ]; + + storage + .add_candidate(candidate_a.clone(), pvd_a.clone(), CandidateState::Seconded) + .unwrap(); + storage + .add_candidate(candidate_b.clone(), pvd_b.clone(), CandidateState::Backed) + .unwrap(); + storage + .add_candidate(candidate_c.clone(), pvd_c.clone(), CandidateState::Backed) + .unwrap(); + + // Candidate A doesn't adhere to the base constraints. + { + for wrong_constraints in [ + // Different required parent + make_constraints(0, vec![0], vec![0x0e].into()), + // Min relay parent number is wrong + make_constraints(1, vec![0], vec![0x0a].into()), + ] { + let scope = Scope::with_ancestors( + para_id, + relay_parent_c_info.clone(), + wrong_constraints.clone(), + pending_availability.clone(), + 4, + ancestors.clone(), + ) + .unwrap(); + let mut chain = FragmentChain::populate(scope, &storage); + + assert!(chain.to_vec().is_empty()); + + chain.extend_from_storage(&storage); + assert!(chain.to_vec().is_empty()); + + // If the min relay parent number is wrong, candidate A can never become valid. + // Otherwise, if only the required parent doesn't match, candidate A is still a + // potential candidate. + if wrong_constraints.min_relay_parent_number == 1 { + assert_eq!( + chain.can_add_candidate_as_potential( + &storage, + &candidate_a.hash(), + &candidate_a.descriptor.relay_parent, + pvd_a.parent_head.hash(), + Some(candidate_a.commitments.head_data.hash()), + ), + PotentialAddition::None + ); + } else { + assert_eq!( + chain.can_add_candidate_as_potential( + &storage, + &candidate_a.hash(), + &candidate_a.descriptor.relay_parent, + pvd_a.parent_head.hash(), + Some(candidate_a.commitments.head_data.hash()), + ), + PotentialAddition::Anyhow + ); + } + + // All other candidates can always be potential candidates. + for (candidate, pvd) in + [(candidate_b.clone(), pvd_b.clone()), (candidate_c.clone(), pvd_c.clone())] + { + assert_eq!( + chain.can_add_candidate_as_potential( + &storage, + &candidate.hash(), + &candidate.descriptor.relay_parent, + pvd.parent_head.hash(), + Some(candidate.commitments.head_data.hash()), + ), + PotentialAddition::Anyhow + ); + } + } + } + + // Various max depths. + { + // depth is 0, will only allow 1 candidate + let scope = Scope::with_ancestors( + para_id, + relay_parent_c_info.clone(), + base_constraints.clone(), + pending_availability.clone(), + 0, + ancestors.clone(), + ) + .unwrap(); + // Before populating the chain, all candidates are potential candidates. However, they can + // only be added as connected candidates, because only one candidates is allowed by max + // depth + let chain = FragmentChain::populate(scope.clone(), &CandidateStorage::default()); + for (candidate, pvd) in [ + (candidate_a.clone(), pvd_a.clone()), + (candidate_b.clone(), pvd_b.clone()), + (candidate_c.clone(), pvd_c.clone()), + ] { + assert_eq!( + chain.can_add_candidate_as_potential( + &CandidateStorage::default(), + &candidate.hash(), + &candidate.descriptor.relay_parent, + pvd.parent_head.hash(), + Some(candidate.commitments.head_data.hash()), + ), + PotentialAddition::IfConnected + ); + } + let mut chain = FragmentChain::populate(scope, &storage); + assert_eq!(chain.to_vec(), vec![candidate_a_hash]); + chain.extend_from_storage(&storage); + assert_eq!(chain.to_vec(), vec![candidate_a_hash]); + // since depth is maxed out, we can't add more potential candidates + // candidate A is no longer a potential candidate because it's already present. + for (candidate, pvd) in [ + (candidate_a.clone(), pvd_a.clone()), + (candidate_b.clone(), pvd_b.clone()), + (candidate_c.clone(), pvd_c.clone()), + ] { + assert_eq!( + chain.can_add_candidate_as_potential( + &storage, + &candidate.hash(), + &candidate.descriptor.relay_parent, + pvd.parent_head.hash(), + Some(candidate.commitments.head_data.hash()), + ), + PotentialAddition::None + ); + } + + // depth is 1, allows two candidates + let scope = Scope::with_ancestors( + para_id, + relay_parent_c_info.clone(), + base_constraints.clone(), + pending_availability.clone(), + 1, + ancestors.clone(), + ) + .unwrap(); + // Before populating the chain, all candidates can be added as potential. + let mut modified_storage = CandidateStorage::default(); + let chain = FragmentChain::populate(scope.clone(), &modified_storage); + for (candidate, pvd) in [ + (candidate_a.clone(), pvd_a.clone()), + (candidate_b.clone(), pvd_b.clone()), + (candidate_c.clone(), pvd_c.clone()), + ] { + assert_eq!( + chain.can_add_candidate_as_potential( + &modified_storage, + &candidate.hash(), + &candidate.descriptor.relay_parent, + pvd.parent_head.hash(), + Some(candidate.commitments.head_data.hash()), + ), + PotentialAddition::Anyhow + ); + } + // Add an unconnected candidate. We now should only allow a Connected candidate, because max + // depth only allows one more candidate. + modified_storage + .add_candidate(candidate_b.clone(), pvd_b.clone(), CandidateState::Seconded) + .unwrap(); + let chain = FragmentChain::populate(scope.clone(), &modified_storage); + for (candidate, pvd) in + [(candidate_a.clone(), pvd_a.clone()), (candidate_c.clone(), pvd_c.clone())] + { + assert_eq!( + chain.can_add_candidate_as_potential( + &modified_storage, + &candidate.hash(), + &candidate.descriptor.relay_parent, + pvd.parent_head.hash(), + Some(candidate.commitments.head_data.hash()), + ), + PotentialAddition::IfConnected + ); + } + + // Now try populating from all candidates. + let mut chain = FragmentChain::populate(scope, &storage); + assert_eq!(chain.to_vec(), vec![candidate_a_hash, candidate_b_hash]); + chain.extend_from_storage(&storage); + assert_eq!(chain.to_vec(), vec![candidate_a_hash, candidate_b_hash]); + // since depth is maxed out, we can't add more potential candidates + // candidate A and B are no longer a potential candidate because they're already present. + for (candidate, pvd) in [ + (candidate_a.clone(), pvd_a.clone()), + (candidate_b.clone(), pvd_b.clone()), + (candidate_c.clone(), pvd_c.clone()), + ] { + assert_eq!( + chain.can_add_candidate_as_potential( + &storage, + &candidate.hash(), + &candidate.descriptor.relay_parent, + pvd.parent_head.hash(), + Some(candidate.commitments.head_data.hash()), + ), + PotentialAddition::None + ); + } + + // depths larger than 2, allows all candidates + for depth in 2..6 { + let scope = Scope::with_ancestors( + para_id, + relay_parent_c_info.clone(), + base_constraints.clone(), + pending_availability.clone(), + depth, + ancestors.clone(), + ) + .unwrap(); + let mut chain = FragmentChain::populate(scope, &storage); + assert_eq!(chain.to_vec(), vec![candidate_a_hash, candidate_b_hash, candidate_c_hash]); + chain.extend_from_storage(&storage); + assert_eq!(chain.to_vec(), vec![candidate_a_hash, candidate_b_hash, candidate_c_hash]); + // Candidates are no longer potential candidates because they're already part of the + // chain. + for (candidate, pvd) in [ + (candidate_a.clone(), pvd_a.clone()), + (candidate_b.clone(), pvd_b.clone()), + (candidate_c.clone(), pvd_c.clone()), + ] { + assert_eq!( + chain.can_add_candidate_as_potential( + &storage, + &candidate.hash(), + &candidate.descriptor.relay_parent, + pvd.parent_head.hash(), + Some(candidate.commitments.head_data.hash()), + ), + PotentialAddition::None + ); + } + } + } + + // Wrong relay parents + { + // Candidates A has relay parent out of scope. + let ancestors_without_a = vec![relay_parent_b_info.clone()]; + let scope = Scope::with_ancestors( + para_id, + relay_parent_c_info.clone(), + base_constraints.clone(), + pending_availability.clone(), + 4, + ancestors_without_a, + ) + .unwrap(); + + let mut chain = FragmentChain::populate(scope, &storage); + assert!(chain.to_vec().is_empty()); + + chain.extend_from_storage(&storage); + assert!(chain.to_vec().is_empty()); + + // Candidate A is not a potential candidate, but candidates B and C still are. + assert_eq!( + chain.can_add_candidate_as_potential( + &storage, + &candidate_a.hash(), + &candidate_a.descriptor.relay_parent, + pvd_a.parent_head.hash(), + Some(candidate_a.commitments.head_data.hash()), + ), + PotentialAddition::None + ); + for (candidate, pvd) in + [(candidate_b.clone(), pvd_b.clone()), (candidate_c.clone(), pvd_c.clone())] + { + assert_eq!( + chain.can_add_candidate_as_potential( + &storage, + &candidate.hash(), + &candidate.descriptor.relay_parent, + pvd.parent_head.hash(), + Some(candidate.commitments.head_data.hash()), + ), + PotentialAddition::Anyhow + ); + } + + // Candidate C has the same relay parent as candidate A's parent. Relay parent not allowed + // to move backwards + let mut modified_storage = storage.clone(); + modified_storage.remove_candidate(&candidate_c_hash); + let (wrong_pvd_c, wrong_candidate_c) = make_committed_candidate( + para_id, + relay_parent_a, + 1, + vec![0x0c].into(), + vec![0x0d].into(), + 2, + ); + modified_storage + .add_candidate(wrong_candidate_c.clone(), wrong_pvd_c.clone(), CandidateState::Seconded) + .unwrap(); + let scope = Scope::with_ancestors( + para_id, + relay_parent_c_info.clone(), + base_constraints.clone(), + pending_availability.clone(), + 4, + ancestors.clone(), + ) + .unwrap(); + let mut chain = FragmentChain::populate(scope, &modified_storage); + assert_eq!(chain.to_vec(), vec![candidate_a_hash, candidate_b_hash]); + chain.extend_from_storage(&modified_storage); + assert_eq!(chain.to_vec(), vec![candidate_a_hash, candidate_b_hash]); + + // Candidate C is not even a potential candidate. + assert_eq!( + chain.can_add_candidate_as_potential( + &modified_storage, + &wrong_candidate_c.hash(), + &wrong_candidate_c.descriptor.relay_parent, + wrong_pvd_c.parent_head.hash(), + Some(wrong_candidate_c.commitments.head_data.hash()), + ), + PotentialAddition::None + ); + } + + // Parachain fork and cycles are not allowed. + { + // Candidate C has the same parent as candidate B. + let mut modified_storage = storage.clone(); + modified_storage.remove_candidate(&candidate_c_hash); + let (wrong_pvd_c, wrong_candidate_c) = make_committed_candidate( + para_id, + relay_parent_c, + 2, + vec![0x0b].into(), + vec![0x0d].into(), + 2, + ); + modified_storage + .add_candidate(wrong_candidate_c.clone(), wrong_pvd_c.clone(), CandidateState::Seconded) + .unwrap(); + let scope = Scope::with_ancestors( + para_id, + relay_parent_c_info.clone(), + base_constraints.clone(), + pending_availability.clone(), + 4, + ancestors.clone(), + ) + .unwrap(); + let mut chain = FragmentChain::populate(scope, &modified_storage); + // We'll either have A->B or A->C. It's not deterministic because CandidateStorage uses + // HashSets and HashMaps. + if chain.to_vec() == vec![candidate_a_hash, candidate_b_hash] { + chain.extend_from_storage(&modified_storage); + assert_eq!(chain.to_vec(), vec![candidate_a_hash, candidate_b_hash]); + // Candidate C is not even a potential candidate. + assert_eq!( + chain.can_add_candidate_as_potential( + &modified_storage, + &wrong_candidate_c.hash(), + &wrong_candidate_c.descriptor.relay_parent, + wrong_pvd_c.parent_head.hash(), + Some(wrong_candidate_c.commitments.head_data.hash()), + ), + PotentialAddition::None + ); + } else if chain.to_vec() == vec![candidate_a_hash, wrong_candidate_c.hash()] { + chain.extend_from_storage(&modified_storage); + assert_eq!(chain.to_vec(), vec![candidate_a_hash, wrong_candidate_c.hash()]); + // Candidate B is not even a potential candidate. + assert_eq!( + chain.can_add_candidate_as_potential( + &modified_storage, + &candidate_b.hash(), + &candidate_b.descriptor.relay_parent, + pvd_b.parent_head.hash(), + Some(candidate_b.commitments.head_data.hash()), + ), + PotentialAddition::None + ); + } else { + panic!("Unexpected chain: {:?}", chain.to_vec()); + } + + // Candidate C is a 0-length cycle. + // Candidate C has the same parent as candidate B. + let mut modified_storage = storage.clone(); + modified_storage.remove_candidate(&candidate_c_hash); + let (wrong_pvd_c, wrong_candidate_c) = make_committed_candidate( + para_id, + relay_parent_c, + 2, + vec![0x0c].into(), + vec![0x0c].into(), + 2, + ); + modified_storage + .add_candidate(wrong_candidate_c.clone(), wrong_pvd_c.clone(), CandidateState::Seconded) + .unwrap(); + let scope = Scope::with_ancestors( + para_id, + relay_parent_c_info.clone(), + base_constraints.clone(), + pending_availability.clone(), + 4, + ancestors.clone(), + ) + .unwrap(); + let mut chain = FragmentChain::populate(scope, &modified_storage); + assert_eq!(chain.to_vec(), vec![candidate_a_hash, candidate_b_hash]); + chain.extend_from_storage(&modified_storage); + assert_eq!(chain.to_vec(), vec![candidate_a_hash, candidate_b_hash]); + // Candidate C is not even a potential candidate. + assert_eq!( + chain.can_add_candidate_as_potential( + &modified_storage, + &wrong_candidate_c.hash(), + &wrong_candidate_c.descriptor.relay_parent, + wrong_pvd_c.parent_head.hash(), + Some(wrong_candidate_c.commitments.head_data.hash()), + ), + PotentialAddition::None + ); + + // Candidate C points back to the pre-state of candidate C. + let mut modified_storage = storage.clone(); + modified_storage.remove_candidate(&candidate_c_hash); + let (wrong_pvd_c, wrong_candidate_c) = make_committed_candidate( + para_id, + relay_parent_c, + 2, + vec![0x0c].into(), + vec![0x0b].into(), + 2, + ); + modified_storage + .add_candidate(wrong_candidate_c.clone(), wrong_pvd_c.clone(), CandidateState::Seconded) + .unwrap(); + let scope = Scope::with_ancestors( + para_id, + relay_parent_c_info.clone(), + base_constraints.clone(), + pending_availability.clone(), + 4, + ancestors.clone(), + ) + .unwrap(); + let mut chain = FragmentChain::populate(scope, &modified_storage); + assert_eq!(chain.to_vec(), vec![candidate_a_hash, candidate_b_hash]); + chain.extend_from_storage(&modified_storage); + assert_eq!(chain.to_vec(), vec![candidate_a_hash, candidate_b_hash]); + // Candidate C is not even a potential candidate. + assert_eq!( + chain.can_add_candidate_as_potential( + &modified_storage, + &wrong_candidate_c.hash(), + &wrong_candidate_c.descriptor.relay_parent, + wrong_pvd_c.parent_head.hash(), + Some(wrong_candidate_c.commitments.head_data.hash()), + ), + PotentialAddition::None + ); + } + + // Test with candidates pending availability + { + // Valid options + for pending in [ + vec![PendingAvailability { + candidate_hash: candidate_a_hash, + relay_parent: relay_parent_a_info.clone(), + }], + vec![ + PendingAvailability { + candidate_hash: candidate_a_hash, + relay_parent: relay_parent_a_info.clone(), + }, + PendingAvailability { + candidate_hash: candidate_b_hash, + relay_parent: relay_parent_b_info.clone(), + }, + ], + vec![ + PendingAvailability { + candidate_hash: candidate_a_hash, + relay_parent: relay_parent_a_info.clone(), + }, + PendingAvailability { + candidate_hash: candidate_b_hash, + relay_parent: relay_parent_b_info.clone(), + }, + PendingAvailability { + candidate_hash: candidate_c_hash, + relay_parent: relay_parent_c_info.clone(), + }, + ], + ] { + let scope = Scope::with_ancestors( + para_id, + relay_parent_c_info.clone(), + base_constraints.clone(), + pending, + 3, + ancestors.clone(), + ) + .unwrap(); + let mut chain = FragmentChain::populate(scope, &storage); + assert_eq!(chain.to_vec(), vec![candidate_a_hash, candidate_b_hash, candidate_c_hash]); + chain.extend_from_storage(&storage); + assert_eq!(chain.to_vec(), vec![candidate_a_hash, candidate_b_hash, candidate_c_hash]); + } + + // Relay parents of pending availability candidates can be out of scope + // Relay parent of candidate A is out of scope. + let ancestors_without_a = vec![relay_parent_b_info.clone()]; + let scope = Scope::with_ancestors( + para_id, + relay_parent_c_info.clone(), + base_constraints.clone(), + vec![PendingAvailability { + candidate_hash: candidate_a_hash, + relay_parent: relay_parent_a_info.clone(), + }], + 4, + ancestors_without_a, + ) + .unwrap(); + let mut chain = FragmentChain::populate(scope, &storage); + assert_eq!(chain.to_vec(), vec![candidate_a_hash, candidate_b_hash, candidate_c_hash]); + chain.extend_from_storage(&storage); + assert_eq!(chain.to_vec(), vec![candidate_a_hash, candidate_b_hash, candidate_c_hash]); + + // Even relay parents of pending availability candidates which are out of scope cannot move + // backwards. + let scope = Scope::with_ancestors( + para_id, + relay_parent_c_info.clone(), + base_constraints.clone(), + vec![ + PendingAvailability { + candidate_hash: candidate_a_hash, + relay_parent: RelayChainBlockInfo { + hash: relay_parent_a_info.hash, + number: 1, + storage_root: relay_parent_a_info.storage_root, + }, + }, + PendingAvailability { + candidate_hash: candidate_b_hash, + relay_parent: RelayChainBlockInfo { + hash: relay_parent_b_info.hash, + number: 0, + storage_root: relay_parent_b_info.storage_root, + }, + }, + ], + 4, + vec![], + ) + .unwrap(); + let mut chain = FragmentChain::populate(scope, &storage); + assert!(chain.to_vec().is_empty()); + + chain.extend_from_storage(&storage); + assert!(chain.to_vec().is_empty()); + } +} + +#[test] +fn extend_from_storage_with_existing_to_vec() { + let para_id = ParaId::from(5u32); + let relay_parent_a = Hash::repeat_byte(1); + let relay_parent_b = Hash::repeat_byte(2); + let relay_parent_d = Hash::repeat_byte(3); + + let (pvd_a, candidate_a) = make_committed_candidate( + para_id, + relay_parent_a, + 0, + vec![0x0a].into(), + vec![0x0b].into(), + 0, + ); + let candidate_a_hash = candidate_a.hash(); + + let (pvd_b, candidate_b) = make_committed_candidate( + para_id, + relay_parent_b, + 1, + vec![0x0b].into(), + vec![0x0c].into(), + 1, + ); + let candidate_b_hash = candidate_b.hash(); + + let (pvd_c, candidate_c) = make_committed_candidate( + para_id, + // Use the same relay parent number as B to test that it doesn't need to change between + // candidates. + relay_parent_b, + 1, + vec![0x0c].into(), + vec![0x0d].into(), + 1, + ); + let candidate_c_hash = candidate_c.hash(); + + // Candidate D will never be added to the chain. + let (pvd_d, candidate_d) = make_committed_candidate( + para_id, + relay_parent_d, + 2, + vec![0x0e].into(), + vec![0x0f].into(), + 1, + ); + + let relay_parent_a_info = RelayChainBlockInfo { + number: pvd_a.relay_parent_number, + hash: relay_parent_a, + storage_root: pvd_a.relay_parent_storage_root, + }; + let relay_parent_b_info = RelayChainBlockInfo { + number: pvd_b.relay_parent_number, + hash: relay_parent_b, + storage_root: pvd_b.relay_parent_storage_root, + }; + let relay_parent_d_info = RelayChainBlockInfo { + number: pvd_d.relay_parent_number, + hash: relay_parent_d, + storage_root: pvd_d.relay_parent_storage_root, + }; + + let base_constraints = make_constraints(0, vec![0], vec![0x0a].into()); + let pending_availability = Vec::new(); + + let ancestors = vec![ + // These need to be ordered in reverse. + relay_parent_b_info.clone(), + relay_parent_a_info.clone(), + ]; + + // Already had A and C in the storage. Introduce B, which should add both B and C to the chain + // now. + { + let mut storage = CandidateStorage::default(); + storage + .add_candidate(candidate_a.clone(), pvd_a.clone(), CandidateState::Seconded) + .unwrap(); + storage + .add_candidate(candidate_c.clone(), pvd_c.clone(), CandidateState::Seconded) + .unwrap(); + storage + .add_candidate(candidate_d.clone(), pvd_d.clone(), CandidateState::Seconded) + .unwrap(); + + let scope = Scope::with_ancestors( + para_id, + relay_parent_d_info.clone(), + base_constraints.clone(), + pending_availability.clone(), + 4, + ancestors.clone(), + ) + .unwrap(); + let mut chain = FragmentChain::populate(scope, &storage); + assert_eq!(chain.to_vec(), vec![candidate_a_hash]); + + storage + .add_candidate(candidate_b.clone(), pvd_b.clone(), CandidateState::Seconded) + .unwrap(); + chain.extend_from_storage(&storage); + assert_eq!(chain.to_vec(), vec![candidate_a_hash, candidate_b_hash, candidate_c_hash]); + } + + // Already had A and B in the chain. Introduce C. + { + let mut storage = CandidateStorage::default(); + storage + .add_candidate(candidate_a.clone(), pvd_a.clone(), CandidateState::Seconded) + .unwrap(); + storage + .add_candidate(candidate_b.clone(), pvd_b.clone(), CandidateState::Seconded) + .unwrap(); + storage + .add_candidate(candidate_d.clone(), pvd_d.clone(), CandidateState::Seconded) + .unwrap(); + + let scope = Scope::with_ancestors( + para_id, + relay_parent_d_info.clone(), + base_constraints.clone(), + pending_availability.clone(), + 4, + ancestors.clone(), + ) + .unwrap(); + let mut chain = FragmentChain::populate(scope, &storage); + assert_eq!(chain.to_vec(), vec![candidate_a_hash, candidate_b_hash]); + + storage + .add_candidate(candidate_c.clone(), pvd_c.clone(), CandidateState::Seconded) + .unwrap(); + chain.extend_from_storage(&storage); + assert_eq!(chain.to_vec(), vec![candidate_a_hash, candidate_b_hash, candidate_c_hash]); + } +} + +#[test] +fn test_find_ancestor_path_and_find_backable_chain_empty_to_vec() { + 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 chain + let storage = CandidateStorage::default(); + 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 chain = FragmentChain::populate(scope, &storage); + assert!(chain.to_vec().is_empty()); + + assert_eq!(chain.find_ancestor_path(Ancestors::new()), 0); + assert_eq!(chain.find_backable_chain(Ancestors::new(), 2, |_| true), vec![]); + // Invalid candidate. + let ancestors: Ancestors = [CandidateHash::default()].into_iter().collect(); + assert_eq!(chain.find_ancestor_path(ancestors.clone()), 0); + assert_eq!(chain.find_backable_chain(ancestors, 2, |_| true), vec![]); +} + +#[test] +fn test_find_ancestor_path_and_find_backable_to_vec() { + let para_id = ParaId::from(5u32); + let relay_parent = Hash::repeat_byte(1); + let required_parent: HeadData = vec![0xff].into(); + let max_depth = 5; + 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![4].into(), + vec![5].into(), + 0, + )); + + let base_constraints = make_constraints(0, vec![0], required_parent.clone()); + let mut storage = CandidateStorage::default(); + + 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(), CandidateState::Seconded) + .unwrap(); + } + let candidates = candidates.into_iter().map(|(_pvd, candidate)| candidate).collect::>(); + let scope = Scope::with_ancestors( + para_id, + relay_parent_info.clone(), + base_constraints.clone(), + vec![], + max_depth, + vec![], + ) + .unwrap(); + let chain = FragmentChain::populate(scope, &storage); + + assert_eq!(candidates.len(), 6); + assert_eq!(chain.to_vec().len(), 6); + + // No ancestors supplied. + assert_eq!(chain.find_ancestor_path(Ancestors::new()), 0); + assert_eq!(chain.find_backable_chain(Ancestors::new(), 0, |_| true), vec![]); + assert_eq!( + chain.find_backable_chain(Ancestors::new(), 1, |_| true), + [0].into_iter().map(|i| candidates[i].hash()).collect::>() + ); + assert_eq!( + chain.find_backable_chain(Ancestors::new(), 2, |_| true), + [0, 1].into_iter().map(|i| candidates[i].hash()).collect::>() + ); + assert_eq!( + chain.find_backable_chain(Ancestors::new(), 5, |_| true), + [0, 1, 2, 3, 4].into_iter().map(|i| candidates[i].hash()).collect::>() + ); + + for count in 6..10 { + assert_eq!( + chain.find_backable_chain(Ancestors::new(), count, |_| true), + [0, 1, 2, 3, 4, 5].into_iter().map(|i| candidates[i].hash()).collect::>() + ); + } + + assert_eq!( + chain.find_backable_chain(Ancestors::new(), 7, |_| true), + [0, 1, 2, 3, 4, 5].into_iter().map(|i| candidates[i].hash()).collect::>() + ); + assert_eq!( + chain.find_backable_chain(Ancestors::new(), 10, |_| true), + [0, 1, 2, 3, 4, 5].into_iter().map(|i| candidates[i].hash()).collect::>() + ); + + // Ancestor which is not part of the chain. Will be ignored. + let ancestors: Ancestors = [CandidateHash::default()].into_iter().collect(); + assert_eq!(chain.find_ancestor_path(ancestors.clone()), 0); + assert_eq!( + chain.find_backable_chain(ancestors, 4, |_| true), + [0, 1, 2, 3].into_iter().map(|i| candidates[i].hash()).collect::>() + ); + let ancestors: Ancestors = + [candidates[1].hash(), CandidateHash::default()].into_iter().collect(); + assert_eq!(chain.find_ancestor_path(ancestors.clone()), 0); + assert_eq!( + chain.find_backable_chain(ancestors, 4, |_| true), + [0, 1, 2, 3].into_iter().map(|i| candidates[i].hash()).collect::>() + ); + let ancestors: Ancestors = + [candidates[0].hash(), CandidateHash::default()].into_iter().collect(); + assert_eq!(chain.find_ancestor_path(ancestors.clone()), 1); + assert_eq!( + chain.find_backable_chain(ancestors, 4, |_| true), + [1, 2, 3, 4].into_iter().map(|i| candidates[i].hash()).collect::>() + ); + + // Ancestors which are part of the chain but don't form a path from root. Will be ignored. + let ancestors: Ancestors = [candidates[1].hash(), candidates[2].hash()].into_iter().collect(); + assert_eq!(chain.find_ancestor_path(ancestors.clone()), 0); + assert_eq!( + chain.find_backable_chain(ancestors, 4, |_| true), + [0, 1, 2, 3].into_iter().map(|i| candidates[i].hash()).collect::>() + ); + + // Valid ancestors. + let ancestors: Ancestors = [candidates[2].hash(), candidates[0].hash(), candidates[1].hash()] + .into_iter() + .collect(); + assert_eq!(chain.find_ancestor_path(ancestors.clone()), 3); + assert_eq!( + chain.find_backable_chain(ancestors.clone(), 2, |_| true), + [3, 4].into_iter().map(|i| candidates[i].hash()).collect::>() + ); + for count in 3..10 { + assert_eq!( + chain.find_backable_chain(ancestors.clone(), count, |_| true), + [3, 4, 5].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(); + assert_eq!(chain.find_ancestor_path(ancestors.clone()), 1); + assert_eq!( + chain.find_backable_chain(ancestors.clone(), 3, |_| true), + [1, 2, 3].into_iter().map(|i| candidates[i].hash()).collect::>() + ); + assert_eq!( + chain.find_backable_chain(ancestors.clone(), 4, |_| true), + [1, 2, 3, 4].into_iter().map(|i| candidates[i].hash()).collect::>() + ); + for count in 5..10 { + assert_eq!( + chain.find_backable_chain(ancestors.clone(), count, |_| true), + [1, 2, 3, 4, 5].into_iter().map(|i| candidates[i].hash()).collect::>() + ); + } + + let ancestors: Ancestors = [candidates[0].hash(), candidates[1].hash(), candidates[3].hash()] + .into_iter() + .collect(); + assert_eq!(chain.find_ancestor_path(ancestors.clone()), 2); + assert_eq!( + chain.find_backable_chain(ancestors.clone(), 4, |_| true), + [2, 3, 4, 5].into_iter().map(|i| candidates[i].hash()).collect::>() + ); + + // Requested count is 0. + assert_eq!(chain.find_backable_chain(ancestors, 0, |_| true), vec![]); + + // Stop when we've found a candidate for which pred returns false. + let ancestors: Ancestors = [candidates[2].hash(), candidates[0].hash(), candidates[1].hash()] + .into_iter() + .collect(); + for count in 1..10 { + assert_eq!( + // Stop at 4. + chain.find_backable_chain(ancestors.clone(), count, |hash| hash != + &candidates[4].hash()), + [3].into_iter().map(|i| candidates[i].hash()).collect::>() + ); + } + + // Stop when we've found a candidate which is pending availability + { + let scope = Scope::with_ancestors( + para_id, + relay_parent_info.clone(), + base_constraints, + // Mark the third candidate as pending availability + vec![PendingAvailability { + candidate_hash: candidates[3].hash(), + relay_parent: relay_parent_info, + }], + max_depth, + vec![], + ) + .unwrap(); + let chain = FragmentChain::populate(scope, &storage); + let ancestors: Ancestors = + [candidates[0].hash(), candidates[1].hash()].into_iter().collect(); + assert_eq!( + // Stop at 4. + chain.find_backable_chain(ancestors.clone(), 3, |_| true), + [2].into_iter().map(|i| candidates[i].hash()).collect::>() + ); + } +} + +#[test] +fn hypothetical_membership() { + let mut storage = CandidateStorage::default(); + + let para_id = ParaId::from(5u32); + let relay_parent_a = Hash::repeat_byte(1); + + let (pvd_a, candidate_a) = make_committed_candidate( + para_id, + relay_parent_a, + 0, + vec![0x0a].into(), + vec![0x0b].into(), + 0, + ); + let candidate_a_hash = candidate_a.hash(); + + let (pvd_b, candidate_b) = make_committed_candidate( + para_id, + relay_parent_a, + 0, + vec![0x0b].into(), + vec![0x0c].into(), + 0, + ); + let candidate_b_hash = candidate_b.hash(); + + let base_constraints = make_constraints(0, vec![0], vec![0x0a].into()); + + let relay_parent_a_info = RelayChainBlockInfo { + number: pvd_a.relay_parent_number, + hash: relay_parent_a, + storage_root: pvd_a.relay_parent_storage_root, + }; + + let max_depth = 4; + storage.add_candidate(candidate_a, pvd_a, CandidateState::Seconded).unwrap(); + storage.add_candidate(candidate_b, pvd_b, CandidateState::Seconded).unwrap(); + let scope = Scope::with_ancestors( + para_id, + relay_parent_a_info.clone(), + base_constraints.clone(), + vec![], + max_depth, + vec![], + ) + .unwrap(); + let chain = FragmentChain::populate(scope, &storage); + + assert_eq!(chain.to_vec().len(), 2); + + // Check candidates which are already present + assert!(chain.hypothetical_membership( + HypotheticalCandidate::Incomplete { + parent_head_data_hash: HeadData::from(vec![0x0a]).hash(), + candidate_relay_parent: relay_parent_a, + candidate_para: para_id, + candidate_hash: candidate_a_hash, + }, + &storage, + )); + assert!(chain.hypothetical_membership( + HypotheticalCandidate::Incomplete { + parent_head_data_hash: HeadData::from(vec![0x0b]).hash(), + candidate_relay_parent: relay_parent_a, + candidate_para: para_id, + candidate_hash: candidate_b_hash, + }, + &storage, + )); + + // Forks not allowed. + assert!(!chain.hypothetical_membership( + HypotheticalCandidate::Incomplete { + parent_head_data_hash: HeadData::from(vec![0x0a]).hash(), + candidate_relay_parent: relay_parent_a, + candidate_para: para_id, + candidate_hash: CandidateHash(Hash::repeat_byte(21)), + }, + &storage, + )); + assert!(!chain.hypothetical_membership( + HypotheticalCandidate::Incomplete { + parent_head_data_hash: HeadData::from(vec![0x0b]).hash(), + candidate_relay_parent: relay_parent_a, + candidate_para: para_id, + candidate_hash: CandidateHash(Hash::repeat_byte(22)), + }, + &storage, + )); + + // Unknown candidate which builds on top of the current chain. + assert!(chain.hypothetical_membership( + HypotheticalCandidate::Incomplete { + parent_head_data_hash: HeadData::from(vec![0x0c]).hash(), + candidate_relay_parent: relay_parent_a, + candidate_para: para_id, + candidate_hash: CandidateHash(Hash::repeat_byte(23)), + }, + &storage, + )); + + // Unknown unconnected candidate which may be valid. + assert!(chain.hypothetical_membership( + HypotheticalCandidate::Incomplete { + parent_head_data_hash: HeadData::from(vec![0x0e]).hash(), + candidate_relay_parent: relay_parent_a, + candidate_para: para_id, + candidate_hash: CandidateHash(Hash::repeat_byte(23)), + }, + &storage, + )); + + // The number of unconnected candidates is limited (chain.len() + unconnected) <= max_depth + { + // C will be an unconnected candidate. + let (pvd_c, candidate_c) = make_committed_candidate( + para_id, + relay_parent_a, + 0, + vec![0x0e].into(), + vec![0x0f].into(), + 0, + ); + let candidate_c_hash = candidate_c.hash(); + + // Add an invalid candidate in the storage. This would introduce a fork. Just to test that + // it's ignored. + let (invalid_pvd, invalid_candidate) = make_committed_candidate( + para_id, + relay_parent_a, + 1, + vec![0x0a].into(), + vec![0x0b].into(), + 0, + ); + + let scope = Scope::with_ancestors( + para_id, + relay_parent_a_info, + base_constraints, + vec![], + 2, + vec![], + ) + .unwrap(); + let mut storage = storage.clone(); + storage.add_candidate(candidate_c, pvd_c, CandidateState::Seconded).unwrap(); + + let chain = FragmentChain::populate(scope, &storage); + assert_eq!(chain.to_vec(), vec![candidate_a_hash, candidate_b_hash]); + + storage + .add_candidate(invalid_candidate, invalid_pvd, CandidateState::Seconded) + .unwrap(); + + // Check that C is accepted as a potential unconnected candidate. + assert!(!chain.hypothetical_membership( + HypotheticalCandidate::Incomplete { + parent_head_data_hash: HeadData::from(vec![0x0e]).hash(), + candidate_relay_parent: relay_parent_a, + candidate_hash: candidate_c_hash, + candidate_para: para_id + }, + &storage, + )); + + // Since C is already an unconnected candidate in the storage. + assert!(!chain.hypothetical_membership( + HypotheticalCandidate::Incomplete { + parent_head_data_hash: HeadData::from(vec![0x0f]).hash(), + candidate_relay_parent: relay_parent_a, + candidate_para: para_id, + candidate_hash: CandidateHash(Hash::repeat_byte(23)), + }, + &storage, + )); + } +} + +#[test] +fn hypothetical_membership_stricter_on_complete_candidates() { + let storage = CandidateStorage::default(); + + let para_id = ParaId::from(5u32); + let relay_parent_a = Hash::repeat_byte(1); + + let (pvd_a, candidate_a) = make_committed_candidate( + para_id, + relay_parent_a, + 0, + vec![0x0a].into(), + vec![0x0b].into(), + 1000, // watermark is illegal + ); + + let candidate_a_hash = candidate_a.hash(); + + let base_constraints = make_constraints(0, vec![0], vec![0x0a].into()); + let pending_availability = Vec::new(); + + let relay_parent_a_info = RelayChainBlockInfo { + number: pvd_a.relay_parent_number, + hash: relay_parent_a, + storage_root: pvd_a.relay_parent_storage_root, + }; + + let max_depth = 4; + let scope = Scope::with_ancestors( + para_id, + relay_parent_a_info, + base_constraints, + pending_availability, + max_depth, + vec![], + ) + .unwrap(); + let chain = FragmentChain::populate(scope, &storage); + + assert!(chain.hypothetical_membership( + HypotheticalCandidate::Incomplete { + parent_head_data_hash: HeadData::from(vec![0x0a]).hash(), + candidate_relay_parent: relay_parent_a, + candidate_para: para_id, + candidate_hash: candidate_a_hash, + }, + &storage, + )); + + assert!(!chain.hypothetical_membership( + HypotheticalCandidate::Complete { + receipt: Arc::new(candidate_a), + persisted_validation_data: pvd_a, + candidate_hash: candidate_a_hash, + }, + &storage, + )); +} + +#[test] +fn hypothetical_membership_with_pending_availability_in_scope() { + let mut storage = CandidateStorage::default(); + + let para_id = ParaId::from(5u32); + let relay_parent_a = Hash::repeat_byte(1); + let relay_parent_b = Hash::repeat_byte(2); + let relay_parent_c = Hash::repeat_byte(3); + + let (pvd_a, candidate_a) = make_committed_candidate( + para_id, + relay_parent_a, + 0, + vec![0x0a].into(), + vec![0x0b].into(), + 0, + ); + let candidate_a_hash = candidate_a.hash(); + + let (pvd_b, candidate_b) = make_committed_candidate( + para_id, + relay_parent_b, + 1, + vec![0x0b].into(), + vec![0x0c].into(), + 1, + ); + + // Note that relay parent `a` is not allowed. + let base_constraints = make_constraints(1, vec![], vec![0x0a].into()); + + let relay_parent_a_info = RelayChainBlockInfo { + number: pvd_a.relay_parent_number, + hash: relay_parent_a, + storage_root: pvd_a.relay_parent_storage_root, + }; + let pending_availability = vec![PendingAvailability { + candidate_hash: candidate_a_hash, + relay_parent: relay_parent_a_info, + }]; + + let relay_parent_b_info = RelayChainBlockInfo { + number: pvd_b.relay_parent_number, + hash: relay_parent_b, + storage_root: pvd_b.relay_parent_storage_root, + }; + let relay_parent_c_info = RelayChainBlockInfo { + number: pvd_b.relay_parent_number + 1, + hash: relay_parent_c, + storage_root: Hash::zero(), + }; + + let max_depth = 4; + storage.add_candidate(candidate_a, pvd_a, CandidateState::Seconded).unwrap(); + storage.add_candidate(candidate_b, pvd_b, CandidateState::Backed).unwrap(); + storage.mark_backed(&candidate_a_hash); + + let scope = Scope::with_ancestors( + para_id, + relay_parent_c_info, + base_constraints, + pending_availability, + max_depth, + vec![relay_parent_b_info], + ) + .unwrap(); + let chain = FragmentChain::populate(scope, &storage); + + assert_eq!(chain.to_vec().len(), 2); + + let candidate_d_hash = CandidateHash(Hash::repeat_byte(0xAA)); + + assert!(chain.hypothetical_membership( + HypotheticalCandidate::Incomplete { + parent_head_data_hash: HeadData::from(vec![0x0a]).hash(), + candidate_relay_parent: relay_parent_a, + candidate_hash: candidate_a_hash, + candidate_para: para_id + }, + &storage, + )); + + assert!(!chain.hypothetical_membership( + HypotheticalCandidate::Incomplete { + parent_head_data_hash: HeadData::from(vec![0x0a]).hash(), + candidate_relay_parent: relay_parent_c, + candidate_para: para_id, + candidate_hash: candidate_d_hash, + }, + &storage, + )); + + assert!(!chain.hypothetical_membership( + HypotheticalCandidate::Incomplete { + parent_head_data_hash: HeadData::from(vec![0x0b]).hash(), + candidate_relay_parent: relay_parent_c, + candidate_para: para_id, + candidate_hash: candidate_d_hash, + }, + &storage, + )); + + assert!(chain.hypothetical_membership( + HypotheticalCandidate::Incomplete { + parent_head_data_hash: HeadData::from(vec![0x0c]).hash(), + candidate_relay_parent: relay_parent_b, + candidate_para: para_id, + candidate_hash: candidate_d_hash, + }, + &storage, + )); +} diff --git a/polkadot/node/core/prospective-parachains/src/fragment_tree.rs b/polkadot/node/core/prospective-parachains/src/fragment_tree.rs deleted file mode 100644 index 8061dc82d8358ae9e7c741e3f785634601eb5d03..0000000000000000000000000000000000000000 --- a/polkadot/node/core/prospective-parachains/src/fragment_tree.rs +++ /dev/null @@ -1,2591 +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 tree utility for managing parachain fragments not referenced by the relay-chain. -//! -//! # Overview -//! -//! This module exposes two main types: [`FragmentTree`] and [`CandidateStorage`] which are meant to -//! be used in close conjunction. Each fragment tree is associated with a particular relay-parent -//! and each node in the tree represents a candidate. Each parachain has a single candidate storage, -//! but can have multiple trees for each relay chain block in the view. -//! -//! A tree has an associated [`Scope`] which defines limits on candidates within the tree. -//! Candidates themselves have their own [`Constraints`] which are either the constraints from the -//! scope, or, if there are previous nodes in the tree, a modified version of the previous -//! candidate's constraints. -//! -//! This module also makes use of types provided by the Inclusion Emulator module, such as -//! [`Fragment`] and [`Constraints`]. These perform the actual job of checking for validity of -//! prospective fragments. -//! -//! # Usage -//! -//! It's expected that higher-level code will have a tree for each relay-chain block which might -//! reasonably have blocks built upon it. -//! -//! Because a para only has a single candidate storage, trees only store indices into the storage. -//! The storage is meant to be pruned when trees are dropped by higher-level code. -//! -//! # Cycles -//! -//! Nodes do not uniquely refer to a parachain block for two reasons. -//! 1. There's no requirement that head-data is unique for a parachain. Furthermore, a parachain -//! is under no obligation to be acyclic, and this is mostly just because it's totally -//! inefficient to enforce it. Practical use-cases are acyclic, but there is still more than -//! one way to reach the same head-data. -//! 2. and candidates only refer to their parent by its head-data. This whole issue could be -//! resolved by having candidates reference their parent by candidate hash. -//! -//! The implication is that when we receive a candidate receipt, there are actually multiple -//! possibilities for any candidates between the para-head recorded in the relay parent's state -//! and the candidate in question. -//! -//! This means that our candidates need to handle multiple parents and that depth is an -//! attribute of a node in a tree, not a candidate. Put another way, the same candidate might -//! have different depths in different parts of the tree. -//! -//! As an extreme example, a candidate which produces head-data which is the same as its parent -//! can correspond to multiple nodes within the same [`FragmentTree`]. Such cycles are bounded -//! by the maximum depth allowed by the tree. An example with `max_depth: 4`: -//! -//! ```text -//! committed head -//! | -//! depth 0: head_a -//! | -//! depth 1: head_b -//! | -//! depth 2: head_a -//! | -//! depth 3: head_b -//! | -//! depth 4: head_a -//! ``` -//! -//! As long as the [`CandidateStorage`] has bounded input on the number of candidates supplied, -//! [`FragmentTree`] complexity is bounded. This means that higher-level code needs to be selective -//! about limiting the amount of candidates that are considered. -//! -//! The code in this module is not designed for speed or efficiency, but conceptual simplicity. -//! Our assumption is that the amount of candidates and parachains we consider will be reasonably -//! bounded and in practice will not exceed a few thousand at any time. This naive implementation -//! will still perform fairly well under these conditions, despite being somewhat wasteful of -//! memory. - -use std::{ - borrow::Cow, - collections::{ - hash_map::{Entry, HashMap}, - BTreeMap, HashSet, - }, -}; - -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, -}; -use polkadot_primitives::{ - BlockNumber, CandidateHash, CommittedCandidateReceipt, Hash, HeadData, Id as ParaId, - PersistedValidationData, -}; - -/// Kinds of failures to import a candidate into storage. -#[derive(Debug, Clone, PartialEq)] -pub enum CandidateStorageInsertionError { - /// An error indicating that a supplied candidate didn't match the persisted - /// validation data provided alongside it. - PersistedValidationDataMismatch, - /// The candidate was already known. - CandidateAlreadyKnown(CandidateHash), -} - -/// Stores candidates and information about them such as their relay-parents and their backing -/// states. -pub(crate) struct CandidateStorage { - // Index from head data hash to candidate hashes with that head data as a parent. - by_parent_head: HashMap>, - - // Index from head data hash to candidate hashes outputting that head data. - by_output_head: HashMap>, - - // Index from candidate hash to fragment node. - by_candidate_hash: HashMap, -} - -impl CandidateStorage { - /// Create a new `CandidateStorage`. - pub fn new() -> Self { - CandidateStorage { - by_parent_head: HashMap::new(), - by_output_head: HashMap::new(), - by_candidate_hash: HashMap::new(), - } - } - - /// Introduce a new candidate. - pub fn add_candidate( - &mut self, - candidate: CommittedCandidateReceipt, - persisted_validation_data: PersistedValidationData, - ) -> Result { - let candidate_hash = candidate.hash(); - - if self.by_candidate_hash.contains_key(&candidate_hash) { - return Err(CandidateStorageInsertionError::CandidateAlreadyKnown(candidate_hash)) - } - - if persisted_validation_data.hash() != candidate.descriptor.persisted_validation_data_hash { - return Err(CandidateStorageInsertionError::PersistedValidationDataMismatch) - } - - let parent_head_hash = persisted_validation_data.parent_head.hash(); - let output_head_hash = candidate.commitments.head_data.hash(); - let entry = CandidateEntry { - candidate_hash, - relay_parent: candidate.descriptor.relay_parent, - state: CandidateState::Introduced, - candidate: ProspectiveCandidate { - commitments: Cow::Owned(candidate.commitments), - collator: candidate.descriptor.collator, - collator_signature: candidate.descriptor.signature, - persisted_validation_data, - pov_hash: candidate.descriptor.pov_hash, - validation_code_hash: candidate.descriptor.validation_code_hash, - }, - }; - - self.by_parent_head.entry(parent_head_hash).or_default().insert(candidate_hash); - self.by_output_head.entry(output_head_hash).or_default().insert(candidate_hash); - // sanity-checked already. - self.by_candidate_hash.insert(candidate_hash, entry); - - Ok(candidate_hash) - } - - /// Remove a candidate from the store. - pub fn remove_candidate(&mut self, candidate_hash: &CandidateHash) { - if let Some(entry) = self.by_candidate_hash.remove(candidate_hash) { - let parent_head_hash = entry.candidate.persisted_validation_data.parent_head.hash(); - if let Entry::Occupied(mut e) = self.by_parent_head.entry(parent_head_hash) { - e.get_mut().remove(&candidate_hash); - if e.get().is_empty() { - e.remove(); - } - } - } - } - - /// Note that an existing candidate has been seconded. - pub fn mark_seconded(&mut self, candidate_hash: &CandidateHash) { - if let Some(entry) = self.by_candidate_hash.get_mut(candidate_hash) { - if entry.state != CandidateState::Backed { - entry.state = CandidateState::Seconded; - } - } - } - - /// Note that an existing candidate has been backed. - pub fn mark_backed(&mut self, candidate_hash: &CandidateHash) { - if let Some(entry) = self.by_candidate_hash.get_mut(candidate_hash) { - gum::trace!(target: LOG_TARGET, ?candidate_hash, "Candidate marked as backed"); - entry.state = CandidateState::Backed; - } else { - gum::trace!(target: LOG_TARGET, ?candidate_hash, "Candidate not found while marking as backed"); - } - } - - /// Whether a candidate is recorded as being backed. - pub fn is_backed(&self, candidate_hash: &CandidateHash) -> bool { - self.by_candidate_hash - .get(candidate_hash) - .map_or(false, |e| e.state == CandidateState::Backed) - } - - /// Whether a candidate is contained within the storage already. - pub fn contains(&self, candidate_hash: &CandidateHash) -> bool { - self.by_candidate_hash.contains_key(candidate_hash) - } - - /// Retain only candidates which pass the predicate. - pub(crate) fn retain(&mut self, pred: impl Fn(&CandidateHash) -> bool) { - self.by_candidate_hash.retain(|h, _v| pred(h)); - self.by_parent_head.retain(|_parent, children| { - children.retain(|h| pred(h)); - !children.is_empty() - }); - self.by_output_head.retain(|_output, candidates| { - candidates.retain(|h| pred(h)); - !candidates.is_empty() - }); - } - - /// Get head-data by hash. - pub(crate) fn head_data_by_hash(&self, hash: &Hash) -> Option<&HeadData> { - // First, search for candidates outputting this head data and extract the head data - // from their commitments if they exist. - // - // Otherwise, search for candidates building upon this head data and extract the head data - // from their persisted validation data if they exist. - self.by_output_head - .get(hash) - .and_then(|m| m.iter().next()) - .and_then(|a_candidate| self.by_candidate_hash.get(a_candidate)) - .map(|e| &e.candidate.commitments.head_data) - .or_else(|| { - self.by_parent_head - .get(hash) - .and_then(|m| m.iter().next()) - .and_then(|a_candidate| self.by_candidate_hash.get(a_candidate)) - .map(|e| &e.candidate.persisted_validation_data.parent_head) - }) - } - - /// Returns candidate's relay parent, if present. - pub(crate) fn relay_parent_by_candidate_hash( - &self, - candidate_hash: &CandidateHash, - ) -> Option { - self.by_candidate_hash.get(candidate_hash).map(|entry| entry.relay_parent) - } - - fn iter_para_children<'a>( - &'a self, - parent_head_hash: &Hash, - ) -> impl Iterator + 'a { - let by_candidate_hash = &self.by_candidate_hash; - self.by_parent_head - .get(parent_head_hash) - .into_iter() - .flat_map(|hashes| hashes.iter()) - .filter_map(move |h| by_candidate_hash.get(h)) - } - - fn get(&'_ self, candidate_hash: &CandidateHash) -> Option<&'_ CandidateEntry> { - self.by_candidate_hash.get(candidate_hash) - } - - #[cfg(test)] - pub fn len(&self) -> (usize, usize) { - (self.by_parent_head.len(), self.by_candidate_hash.len()) - } -} - -/// The state of a candidate. -/// -/// Candidates aren't even considered until they've at least been seconded. -#[derive(Debug, PartialEq)] -enum CandidateState { - /// The candidate has been introduced in a spam-protected way but - /// is not necessarily backed. - Introduced, - /// The candidate has been seconded. - Seconded, - /// The candidate has been completely backed by the group. - Backed, -} - -#[derive(Debug)] -struct CandidateEntry { - candidate_hash: CandidateHash, - relay_parent: Hash, - candidate: ProspectiveCandidate<'static>, - state: CandidateState, -} - -/// A candidate existing on-chain but pending availability, for special treatment -/// in the [`Scope`]. -#[derive(Debug, Clone)] -pub(crate) struct PendingAvailability { - /// The candidate hash. - pub candidate_hash: CandidateHash, - /// The block info of the relay parent. - pub relay_parent: RelayChainBlockInfo, -} - -/// The scope of a [`FragmentTree`]. -#[derive(Debug)] -pub(crate) struct Scope { - para: ParaId, - relay_parent: RelayChainBlockInfo, - ancestors: BTreeMap, - ancestors_by_hash: HashMap, - pending_availability: Vec, - base_constraints: Constraints, - max_depth: usize, -} - -/// An error variant indicating that ancestors provided to a scope -/// had unexpected order. -#[derive(Debug)] -pub struct UnexpectedAncestor { - /// The block number that this error occurred at. - pub number: BlockNumber, - /// The previous seen block number, which did not match `number`. - pub prev: BlockNumber, -} - -impl Scope { - /// Define a new [`Scope`]. - /// - /// All arguments are straightforward except the ancestors. - /// - /// Ancestors should be in reverse order, starting with the parent - /// of the `relay_parent`, and proceeding backwards in block number - /// increments of 1. Ancestors not following these conditions will be - /// rejected. - /// - /// This function will only consume ancestors up to the `min_relay_parent_number` of - /// the `base_constraints`. - /// - /// Only ancestors whose children have the same session as the relay-parent's - /// children should be provided. - /// - /// It is allowed to provide zero ancestors. - pub fn with_ancestors( - para: ParaId, - relay_parent: RelayChainBlockInfo, - base_constraints: Constraints, - pending_availability: Vec, - max_depth: usize, - ancestors: impl IntoIterator, - ) -> Result { - let mut ancestors_map = BTreeMap::new(); - let mut ancestors_by_hash = HashMap::new(); - { - let mut prev = relay_parent.number; - for ancestor in ancestors { - if prev == 0 { - return Err(UnexpectedAncestor { number: ancestor.number, prev }) - } else if ancestor.number != prev - 1 { - return Err(UnexpectedAncestor { number: ancestor.number, prev }) - } else if prev == base_constraints.min_relay_parent_number { - break - } else { - prev = ancestor.number; - ancestors_by_hash.insert(ancestor.hash, ancestor.clone()); - ancestors_map.insert(ancestor.number, ancestor); - } - } - } - - Ok(Scope { - para, - relay_parent, - base_constraints, - pending_availability, - max_depth, - ancestors: ancestors_map, - ancestors_by_hash, - }) - } - - /// Get the earliest relay-parent allowed in the scope of the fragment tree. - pub fn earliest_relay_parent(&self) -> RelayChainBlockInfo { - self.ancestors - .iter() - .next() - .map(|(_, v)| v.clone()) - .unwrap_or_else(|| self.relay_parent.clone()) - } - - /// Get the ancestor of the fragment tree by hash. - pub fn ancestor_by_hash(&self, hash: &Hash) -> Option { - if hash == &self.relay_parent.hash { - return Some(self.relay_parent.clone()) - } - - self.ancestors_by_hash.get(hash).map(|info| info.clone()) - } - - /// Whether the candidate in question is one pending availability in this scope. - pub fn get_pending_availability( - &self, - candidate_hash: &CandidateHash, - ) -> Option<&PendingAvailability> { - self.pending_availability.iter().find(|c| &c.candidate_hash == candidate_hash) - } - - /// Get the base constraints of the scope - pub fn base_constraints(&self) -> &Constraints { - &self.base_constraints - } -} - -/// We use indices into a flat vector to refer to nodes in the tree. -/// Every tree also has an implicit root. -#[derive(Debug, Clone, Copy, PartialEq)] -enum NodePointer { - Root, - Storage(usize), -} - -/// A hypothetical candidate, which may or may not exist in -/// the fragment tree already. -pub(crate) enum HypotheticalCandidate<'a> { - Complete { - receipt: Cow<'a, CommittedCandidateReceipt>, - persisted_validation_data: Cow<'a, PersistedValidationData>, - }, - Incomplete { - relay_parent: Hash, - parent_head_data_hash: Hash, - }, -} - -impl<'a> HypotheticalCandidate<'a> { - fn parent_head_data_hash(&self) -> Hash { - match *self { - HypotheticalCandidate::Complete { ref persisted_validation_data, .. } => - persisted_validation_data.as_ref().parent_head.hash(), - HypotheticalCandidate::Incomplete { ref parent_head_data_hash, .. } => - *parent_head_data_hash, - } - } - - fn relay_parent(&self) -> Hash { - match *self { - HypotheticalCandidate::Complete { ref receipt, .. } => - receipt.descriptor().relay_parent, - HypotheticalCandidate::Incomplete { ref relay_parent, .. } => *relay_parent, - } - } -} - -/// This is a tree of candidates based on some underlying storage of candidates and a scope. -/// -/// All nodes in the tree must be either pending availability or within the scope. Within the scope -/// means it's built off of the relay-parent or an ancestor. -pub(crate) struct FragmentTree { - scope: Scope, - - // Invariant: a contiguous prefix of the 'nodes' storage will contain - // the top-level children. - nodes: Vec, - - // The candidates stored in this tree, mapped to a bitvec indicating the depths - // where the candidate is stored. - candidates: HashMap>, -} - -impl FragmentTree { - /// Create a new [`FragmentTree`] with given scope and populated from the storage. - /// - /// Can be populated recursively (i.e. `populate` will pick up candidates that build on other - /// candidates). - pub fn populate(scope: Scope, storage: &CandidateStorage) -> Self { - gum::trace!( - target: LOG_TARGET, - relay_parent = ?scope.relay_parent.hash, - relay_parent_num = scope.relay_parent.number, - para_id = ?scope.para, - ancestors = scope.ancestors.len(), - "Instantiating Fragment Tree", - ); - - let mut tree = FragmentTree { scope, nodes: Vec::new(), candidates: HashMap::new() }; - - tree.populate_from_bases(storage, vec![NodePointer::Root]); - - tree - } - - /// Get the scope of the Fragment Tree. - pub fn scope(&self) -> &Scope { - &self.scope - } - - // Inserts a node and updates child references in a non-root parent. - fn insert_node(&mut self, node: FragmentNode) { - let pointer = NodePointer::Storage(self.nodes.len()); - let parent_pointer = node.parent; - let candidate_hash = node.candidate_hash; - - let max_depth = self.scope.max_depth; - - self.candidates - .entry(candidate_hash) - .or_insert_with(|| bitvec![u16, Msb0; 0; max_depth + 1]) - .set(node.depth, true); - - match parent_pointer { - NodePointer::Storage(ptr) => { - self.nodes.push(node); - self.nodes[ptr].children.push((pointer, candidate_hash)) - }, - NodePointer::Root => { - // Maintain the invariant of node storage beginning with depth-0. - if self.nodes.last().map_or(true, |last| last.parent == NodePointer::Root) { - self.nodes.push(node); - } else { - let pos = - self.nodes.iter().take_while(|n| n.parent == NodePointer::Root).count(); - self.nodes.insert(pos, node); - } - }, - } - } - - fn node_has_candidate_child( - &self, - pointer: NodePointer, - candidate_hash: &CandidateHash, - ) -> bool { - self.node_candidate_child(pointer, candidate_hash).is_some() - } - - fn node_candidate_child( - &self, - pointer: NodePointer, - candidate_hash: &CandidateHash, - ) -> Option { - match pointer { - NodePointer::Root => self - .nodes - .iter() - .take_while(|n| n.parent == NodePointer::Root) - .enumerate() - .find(|(_, n)| &n.candidate_hash == candidate_hash) - .map(|(i, _)| NodePointer::Storage(i)), - NodePointer::Storage(ptr) => - self.nodes.get(ptr).and_then(|n| n.candidate_child(candidate_hash)), - } - } - - /// Returns an O(n) iterator over the hashes of candidates contained in the - /// tree. - pub(crate) fn candidates(&self) -> impl Iterator + '_ { - self.candidates.keys().cloned() - } - - /// Whether the candidate exists and at what depths. - pub(crate) fn candidate(&self, candidate: &CandidateHash) -> Option> { - self.candidates.get(candidate).map(|d| d.iter_ones().collect()) - } - - /// Add a candidate and recursively populate from storage. - /// - /// Candidates can be added either as children of the root or children of other candidates. - pub(crate) fn add_and_populate(&mut self, hash: CandidateHash, storage: &CandidateStorage) { - let candidate_entry = match storage.get(&hash) { - None => return, - Some(e) => e, - }; - - let candidate_parent = &candidate_entry.candidate.persisted_validation_data.parent_head; - - // Select an initial set of bases, whose required relay-parent matches that of the - // candidate. - let root_base = if &self.scope.base_constraints.required_parent == candidate_parent { - Some(NodePointer::Root) - } else { - None - }; - - let non_root_bases = self - .nodes - .iter() - .enumerate() - .filter(|(_, n)| { - n.cumulative_modifications.required_parent.as_ref() == Some(candidate_parent) - }) - .map(|(i, _)| NodePointer::Storage(i)); - - let bases = root_base.into_iter().chain(non_root_bases).collect(); - - // Pass this into the population function, which will sanity-check stuff like depth, - // fragments, etc. and then recursively populate. - self.populate_from_bases(storage, bases); - } - - /// Returns `true` if the path from the root to the node's parent (inclusive) - /// only contains backed candidates, `false` otherwise. - fn path_contains_backed_only_candidates( - &self, - mut parent_pointer: NodePointer, - candidate_storage: &CandidateStorage, - ) -> bool { - while let NodePointer::Storage(ptr) = parent_pointer { - let node = &self.nodes[ptr]; - let candidate_hash = &node.candidate_hash; - - if candidate_storage.get(candidate_hash).map_or(true, |candidate_entry| { - !matches!(candidate_entry.state, CandidateState::Backed) - }) { - return false - } - parent_pointer = node.parent; - } - - true - } - - /// Returns the hypothetical depths where a candidate with the given hash and parent head data - /// would be added to the tree, without applying other candidates recursively on top of it. - /// - /// If the candidate is already known, this returns the actual depths where this - /// candidate is part of the tree. - /// - /// Setting `backed_in_path_only` to `true` ensures this function only returns such membership - /// that every candidate in the path from the root is backed. - pub(crate) fn hypothetical_depths( - &self, - hash: CandidateHash, - candidate: HypotheticalCandidate, - candidate_storage: &CandidateStorage, - backed_in_path_only: bool, - ) -> Vec { - // if `true`, we always have to traverse the tree. - if !backed_in_path_only { - // if known. - if let Some(depths) = self.candidates.get(&hash) { - return depths.iter_ones().collect() - } - } - - // if out of scope. - let candidate_relay_parent = candidate.relay_parent(); - let candidate_relay_parent = if self.scope.relay_parent.hash == candidate_relay_parent { - self.scope.relay_parent.clone() - } else if let Some(info) = self.scope.ancestors_by_hash.get(&candidate_relay_parent) { - info.clone() - } else { - return Vec::new() - }; - - let max_depth = self.scope.max_depth; - let mut depths = bitvec![u16, Msb0; 0; max_depth + 1]; - - // iterate over all nodes where parent head-data matches, - // relay-parent number is <= candidate, and depth < max_depth. - let node_pointers = (0..self.nodes.len()).map(NodePointer::Storage); - for parent_pointer in std::iter::once(NodePointer::Root).chain(node_pointers) { - let (modifications, child_depth, earliest_rp) = match parent_pointer { - NodePointer::Root => - (ConstraintModifications::identity(), 0, self.scope.earliest_relay_parent()), - NodePointer::Storage(ptr) => { - let node = &self.nodes[ptr]; - let parent_rp = self - .scope - .ancestor_by_hash(&node.relay_parent()) - .or_else(|| { - self.scope - .get_pending_availability(&node.candidate_hash) - .map(|_| self.scope.earliest_relay_parent()) - }) - .expect("All nodes in tree are either pending availability or within scope; qed"); - - (node.cumulative_modifications.clone(), node.depth + 1, parent_rp) - }, - }; - - if child_depth > max_depth { - continue - } - - if earliest_rp.number > candidate_relay_parent.number { - continue - } - - let child_constraints = - match self.scope.base_constraints.apply_modifications(&modifications) { - Err(e) => { - gum::debug!( - target: LOG_TARGET, - new_parent_head = ?modifications.required_parent, - err = ?e, - "Failed to apply modifications", - ); - - continue - }, - Ok(c) => c, - }; - - let parent_head_hash = candidate.parent_head_data_hash(); - if parent_head_hash != child_constraints.required_parent.hash() { - continue - } - - // We do additional checks for complete candidates. - if let HypotheticalCandidate::Complete { ref receipt, ref persisted_validation_data } = - candidate - { - let prospective_candidate = ProspectiveCandidate { - commitments: Cow::Borrowed(&receipt.commitments), - collator: receipt.descriptor().collator.clone(), - collator_signature: receipt.descriptor().signature.clone(), - persisted_validation_data: persisted_validation_data.as_ref().clone(), - pov_hash: receipt.descriptor().pov_hash, - validation_code_hash: receipt.descriptor().validation_code_hash, - }; - - if Fragment::new( - candidate_relay_parent.clone(), - child_constraints, - prospective_candidate, - ) - .is_err() - { - continue - } - } - - // Check that the path only contains backed candidates, if necessary. - if !backed_in_path_only || - self.path_contains_backed_only_candidates(parent_pointer, candidate_storage) - { - depths.set(child_depth, true); - } - } - - depths.iter_ones().collect() - } - - /// 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 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 `ancestors` is to allow queries on the basis of - /// one or more candidates which were previously pending availability becoming - /// available or candidates timing out. - pub(crate) fn find_backable_chain( - &self, - ancestors: Ancestors, - count: u32, - pred: impl Fn(&CandidateHash) -> bool, - ) -> 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`. - // If not possible, return the longest one we could find. - // Does a depth-first search, since we're optimistic that there won't be more than one such - // chains (parachains shouldn't usually have forks). So in the usual case, this will conclude - // in `O(expected_count)`. - // 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)`, 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` - // (because each validator in the assigned group can second `max_candidate_depth` - // candidates). The prospective-parachains subsystem assumes that the number of para forks is - // limited by collator-protocol and backing subsystems. In practice, this is a constant which - // can only be altered by sudo or governance. - // 2. `expected_count` is equal to the number of cores a para is scheduled on (in an elastic - // 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 find_backable_chain_inner( - &self, - base_node: NodePointer, - expected_count: u32, - remaining_count: u32, - pred: &dyn Fn(&CandidateHash) -> bool, - accumulator: &mut Vec, - ) -> Vec { - if remaining_count == 0 { - // The best option is the chain we've accumulated so far. - return accumulator.to_vec(); - } - - let children: Vec<_> = match base_node { - NodePointer::Root => self - .nodes - .iter() - .enumerate() - .take_while(|(_, n)| n.parent == NodePointer::Root) - .filter(|(_, n)| self.scope.get_pending_availability(&n.candidate_hash).is_none()) - .filter(|(_, n)| pred(&n.candidate_hash)) - .map(|(ptr, n)| (NodePointer::Storage(ptr), n.candidate_hash)) - .collect(), - NodePointer::Storage(base_node_ptr) => { - let base_node = &self.nodes[base_node_ptr]; - - base_node - .children - .iter() - .filter(|(_, hash)| self.scope.get_pending_availability(&hash).is_none()) - .filter(|(_, hash)| pred(&hash)) - .map(|(ptr, hash)| (*ptr, *hash)) - .collect() - }, - }; - - let mut best_result = accumulator.clone(); - for (child_ptr, child_hash) in children { - accumulator.push(child_hash); - - let result = self.find_backable_chain_inner( - child_ptr, - expected_count, - remaining_count - 1, - &pred, - accumulator, - ); - - accumulator.pop(); - - // 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() { - best_result = result; - } - } - - 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; - - loop { - let sweep_start = self.nodes.len(); - - if Some(sweep_start) == last_sweep_start { - break - } - - let parents: Vec = if let Some(last_start) = last_sweep_start { - (last_start..self.nodes.len()).map(NodePointer::Storage).collect() - } else { - initial_bases.clone() - }; - - // 1. get parent head and find constraints - // 2. iterate all candidates building on the right head and viable relay parent - // 3. add new node - for parent_pointer in parents { - let (modifications, child_depth, earliest_rp) = match parent_pointer { - NodePointer::Root => - (ConstraintModifications::identity(), 0, self.scope.earliest_relay_parent()), - NodePointer::Storage(ptr) => { - let node = &self.nodes[ptr]; - let parent_rp = self - .scope - .ancestor_by_hash(&node.relay_parent()) - .or_else(|| { - // if the relay-parent is out of scope _and_ it is in the tree, - // it must be a candidate pending availability. - self.scope - .get_pending_availability(&node.candidate_hash) - .map(|c| c.relay_parent.clone()) - }) - .expect("All nodes in tree are either pending availability or within scope; qed"); - - (node.cumulative_modifications.clone(), node.depth + 1, parent_rp) - }, - }; - - if child_depth > self.scope.max_depth { - continue - } - - let child_constraints = - match self.scope.base_constraints.apply_modifications(&modifications) { - Err(e) => { - gum::debug!( - target: LOG_TARGET, - new_parent_head = ?modifications.required_parent, - err = ?e, - "Failed to apply modifications", - ); - - continue - }, - Ok(c) => c, - }; - - // Add nodes to tree wherever - // 1. parent hash is correct - // 2. relay-parent does not move backwards. - // 3. all non-pending-availability candidates have relay-parent in scope. - // 4. candidate outputs fulfill constraints - let required_head_hash = child_constraints.required_parent.hash(); - for candidate in storage.iter_para_children(&required_head_hash) { - let pending = self.scope.get_pending_availability(&candidate.candidate_hash); - let relay_parent = pending - .map(|p| p.relay_parent.clone()) - .or_else(|| self.scope.ancestor_by_hash(&candidate.relay_parent)); - - let relay_parent = match relay_parent { - Some(r) => r, - None => continue, - }; - - // require: pending availability candidates don't move backwards - // and only those can be out-of-scope. - // - // earliest_rp can be before the earliest relay parent in the scope - // when the parent is a pending availability candidate as well, but - // only other pending candidates can have a relay parent out of scope. - let min_relay_parent_number = pending - .map(|p| match parent_pointer { - NodePointer::Root => p.relay_parent.number, - NodePointer::Storage(_) => earliest_rp.number, - }) - .unwrap_or_else(|| { - std::cmp::max( - earliest_rp.number, - self.scope.earliest_relay_parent().number, - ) - }); - - if relay_parent.number < min_relay_parent_number { - continue // relay parent moved backwards. - } - - // don't add candidates where the parent already has it as a child. - if self.node_has_candidate_child(parent_pointer, &candidate.candidate_hash) { - continue - } - - let fragment = { - let mut constraints = child_constraints.clone(); - if let Some(ref p) = pending { - // overwrite for candidates pending availability as a special-case. - constraints.min_relay_parent_number = p.relay_parent.number; - } - - let f = Fragment::new( - relay_parent.clone(), - constraints, - candidate.candidate.partial_clone(), - ); - - match f { - Ok(f) => f.into_owned(), - Err(e) => { - gum::debug!( - target: LOG_TARGET, - err = ?e, - ?relay_parent, - candidate_hash = ?candidate.candidate_hash, - "Failed to instantiate fragment", - ); - - continue - }, - } - }; - - let mut cumulative_modifications = modifications.clone(); - cumulative_modifications.stack(fragment.constraint_modifications()); - - let node = FragmentNode { - parent: parent_pointer, - fragment, - candidate_hash: candidate.candidate_hash, - depth: child_depth, - cumulative_modifications, - children: Vec::new(), - }; - - self.insert_node(node); - } - } - - last_sweep_start = Some(sweep_start); - } - } -} - -struct FragmentNode { - // A pointer to the parent node. - parent: NodePointer, - fragment: Fragment<'static>, - candidate_hash: CandidateHash, - depth: usize, - cumulative_modifications: ConstraintModifications, - children: Vec<(NodePointer, CandidateHash)>, -} - -impl FragmentNode { - fn relay_parent(&self) -> Hash { - self.fragment.relay_parent().hash - } - - fn candidate_child(&self, candidate_hash: &CandidateHash) -> Option { - self.children.iter().find(|(_, c)| c == candidate_hash).map(|(p, _)| *p) - } -} - -#[cfg(test)] -mod tests { - use super::*; - use assert_matches::assert_matches; - 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, - required_parent: HeadData, - ) -> Constraints { - Constraints { - min_relay_parent_number, - max_pov_size: 1_000_000, - max_code_size: 1_000_000, - ump_remaining: 10, - ump_remaining_bytes: 1_000, - max_ump_num_per_candidate: 10, - dmp_remaining_messages: [0; 10].into(), - hrmp_inbound: InboundHrmpLimitations { valid_watermarks }, - hrmp_channels_out: HashMap::new(), - max_hrmp_num_per_candidate: 0, - required_parent, - validation_code_hash: Hash::repeat_byte(42).into(), - upgrade_restriction: None, - future_validation_code: None, - } - } - - fn make_committed_candidate( - para_id: ParaId, - relay_parent: Hash, - relay_parent_number: BlockNumber, - parent_head: HeadData, - para_head: HeadData, - hrmp_watermark: BlockNumber, - ) -> (PersistedValidationData, CommittedCandidateReceipt) { - let persisted_validation_data = PersistedValidationData { - parent_head, - relay_parent_number, - relay_parent_storage_root: Hash::repeat_byte(69), - max_pov_size: 1_000_000, - }; - - let candidate = CommittedCandidateReceipt { - descriptor: CandidateDescriptor { - para_id, - relay_parent, - collator: test_helpers::dummy_collator(), - persisted_validation_data_hash: persisted_validation_data.hash(), - pov_hash: Hash::repeat_byte(1), - erasure_root: Hash::repeat_byte(1), - signature: test_helpers::dummy_collator_signature(), - para_head: para_head.hash(), - validation_code_hash: Hash::repeat_byte(42).into(), - }, - commitments: CandidateCommitments { - upward_messages: Default::default(), - horizontal_messages: Default::default(), - new_validation_code: None, - head_data: para_head, - processed_downward_messages: 1, - hrmp_watermark, - }, - }; - - (persisted_validation_data, candidate) - } - - #[test] - fn scope_rejects_ancestors_that_skip_blocks() { - let para_id = ParaId::from(5u32); - let relay_parent = RelayChainBlockInfo { - number: 10, - hash: Hash::repeat_byte(10), - storage_root: Hash::repeat_byte(69), - }; - - let ancestors = vec![RelayChainBlockInfo { - number: 8, - hash: Hash::repeat_byte(8), - storage_root: Hash::repeat_byte(69), - }]; - - let max_depth = 2; - let base_constraints = make_constraints(8, vec![8, 9], vec![1, 2, 3].into()); - let pending_availability = Vec::new(); - - assert_matches!( - Scope::with_ancestors( - para_id, - relay_parent, - base_constraints, - pending_availability, - max_depth, - ancestors - ), - Err(UnexpectedAncestor { number: 8, prev: 10 }) - ); - } - - #[test] - fn scope_rejects_ancestor_for_0_block() { - let para_id = ParaId::from(5u32); - let relay_parent = RelayChainBlockInfo { - number: 0, - hash: Hash::repeat_byte(0), - storage_root: Hash::repeat_byte(69), - }; - - let ancestors = vec![RelayChainBlockInfo { - number: 99999, - hash: Hash::repeat_byte(99), - storage_root: Hash::repeat_byte(69), - }]; - - let max_depth = 2; - let base_constraints = make_constraints(0, vec![], vec![1, 2, 3].into()); - let pending_availability = Vec::new(); - - assert_matches!( - Scope::with_ancestors( - para_id, - relay_parent, - base_constraints, - pending_availability, - max_depth, - ancestors, - ), - Err(UnexpectedAncestor { number: 99999, prev: 0 }) - ); - } - - #[test] - fn scope_only_takes_ancestors_up_to_min() { - let para_id = ParaId::from(5u32); - let relay_parent = RelayChainBlockInfo { - number: 5, - hash: Hash::repeat_byte(0), - storage_root: Hash::repeat_byte(69), - }; - - let ancestors = vec![ - RelayChainBlockInfo { - number: 4, - hash: Hash::repeat_byte(4), - storage_root: Hash::repeat_byte(69), - }, - RelayChainBlockInfo { - number: 3, - hash: Hash::repeat_byte(3), - storage_root: Hash::repeat_byte(69), - }, - RelayChainBlockInfo { - number: 2, - hash: Hash::repeat_byte(2), - storage_root: Hash::repeat_byte(69), - }, - ]; - - let max_depth = 2; - let base_constraints = make_constraints(3, vec![2], vec![1, 2, 3].into()); - let pending_availability = Vec::new(); - - let scope = Scope::with_ancestors( - para_id, - relay_parent, - base_constraints, - pending_availability, - max_depth, - ancestors, - ) - .unwrap(); - - assert_eq!(scope.ancestors.len(), 2); - assert_eq!(scope.ancestors_by_hash.len(), 2); - } - - #[test] - fn storage_add_candidate() { - let mut storage = CandidateStorage::new(); - let relay_parent = Hash::repeat_byte(69); - - let (pvd, candidate) = make_committed_candidate( - ParaId::from(5u32), - relay_parent, - 8, - vec![4, 5, 6].into(), - vec![1, 2, 3].into(), - 7, - ); - - let candidate_hash = candidate.hash(); - let parent_head_hash = pvd.parent_head.hash(); - - storage.add_candidate(candidate, pvd).unwrap(); - assert!(storage.contains(&candidate_hash)); - assert_eq!(storage.iter_para_children(&parent_head_hash).count(), 1); - - assert_eq!(storage.relay_parent_by_candidate_hash(&candidate_hash), Some(relay_parent)); - } - - #[test] - fn storage_retain() { - let mut storage = CandidateStorage::new(); - - let (pvd, candidate) = make_committed_candidate( - ParaId::from(5u32), - Hash::repeat_byte(69), - 8, - vec![4, 5, 6].into(), - vec![1, 2, 3].into(), - 7, - ); - - let candidate_hash = candidate.hash(); - let output_head_hash = candidate.commitments.head_data.hash(); - let parent_head_hash = pvd.parent_head.hash(); - - storage.add_candidate(candidate, pvd).unwrap(); - storage.retain(|_| true); - assert!(storage.contains(&candidate_hash)); - assert_eq!(storage.iter_para_children(&parent_head_hash).count(), 1); - assert!(storage.head_data_by_hash(&output_head_hash).is_some()); - - storage.retain(|_| false); - assert!(!storage.contains(&candidate_hash)); - assert_eq!(storage.iter_para_children(&parent_head_hash).count(), 0); - assert!(storage.head_data_by_hash(&output_head_hash).is_none()); - } - - // [`FragmentTree::populate`] should pick up candidates that build on other candidates. - #[test] - fn populate_works_recursively() { - let mut storage = CandidateStorage::new(); - - let para_id = ParaId::from(5u32); - let relay_parent_a = Hash::repeat_byte(1); - let relay_parent_b = Hash::repeat_byte(2); - - let (pvd_a, candidate_a) = make_committed_candidate( - para_id, - relay_parent_a, - 0, - vec![0x0a].into(), - vec![0x0b].into(), - 0, - ); - let candidate_a_hash = candidate_a.hash(); - - let (pvd_b, candidate_b) = make_committed_candidate( - para_id, - relay_parent_b, - 1, - vec![0x0b].into(), - vec![0x0c].into(), - 1, - ); - let candidate_b_hash = candidate_b.hash(); - - let base_constraints = make_constraints(0, vec![0], vec![0x0a].into()); - let pending_availability = Vec::new(); - - let ancestors = vec![RelayChainBlockInfo { - number: pvd_a.relay_parent_number, - hash: relay_parent_a, - storage_root: pvd_a.relay_parent_storage_root, - }]; - - let relay_parent_b_info = RelayChainBlockInfo { - number: pvd_b.relay_parent_number, - hash: relay_parent_b, - storage_root: pvd_b.relay_parent_storage_root, - }; - - storage.add_candidate(candidate_a, pvd_a).unwrap(); - storage.add_candidate(candidate_b, pvd_b).unwrap(); - let scope = Scope::with_ancestors( - para_id, - relay_parent_b_info, - base_constraints, - pending_availability, - 4, - ancestors, - ) - .unwrap(); - let tree = FragmentTree::populate(scope, &storage); - - let candidates: Vec<_> = tree.candidates().collect(); - assert_eq!(candidates.len(), 2); - assert!(candidates.contains(&candidate_a_hash)); - assert!(candidates.contains(&candidate_b_hash)); - - assert_eq!(tree.nodes.len(), 2); - assert_eq!(tree.nodes[0].parent, NodePointer::Root); - assert_eq!(tree.nodes[0].candidate_hash, candidate_a_hash); - assert_eq!(tree.nodes[0].depth, 0); - - assert_eq!(tree.nodes[1].parent, NodePointer::Storage(0)); - assert_eq!(tree.nodes[1].candidate_hash, candidate_b_hash); - assert_eq!(tree.nodes[1].depth, 1); - } - - #[test] - fn children_of_root_are_contiguous() { - let mut storage = CandidateStorage::new(); - - let para_id = ParaId::from(5u32); - let relay_parent_a = Hash::repeat_byte(1); - let relay_parent_b = Hash::repeat_byte(2); - - let (pvd_a, candidate_a) = make_committed_candidate( - para_id, - relay_parent_a, - 0, - vec![0x0a].into(), - vec![0x0b].into(), - 0, - ); - - let (pvd_b, candidate_b) = make_committed_candidate( - para_id, - relay_parent_b, - 1, - vec![0x0b].into(), - vec![0x0c].into(), - 1, - ); - - let (pvd_a2, candidate_a2) = make_committed_candidate( - para_id, - relay_parent_a, - 0, - vec![0x0a].into(), - vec![0x0b, 1].into(), - 0, - ); - let candidate_a2_hash = candidate_a2.hash(); - - let base_constraints = make_constraints(0, vec![0], vec![0x0a].into()); - let pending_availability = Vec::new(); - - let ancestors = vec![RelayChainBlockInfo { - number: pvd_a.relay_parent_number, - hash: relay_parent_a, - storage_root: pvd_a.relay_parent_storage_root, - }]; - - let relay_parent_b_info = RelayChainBlockInfo { - number: pvd_b.relay_parent_number, - hash: relay_parent_b, - storage_root: pvd_b.relay_parent_storage_root, - }; - - storage.add_candidate(candidate_a, pvd_a).unwrap(); - storage.add_candidate(candidate_b, pvd_b).unwrap(); - let scope = Scope::with_ancestors( - para_id, - relay_parent_b_info, - base_constraints, - pending_availability, - 4, - ancestors, - ) - .unwrap(); - let mut tree = FragmentTree::populate(scope, &storage); - - storage.add_candidate(candidate_a2, pvd_a2).unwrap(); - tree.add_and_populate(candidate_a2_hash, &storage); - let candidates: Vec<_> = tree.candidates().collect(); - assert_eq!(candidates.len(), 3); - - assert_eq!(tree.nodes[0].parent, NodePointer::Root); - assert_eq!(tree.nodes[1].parent, NodePointer::Root); - assert_eq!(tree.nodes[2].parent, NodePointer::Storage(0)); - } - - #[test] - fn add_candidate_child_of_root() { - let mut storage = CandidateStorage::new(); - - let para_id = ParaId::from(5u32); - let relay_parent_a = Hash::repeat_byte(1); - - let (pvd_a, candidate_a) = make_committed_candidate( - para_id, - relay_parent_a, - 0, - vec![0x0a].into(), - vec![0x0b].into(), - 0, - ); - - let (pvd_b, candidate_b) = make_committed_candidate( - para_id, - relay_parent_a, - 0, - vec![0x0a].into(), - vec![0x0c].into(), - 0, - ); - let candidate_b_hash = candidate_b.hash(); - - let base_constraints = make_constraints(0, vec![0], vec![0x0a].into()); - let pending_availability = Vec::new(); - - let relay_parent_a_info = RelayChainBlockInfo { - number: pvd_a.relay_parent_number, - hash: relay_parent_a, - storage_root: pvd_a.relay_parent_storage_root, - }; - - storage.add_candidate(candidate_a, pvd_a).unwrap(); - let scope = Scope::with_ancestors( - para_id, - relay_parent_a_info, - base_constraints, - pending_availability, - 4, - vec![], - ) - .unwrap(); - let mut tree = FragmentTree::populate(scope, &storage); - - storage.add_candidate(candidate_b, pvd_b).unwrap(); - tree.add_and_populate(candidate_b_hash, &storage); - let candidates: Vec<_> = tree.candidates().collect(); - assert_eq!(candidates.len(), 2); - - assert_eq!(tree.nodes[0].parent, NodePointer::Root); - assert_eq!(tree.nodes[1].parent, NodePointer::Root); - } - - #[test] - fn add_candidate_child_of_non_root() { - let mut storage = CandidateStorage::new(); - - let para_id = ParaId::from(5u32); - let relay_parent_a = Hash::repeat_byte(1); - - let (pvd_a, candidate_a) = make_committed_candidate( - para_id, - relay_parent_a, - 0, - vec![0x0a].into(), - vec![0x0b].into(), - 0, - ); - - let (pvd_b, candidate_b) = make_committed_candidate( - para_id, - relay_parent_a, - 0, - vec![0x0b].into(), - vec![0x0c].into(), - 0, - ); - let candidate_b_hash = candidate_b.hash(); - - let base_constraints = make_constraints(0, vec![0], vec![0x0a].into()); - let pending_availability = Vec::new(); - - let relay_parent_a_info = RelayChainBlockInfo { - number: pvd_a.relay_parent_number, - hash: relay_parent_a, - storage_root: pvd_a.relay_parent_storage_root, - }; - - storage.add_candidate(candidate_a, pvd_a).unwrap(); - let scope = Scope::with_ancestors( - para_id, - relay_parent_a_info, - base_constraints, - pending_availability, - 4, - vec![], - ) - .unwrap(); - let mut tree = FragmentTree::populate(scope, &storage); - - storage.add_candidate(candidate_b, pvd_b).unwrap(); - tree.add_and_populate(candidate_b_hash, &storage); - let candidates: Vec<_> = tree.candidates().collect(); - assert_eq!(candidates.len(), 2); - - assert_eq!(tree.nodes[0].parent, NodePointer::Root); - 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(); - - let para_id = ParaId::from(5u32); - let relay_parent_a = Hash::repeat_byte(1); - - let (pvd_a, candidate_a) = make_committed_candidate( - para_id, - relay_parent_a, - 0, - vec![0x0a].into(), - vec![0x0a].into(), // input same as output - 0, - ); - let candidate_a_hash = candidate_a.hash(); - let base_constraints = make_constraints(0, vec![0], vec![0x0a].into()); - let pending_availability = Vec::new(); - - let relay_parent_a_info = RelayChainBlockInfo { - number: pvd_a.relay_parent_number, - hash: relay_parent_a, - storage_root: pvd_a.relay_parent_storage_root, - }; - - let max_depth = 4; - storage.add_candidate(candidate_a, pvd_a).unwrap(); - let scope = Scope::with_ancestors( - para_id, - relay_parent_a_info, - base_constraints, - pending_availability, - max_depth, - vec![], - ) - .unwrap(); - let tree = FragmentTree::populate(scope, &storage); - - let candidates: Vec<_> = tree.candidates().collect(); - assert_eq!(candidates.len(), 1); - assert_eq!(tree.nodes.len(), max_depth + 1); - - assert_eq!(tree.nodes[0].parent, NodePointer::Root); - assert_eq!(tree.nodes[1].parent, NodePointer::Storage(0)); - assert_eq!(tree.nodes[2].parent, NodePointer::Storage(1)); - assert_eq!(tree.nodes[3].parent, NodePointer::Storage(2)); - assert_eq!(tree.nodes[4].parent, NodePointer::Storage(3)); - - assert_eq!(tree.nodes[0].candidate_hash, candidate_a_hash); - assert_eq!(tree.nodes[1].candidate_hash, candidate_a_hash); - assert_eq!(tree.nodes[2].candidate_hash, candidate_a_hash); - assert_eq!(tree.nodes[3].candidate_hash, candidate_a_hash); - assert_eq!(tree.nodes[4].candidate_hash, candidate_a_hash); - - for count in 1..10 { - assert_eq!( - 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.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::>() - ); - } - } - - #[test] - fn graceful_cycle_of_1() { - let mut storage = CandidateStorage::new(); - - let para_id = ParaId::from(5u32); - let relay_parent_a = Hash::repeat_byte(1); - - let (pvd_a, candidate_a) = make_committed_candidate( - para_id, - relay_parent_a, - 0, - vec![0x0a].into(), - vec![0x0b].into(), // input same as output - 0, - ); - let candidate_a_hash = candidate_a.hash(); - - let (pvd_b, candidate_b) = make_committed_candidate( - para_id, - relay_parent_a, - 0, - vec![0x0b].into(), - vec![0x0a].into(), // input same as output - 0, - ); - let candidate_b_hash = candidate_b.hash(); - - let base_constraints = make_constraints(0, vec![0], vec![0x0a].into()); - let pending_availability = Vec::new(); - - let relay_parent_a_info = RelayChainBlockInfo { - number: pvd_a.relay_parent_number, - hash: relay_parent_a, - storage_root: pvd_a.relay_parent_storage_root, - }; - - let max_depth = 4; - storage.add_candidate(candidate_a, pvd_a).unwrap(); - storage.add_candidate(candidate_b, pvd_b).unwrap(); - let scope = Scope::with_ancestors( - para_id, - relay_parent_a_info, - base_constraints, - pending_availability, - max_depth, - vec![], - ) - .unwrap(); - let tree = FragmentTree::populate(scope, &storage); - - let candidates: Vec<_> = tree.candidates().collect(); - assert_eq!(candidates.len(), 2); - assert_eq!(tree.nodes.len(), max_depth + 1); - - assert_eq!(tree.nodes[0].parent, NodePointer::Root); - assert_eq!(tree.nodes[1].parent, NodePointer::Storage(0)); - assert_eq!(tree.nodes[2].parent, NodePointer::Storage(1)); - assert_eq!(tree.nodes[3].parent, NodePointer::Storage(2)); - assert_eq!(tree.nodes[4].parent, NodePointer::Storage(3)); - - assert_eq!(tree.nodes[0].candidate_hash, candidate_a_hash); - assert_eq!(tree.nodes[1].candidate_hash, candidate_b_hash); - assert_eq!(tree.nodes[2].candidate_hash, candidate_a_hash); - assert_eq!(tree.nodes[3].candidate_hash, candidate_b_hash); - assert_eq!(tree.nodes[4].candidate_hash, candidate_a_hash); - - assert_eq!(tree.find_backable_chain(Ancestors::new(), 1, |_| true), vec![candidate_a_hash],); - assert_eq!( - tree.find_backable_chain(Ancestors::new(), 2, |_| true), - vec![candidate_a_hash, candidate_b_hash], - ); - assert_eq!( - tree.find_backable_chain(Ancestors::new(), 3, |_| true), - vec![candidate_a_hash, candidate_b_hash, candidate_a_hash], - ); - assert_eq!( - tree.find_backable_chain([candidate_a_hash].into_iter().collect(), 2, |_| true), - vec![candidate_b_hash, candidate_a_hash], - ); - - assert_eq!( - tree.find_backable_chain(Ancestors::new(), 6, |_| true), - vec![ - candidate_a_hash, - candidate_b_hash, - 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] - fn hypothetical_depths_known_and_unknown() { - let mut storage = CandidateStorage::new(); - - let para_id = ParaId::from(5u32); - let relay_parent_a = Hash::repeat_byte(1); - - let (pvd_a, candidate_a) = make_committed_candidate( - para_id, - relay_parent_a, - 0, - vec![0x0a].into(), - vec![0x0b].into(), // input same as output - 0, - ); - let candidate_a_hash = candidate_a.hash(); - - let (pvd_b, candidate_b) = make_committed_candidate( - para_id, - relay_parent_a, - 0, - vec![0x0b].into(), - vec![0x0a].into(), // input same as output - 0, - ); - let candidate_b_hash = candidate_b.hash(); - - let base_constraints = make_constraints(0, vec![0], vec![0x0a].into()); - let pending_availability = Vec::new(); - - let relay_parent_a_info = RelayChainBlockInfo { - number: pvd_a.relay_parent_number, - hash: relay_parent_a, - storage_root: pvd_a.relay_parent_storage_root, - }; - - let max_depth = 4; - storage.add_candidate(candidate_a, pvd_a).unwrap(); - storage.add_candidate(candidate_b, pvd_b).unwrap(); - let scope = Scope::with_ancestors( - para_id, - relay_parent_a_info, - base_constraints, - pending_availability, - max_depth, - vec![], - ) - .unwrap(); - let tree = FragmentTree::populate(scope, &storage); - - let candidates: Vec<_> = tree.candidates().collect(); - assert_eq!(candidates.len(), 2); - assert_eq!(tree.nodes.len(), max_depth + 1); - - assert_eq!( - tree.hypothetical_depths( - candidate_a_hash, - HypotheticalCandidate::Incomplete { - parent_head_data_hash: HeadData::from(vec![0x0a]).hash(), - relay_parent: relay_parent_a, - }, - &storage, - false, - ), - vec![0, 2, 4], - ); - - assert_eq!( - tree.hypothetical_depths( - candidate_b_hash, - HypotheticalCandidate::Incomplete { - parent_head_data_hash: HeadData::from(vec![0x0b]).hash(), - relay_parent: relay_parent_a, - }, - &storage, - false, - ), - vec![1, 3], - ); - - assert_eq!( - tree.hypothetical_depths( - CandidateHash(Hash::repeat_byte(21)), - HypotheticalCandidate::Incomplete { - parent_head_data_hash: HeadData::from(vec![0x0a]).hash(), - relay_parent: relay_parent_a, - }, - &storage, - false, - ), - vec![0, 2, 4], - ); - - assert_eq!( - tree.hypothetical_depths( - CandidateHash(Hash::repeat_byte(22)), - HypotheticalCandidate::Incomplete { - parent_head_data_hash: HeadData::from(vec![0x0b]).hash(), - relay_parent: relay_parent_a, - }, - &storage, - false, - ), - vec![1, 3] - ); - } - - #[test] - fn hypothetical_depths_stricter_on_complete() { - let storage = CandidateStorage::new(); - - let para_id = ParaId::from(5u32); - let relay_parent_a = Hash::repeat_byte(1); - - let (pvd_a, candidate_a) = make_committed_candidate( - para_id, - relay_parent_a, - 0, - vec![0x0a].into(), - vec![0x0b].into(), - 1000, // watermark is illegal - ); - - let candidate_a_hash = candidate_a.hash(); - - let base_constraints = make_constraints(0, vec![0], vec![0x0a].into()); - let pending_availability = Vec::new(); - - let relay_parent_a_info = RelayChainBlockInfo { - number: pvd_a.relay_parent_number, - hash: relay_parent_a, - storage_root: pvd_a.relay_parent_storage_root, - }; - - let max_depth = 4; - let scope = Scope::with_ancestors( - para_id, - relay_parent_a_info, - base_constraints, - pending_availability, - max_depth, - vec![], - ) - .unwrap(); - let tree = FragmentTree::populate(scope, &storage); - - assert_eq!( - tree.hypothetical_depths( - candidate_a_hash, - HypotheticalCandidate::Incomplete { - parent_head_data_hash: HeadData::from(vec![0x0a]).hash(), - relay_parent: relay_parent_a, - }, - &storage, - false, - ), - vec![0], - ); - - assert!(tree - .hypothetical_depths( - candidate_a_hash, - HypotheticalCandidate::Complete { - receipt: Cow::Owned(candidate_a), - persisted_validation_data: Cow::Owned(pvd_a), - }, - &storage, - false, - ) - .is_empty()); - } - - #[test] - fn hypothetical_depths_backed_in_path() { - let mut storage = CandidateStorage::new(); - - let para_id = ParaId::from(5u32); - let relay_parent_a = Hash::repeat_byte(1); - - let (pvd_a, candidate_a) = make_committed_candidate( - para_id, - relay_parent_a, - 0, - vec![0x0a].into(), - vec![0x0b].into(), - 0, - ); - let candidate_a_hash = candidate_a.hash(); - - let (pvd_b, candidate_b) = make_committed_candidate( - para_id, - relay_parent_a, - 0, - vec![0x0b].into(), - vec![0x0c].into(), - 0, - ); - let candidate_b_hash = candidate_b.hash(); - - let (pvd_c, candidate_c) = make_committed_candidate( - para_id, - relay_parent_a, - 0, - vec![0x0b].into(), - vec![0x0d].into(), - 0, - ); - - let base_constraints = make_constraints(0, vec![0], vec![0x0a].into()); - let pending_availability = Vec::new(); - - let relay_parent_a_info = RelayChainBlockInfo { - number: pvd_a.relay_parent_number, - hash: relay_parent_a, - storage_root: pvd_a.relay_parent_storage_root, - }; - - let max_depth = 4; - storage.add_candidate(candidate_a, pvd_a).unwrap(); - storage.add_candidate(candidate_b, pvd_b).unwrap(); - storage.add_candidate(candidate_c, pvd_c).unwrap(); - - // `A` and `B` are backed, `C` is not. - storage.mark_backed(&candidate_a_hash); - storage.mark_backed(&candidate_b_hash); - - let scope = Scope::with_ancestors( - para_id, - relay_parent_a_info, - base_constraints, - pending_availability, - max_depth, - vec![], - ) - .unwrap(); - let tree = FragmentTree::populate(scope, &storage); - - let candidates: Vec<_> = tree.candidates().collect(); - assert_eq!(candidates.len(), 3); - assert_eq!(tree.nodes.len(), 3); - - let candidate_d_hash = CandidateHash(Hash::repeat_byte(0xAA)); - - assert_eq!( - tree.hypothetical_depths( - candidate_d_hash, - HypotheticalCandidate::Incomplete { - parent_head_data_hash: HeadData::from(vec![0x0a]).hash(), - relay_parent: relay_parent_a, - }, - &storage, - true, - ), - vec![0], - ); - - assert_eq!( - tree.hypothetical_depths( - candidate_d_hash, - HypotheticalCandidate::Incomplete { - parent_head_data_hash: HeadData::from(vec![0x0c]).hash(), - relay_parent: relay_parent_a, - }, - &storage, - true, - ), - vec![2], - ); - - assert_eq!( - tree.hypothetical_depths( - candidate_d_hash, - HypotheticalCandidate::Incomplete { - parent_head_data_hash: HeadData::from(vec![0x0d]).hash(), - relay_parent: relay_parent_a, - }, - &storage, - true, - ), - Vec::::new(), - ); - - assert_eq!( - tree.hypothetical_depths( - candidate_d_hash, - HypotheticalCandidate::Incomplete { - parent_head_data_hash: HeadData::from(vec![0x0d]).hash(), - relay_parent: relay_parent_a, - }, - &storage, - false, - ), - vec![2], // non-empty if `false`. - ); - } - - #[test] - fn pending_availability_in_scope() { - let mut storage = CandidateStorage::new(); - - let para_id = ParaId::from(5u32); - let relay_parent_a = Hash::repeat_byte(1); - let relay_parent_b = Hash::repeat_byte(2); - let relay_parent_c = Hash::repeat_byte(3); - - let (pvd_a, candidate_a) = make_committed_candidate( - para_id, - relay_parent_a, - 0, - vec![0x0a].into(), - vec![0x0b].into(), - 0, - ); - let candidate_a_hash = candidate_a.hash(); - - let (pvd_b, candidate_b) = make_committed_candidate( - para_id, - relay_parent_b, - 1, - vec![0x0b].into(), - vec![0x0c].into(), - 1, - ); - - // Note that relay parent `a` is not allowed. - let base_constraints = make_constraints(1, vec![], vec![0x0a].into()); - - let relay_parent_a_info = RelayChainBlockInfo { - number: pvd_a.relay_parent_number, - hash: relay_parent_a, - storage_root: pvd_a.relay_parent_storage_root, - }; - let pending_availability = vec![PendingAvailability { - candidate_hash: candidate_a_hash, - relay_parent: relay_parent_a_info, - }]; - - let relay_parent_b_info = RelayChainBlockInfo { - number: pvd_b.relay_parent_number, - hash: relay_parent_b, - storage_root: pvd_b.relay_parent_storage_root, - }; - let relay_parent_c_info = RelayChainBlockInfo { - number: pvd_b.relay_parent_number + 1, - hash: relay_parent_c, - storage_root: Hash::zero(), - }; - - let max_depth = 4; - storage.add_candidate(candidate_a, pvd_a).unwrap(); - storage.add_candidate(candidate_b, pvd_b).unwrap(); - storage.mark_backed(&candidate_a_hash); - - let scope = Scope::with_ancestors( - para_id, - relay_parent_c_info, - base_constraints, - pending_availability, - max_depth, - vec![relay_parent_b_info], - ) - .unwrap(); - let tree = FragmentTree::populate(scope, &storage); - - let candidates: Vec<_> = tree.candidates().collect(); - assert_eq!(candidates.len(), 2); - assert_eq!(tree.nodes.len(), 2); - - let candidate_d_hash = CandidateHash(Hash::repeat_byte(0xAA)); - - assert_eq!( - tree.hypothetical_depths( - candidate_d_hash, - HypotheticalCandidate::Incomplete { - parent_head_data_hash: HeadData::from(vec![0x0b]).hash(), - relay_parent: relay_parent_c, - }, - &storage, - false, - ), - vec![1], - ); - - assert_eq!( - tree.hypothetical_depths( - candidate_d_hash, - HypotheticalCandidate::Incomplete { - parent_head_data_hash: HeadData::from(vec![0x0c]).hash(), - relay_parent: relay_parent_b, - }, - &storage, - false, - ), - vec![2], - ); - } -} diff --git a/polkadot/node/core/prospective-parachains/src/lib.rs b/polkadot/node/core/prospective-parachains/src/lib.rs index f5d50fb74faca5fec78c47aa6a653a1a9fe48699..d5bb5ff76ba8e8e603f2ab6b915b6c8fdb2d5f3c 100644 --- a/polkadot/node/core/prospective-parachains/src/lib.rs +++ b/polkadot/node/core/prospective-parachains/src/lib.rs @@ -21,22 +21,20 @@ //! This is the main coordinator of work within the node for the collation and //! backing phases of parachain consensus. //! -//! This is primarily an implementation of "Fragment Trees", as described in +//! This is primarily an implementation of "Fragment Chains", as described in //! [`polkadot_node_subsystem_util::inclusion_emulator`]. //! //! This subsystem also handles concerns such as the relay-chain being forkful and session changes. -use std::{ - borrow::Cow, - collections::{HashMap, HashSet}, -}; +use std::collections::{HashMap, HashSet}; +use fragment_chain::{FragmentChain, PotentialAddition}; use futures::{channel::oneshot, prelude::*}; use polkadot_node_subsystem::{ messages::{ - Ancestors, ChainApiMessage, FragmentTreeMembership, HypotheticalCandidate, - HypotheticalFrontierRequest, IntroduceCandidateRequest, ParentHeadData, + Ancestors, ChainApiMessage, HypotheticalCandidate, HypotheticalMembership, + HypotheticalMembershipRequest, IntroduceSecondedCandidateRequest, ParentHeadData, ProspectiveParachainsMessage, ProspectiveValidationDataRequest, RuntimeApiMessage, RuntimeApiRequest, }, @@ -55,13 +53,14 @@ use polkadot_primitives::{ use crate::{ error::{FatalError, FatalResult, JfyiError, JfyiErrorResult, Result}, - fragment_tree::{ - CandidateStorage, CandidateStorageInsertionError, FragmentTree, Scope as TreeScope, + fragment_chain::{ + CandidateState, CandidateStorage, CandidateStorageInsertionError, + Scope as FragmentChainScope, }, }; mod error; -mod fragment_tree; +mod fragment_chain; #[cfg(test)] mod tests; @@ -72,7 +71,7 @@ const LOG_TARGET: &str = "parachain::prospective-parachains"; struct RelayBlockViewData { // Scheduling info for paras and upcoming paras. - fragment_trees: HashMap, + fragment_chains: HashMap, pending_availability: HashSet, } @@ -141,12 +140,10 @@ async fn run_iteration( }, FromOrchestra::Signal(OverseerSignal::BlockFinalized(..)) => {}, FromOrchestra::Communication { msg } => match msg { - ProspectiveParachainsMessage::IntroduceCandidate(request, tx) => - handle_candidate_introduced(&mut *ctx, view, request, tx).await?, - ProspectiveParachainsMessage::CandidateSeconded(para, candidate_hash) => - handle_candidate_seconded(view, para, candidate_hash), + ProspectiveParachainsMessage::IntroduceSecondedCandidate(request, tx) => + handle_introduce_seconded_candidate(&mut *ctx, view, request, tx, metrics).await, ProspectiveParachainsMessage::CandidateBacked(para, candidate_hash) => - handle_candidate_backed(&mut *ctx, view, para, candidate_hash).await?, + handle_candidate_backed(&mut *ctx, view, para, candidate_hash).await, ProspectiveParachainsMessage::GetBackableCandidates( relay_parent, para, @@ -154,10 +151,8 @@ async fn run_iteration( ancestors, 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) => - answer_tree_membership_request(&view, para, candidate, tx), + ProspectiveParachainsMessage::GetHypotheticalMembership(request, tx) => + answer_hypothetical_membership_request(&view, request, tx, metrics), ProspectiveParachainsMessage::GetMinimumRelayParents(relay_parent, tx) => answer_minimum_relay_parents_request(&view, relay_parent, tx), ProspectiveParachainsMessage::GetProspectiveValidationData(request, tx) => @@ -175,8 +170,8 @@ async fn handle_active_leaves_update( metrics: &Metrics, ) -> JfyiErrorResult<()> { // 1. clean up inactive leaves - // 2. determine all scheduled para at new block - // 3. construct new fragment tree for each para for each new leaf + // 2. determine all scheduled paras at the new block + // 3. construct new fragment chain for each para for each new leaf // 4. prune candidate storage. for deactivated in &update.deactivated { @@ -203,9 +198,7 @@ async fn handle_active_leaves_update( return Ok(()) }; - let mut pending_availability = HashSet::new(); - let scheduled_paras = - fetch_upcoming_paras(&mut *ctx, hash, &mut pending_availability).await?; + let scheduled_paras = fetch_upcoming_paras(&mut *ctx, hash).await?; let block_info: RelayChainBlockInfo = match fetch_block_info(&mut *ctx, &mut temp_header_cache, hash).await? { @@ -227,30 +220,30 @@ async fn handle_active_leaves_update( let ancestry = fetch_ancestry(&mut *ctx, &mut temp_header_cache, hash, allowed_ancestry_len).await?; + let mut all_pending_availability = HashSet::new(); + // Find constraints. - let mut fragment_trees = HashMap::new(); + let mut fragment_chains = HashMap::new(); for para in scheduled_paras { let candidate_storage = - view.candidate_storage.entry(para).or_insert_with(CandidateStorage::new); + view.candidate_storage.entry(para).or_insert_with(CandidateStorage::default); let backing_state = fetch_backing_state(&mut *ctx, hash, para).await?; - let (constraints, pending_availability) = match backing_state { - Some(c) => c, - None => { - // This indicates a runtime conflict of some kind. - - gum::debug!( - target: LOG_TARGET, - para_id = ?para, - relay_parent = ?hash, - "Failed to get inclusion backing state." - ); + let Some((constraints, pending_availability)) = backing_state else { + // This indicates a runtime conflict of some kind. + gum::debug!( + target: LOG_TARGET, + para_id = ?para, + relay_parent = ?hash, + "Failed to get inclusion backing state." + ); - continue - }, + continue }; + all_pending_availability.extend(pending_availability.iter().map(|c| c.candidate_hash)); + let pending_availability = preprocess_candidates_pending_availability( ctx, &mut temp_header_cache, @@ -261,15 +254,15 @@ async fn handle_active_leaves_update( let mut compact_pending = Vec::with_capacity(pending_availability.len()); for c in pending_availability { - let res = candidate_storage.add_candidate(c.candidate, c.persisted_validation_data); + let res = candidate_storage.add_candidate( + c.candidate, + c.persisted_validation_data, + CandidateState::Backed, + ); let candidate_hash = c.compact.candidate_hash; - compact_pending.push(c.compact); match res { - Ok(_) | Err(CandidateStorageInsertionError::CandidateAlreadyKnown(_)) => { - // Anything on-chain is guaranteed to be backed. - candidate_storage.mark_backed(&candidate_hash); - }, + Ok(_) | Err(CandidateStorageInsertionError::CandidateAlreadyKnown(_)) => {}, Err(err) => { gum::warn!( target: LOG_TARGET, @@ -278,11 +271,15 @@ async fn handle_active_leaves_update( ?err, "Scraped invalid candidate pending availability", ); + + break }, } + + compact_pending.push(c.compact); } - let scope = TreeScope::with_ancestors( + let scope = FragmentChainScope::with_ancestors( para, block_info.clone(), constraints, @@ -297,16 +294,26 @@ async fn handle_active_leaves_update( relay_parent = ?hash, min_relay_parent = scope.earliest_relay_parent().number, para_id = ?para, - "Creating fragment tree" + "Creating fragment chain" ); - let tree = FragmentTree::populate(scope, &*candidate_storage); + let chain = FragmentChain::populate(scope, &*candidate_storage); + + gum::trace!( + target: LOG_TARGET, + relay_parent = ?hash, + para_id = ?para, + "Populated fragment chain with {} candidates", + chain.len() + ); - fragment_trees.insert(para, tree); + fragment_chains.insert(para, chain); } - view.active_leaves - .insert(hash, RelayBlockViewData { fragment_trees, pending_availability }); + view.active_leaves.insert( + hash, + RelayBlockViewData { fragment_chains, pending_availability: all_pending_availability }, + ); } if !update.deactivated.is_empty() { @@ -318,18 +325,39 @@ async fn handle_active_leaves_update( } fn prune_view_candidate_storage(view: &mut View, metrics: &Metrics) { - metrics.time_prune_view_candidate_storage(); + let _timer = metrics.time_prune_view_candidate_storage(); let active_leaves = &view.active_leaves; let mut live_candidates = HashSet::new(); let mut live_paras = HashSet::new(); for sub_view in active_leaves.values() { - for (para_id, fragment_tree) in &sub_view.fragment_trees { - live_candidates.extend(fragment_tree.candidates()); + live_candidates.extend(sub_view.pending_availability.iter().cloned()); + + for (para_id, fragment_chain) in &sub_view.fragment_chains { + live_candidates.extend(fragment_chain.to_vec()); live_paras.insert(*para_id); } + } - live_candidates.extend(sub_view.pending_availability.iter().cloned()); + let connected_candidates_count = live_candidates.len(); + for (leaf, sub_view) in active_leaves.iter() { + for (para_id, fragment_chain) in &sub_view.fragment_chains { + if let Some(storage) = view.candidate_storage.get(para_id) { + let unconnected_potential = + fragment_chain.find_unconnected_potential_candidates(storage, None); + if !unconnected_potential.is_empty() { + gum::trace!( + target: LOG_TARGET, + ?leaf, + "Keeping {} unconnected candidates for paraid {} in storage: {:?}", + unconnected_potential.len(), + para_id, + unconnected_potential + ); + } + live_candidates.extend(unconnected_potential); + } + } } view.candidate_storage.retain(|para_id, storage| { @@ -343,13 +371,27 @@ fn prune_view_candidate_storage(view: &mut View, metrics: &Metrics) { // This maintains a convenient invariant that para-id storage exists // as long as there's an active head which schedules the para. true - }) + }); + + for (para_id, storage) in view.candidate_storage.iter() { + gum::trace!( + target: LOG_TARGET, + "Keeping a total of {} connected candidates for paraid {} in storage", + storage.candidates().count(), + para_id, + ); + } + + metrics.record_candidate_storage_size( + connected_candidates_count as u64, + live_candidates.len().saturating_sub(connected_candidates_count) as u64, + ); } struct ImportablePendingAvailability { candidate: CommittedCandidateReceipt, persisted_validation_data: PersistedValidationData, - compact: crate::fragment_tree::PendingAvailability, + compact: crate::fragment_chain::PendingAvailability, } #[overseer::contextbounds(ProspectiveParachains, prefix = self::overseer)] @@ -365,22 +407,20 @@ async fn preprocess_candidates_pending_availability( let expected_count = pending_availability.len(); for (i, pending) in pending_availability.into_iter().enumerate() { - let relay_parent = - match fetch_block_info(ctx, cache, pending.descriptor.relay_parent).await? { - None => { - gum::debug!( - target: LOG_TARGET, - ?pending.candidate_hash, - ?pending.descriptor.para_id, - index = ?i, - ?expected_count, - "Had to stop processing pending candidates early due to missing info.", - ); + let Some(relay_parent) = + fetch_block_info(ctx, cache, pending.descriptor.relay_parent).await? + else { + gum::debug!( + target: LOG_TARGET, + ?pending.candidate_hash, + ?pending.descriptor.para_id, + index = ?i, + ?expected_count, + "Had to stop processing pending candidates early due to missing info.", + ); - break - }, - Some(b) => b, - }; + break + }; let next_required_parent = pending.commitments.head_data.clone(); importable.push(ImportablePendingAvailability { @@ -394,7 +434,7 @@ async fn preprocess_candidates_pending_availability( relay_parent_number: relay_parent.number, relay_parent_storage_root: relay_parent.storage_root, }, - compact: crate::fragment_tree::PendingAvailability { + compact: crate::fragment_chain::PendingAvailability { candidate_hash: pending.candidate_hash, relay_parent, }, @@ -407,104 +447,139 @@ async fn preprocess_candidates_pending_availability( } #[overseer::contextbounds(ProspectiveParachains, prefix = self::overseer)] -async fn handle_candidate_introduced( +async fn handle_introduce_seconded_candidate( _ctx: &mut Context, view: &mut View, - request: IntroduceCandidateRequest, - tx: oneshot::Sender, -) -> JfyiErrorResult<()> { - let IntroduceCandidateRequest { + request: IntroduceSecondedCandidateRequest, + tx: oneshot::Sender, + metrics: &Metrics, +) { + let _timer = metrics.time_introduce_seconded_candidate(); + + let IntroduceSecondedCandidateRequest { candidate_para: para, candidate_receipt: candidate, persisted_validation_data: pvd, } = request; - // Add the candidate to storage. - // Then attempt to add it to all trees. - let storage = match view.candidate_storage.get_mut(¶) { - None => { - gum::warn!( - target: LOG_TARGET, - para_id = ?para, - candidate_hash = ?candidate.hash(), - "Received seconded candidate for inactive para", - ); + let Some(storage) = view.candidate_storage.get_mut(¶) else { + gum::warn!( + target: LOG_TARGET, + para_id = ?para, + candidate_hash = ?candidate.hash(), + "Received seconded candidate for inactive para", + ); - let _ = tx.send(Vec::new()); - return Ok(()) - }, - Some(storage) => storage, + let _ = tx.send(false); + return }; - let candidate_hash = match storage.add_candidate(candidate, pvd) { - Ok(c) => c, - Err(CandidateStorageInsertionError::CandidateAlreadyKnown(c)) => { - // Candidate known - return existing fragment tree membership. - let _ = tx.send(fragment_tree_membership(&view.active_leaves, para, c)); - return Ok(()) - }, - Err(CandidateStorageInsertionError::PersistedValidationDataMismatch) => { - // We can't log the candidate hash without either doing more ~expensive - // hashing but this branch indicates something is seriously wrong elsewhere - // so it's doubtful that it would affect debugging. + let parent_head_hash = pvd.parent_head.hash(); + let output_head_hash = Some(candidate.commitments.head_data.hash()); + + // We first introduce the candidate in the storage and then try to extend the chain. + // If the candidate gets included in the chain, we can keep it in storage. + // If it doesn't, check that it's still a potential candidate in at least one fragment chain. + // If it's not, we can remove it. + + let candidate_hash = + match storage.add_candidate(candidate.clone(), pvd, CandidateState::Seconded) { + Ok(c) => c, + Err(CandidateStorageInsertionError::CandidateAlreadyKnown(_)) => { + gum::debug!( + target: LOG_TARGET, + para = ?para, + "Attempting to introduce an already known candidate: {:?}", + candidate.hash() + ); + // Candidate already known. + let _ = tx.send(true); + return + }, + Err(CandidateStorageInsertionError::PersistedValidationDataMismatch) => { + // We can't log the candidate hash without either doing more ~expensive + // hashing but this branch indicates something is seriously wrong elsewhere + // so it's doubtful that it would affect debugging. - gum::warn!( + gum::warn!( + target: LOG_TARGET, + para = ?para, + "Received seconded candidate had mismatching validation data", + ); + + let _ = tx.send(false); + return + }, + }; + + let mut keep_in_storage = false; + for (relay_parent, leaf_data) in view.active_leaves.iter_mut() { + if let Some(chain) = leaf_data.fragment_chains.get_mut(¶) { + gum::trace!( target: LOG_TARGET, para = ?para, - "Received seconded candidate had mismatching validation data", + ?relay_parent, + "Candidates in chain before trying to introduce a new one: {:?}", + chain.to_vec() ); + chain.extend_from_storage(&*storage); + if chain.contains_candidate(&candidate_hash) { + keep_in_storage = true; - let _ = tx.send(Vec::new()); - return Ok(()) - }, - }; + gum::trace!( + target: LOG_TARGET, + ?relay_parent, + para = ?para, + ?candidate_hash, + "Added candidate to chain.", + ); + } else { + match chain.can_add_candidate_as_potential( + &storage, + &candidate_hash, + &candidate.descriptor.relay_parent, + parent_head_hash, + output_head_hash, + ) { + PotentialAddition::Anyhow => { + gum::trace!( + target: LOG_TARGET, + para = ?para, + ?relay_parent, + ?candidate_hash, + "Kept candidate as unconnected potential.", + ); - let mut membership = Vec::new(); - for (relay_parent, leaf_data) in &mut view.active_leaves { - if let Some(tree) = leaf_data.fragment_trees.get_mut(¶) { - tree.add_and_populate(candidate_hash, &*storage); - if let Some(depths) = tree.candidate(&candidate_hash) { - membership.push((*relay_parent, depths)); + keep_in_storage = true; + }, + _ => { + gum::trace!( + target: LOG_TARGET, + para = ?para, + ?relay_parent, + "Not introducing a new candidate: {:?}", + candidate_hash + ); + }, + } } } } - if membership.is_empty() { + // If there is at least one leaf where this candidate can be added or potentially added in the + // future, keep it in storage. + if !keep_in_storage { storage.remove_candidate(&candidate_hash); - } - - let _ = tx.send(membership); - - Ok(()) -} - -fn handle_candidate_seconded(view: &mut View, para: ParaId, candidate_hash: CandidateHash) { - let storage = match view.candidate_storage.get_mut(¶) { - None => { - gum::warn!( - target: LOG_TARGET, - para_id = ?para, - ?candidate_hash, - "Received instruction to second unknown candidate", - ); - return - }, - Some(storage) => storage, - }; - - if !storage.contains(&candidate_hash) { - gum::warn!( + gum::debug!( target: LOG_TARGET, - para_id = ?para, - ?candidate_hash, - "Received instruction to second unknown candidate", + para = ?para, + candidate = ?candidate_hash, + "Newly-seconded candidate cannot be kept under any active leaf", ); - - return } - storage.mark_seconded(&candidate_hash); + let _ = tx.send(keep_in_storage); } #[overseer::contextbounds(ProspectiveParachains, prefix = self::overseer)] @@ -513,19 +588,16 @@ async fn handle_candidate_backed( view: &mut View, para: ParaId, candidate_hash: CandidateHash, -) -> JfyiErrorResult<()> { - let storage = match view.candidate_storage.get_mut(¶) { - None => { - gum::warn!( - target: LOG_TARGET, - para_id = ?para, - ?candidate_hash, - "Received instruction to back unknown candidate", - ); +) { + let Some(storage) = view.candidate_storage.get_mut(¶) else { + gum::warn!( + target: LOG_TARGET, + para_id = ?para, + ?candidate_hash, + "Received instruction to back a candidate for unscheduled para", + ); - return Ok(()) - }, - Some(storage) => storage, + return }; if !storage.contains(&candidate_hash) { @@ -536,7 +608,7 @@ async fn handle_candidate_backed( "Received instruction to back unknown candidate", ); - return Ok(()) + return } if storage.is_backed(&candidate_hash) { @@ -547,11 +619,10 @@ async fn handle_candidate_backed( "Received redundant instruction to mark candidate as backed", ); - return Ok(()) + return } storage.mark_backed(&candidate_hash); - Ok(()) } fn answer_get_backable_candidates( @@ -562,62 +633,71 @@ fn answer_get_backable_candidates( ancestors: Ancestors, tx: oneshot::Sender>, ) { - let data = match view.active_leaves.get(&relay_parent) { - None => { - gum::debug!( - target: LOG_TARGET, - ?relay_parent, - para_id = ?para, - "Requested backable candidate for inactive relay-parent." - ); + let Some(data) = view.active_leaves.get(&relay_parent) else { + gum::debug!( + target: LOG_TARGET, + ?relay_parent, + para_id = ?para, + "Requested backable candidate for inactive relay-parent." + ); - let _ = tx.send(vec![]); - return - }, - Some(d) => d, + let _ = tx.send(vec![]); + return }; - let tree = match data.fragment_trees.get(¶) { - None => { - gum::debug!( - target: LOG_TARGET, - ?relay_parent, - para_id = ?para, - "Requested backable candidate for inactive para." - ); + let Some(chain) = data.fragment_chains.get(¶) else { + gum::debug!( + target: LOG_TARGET, + ?relay_parent, + para_id = ?para, + "Requested backable candidate for inactive para." + ); - let _ = tx.send(vec![]); - return - }, - Some(tree) => tree, + let _ = tx.send(vec![]); + return }; - let storage = match view.candidate_storage.get(¶) { - None => { - gum::warn!( - target: LOG_TARGET, - ?relay_parent, - para_id = ?para, - "No candidate storage for active para", - ); + let Some(storage) = view.candidate_storage.get(¶) else { + gum::warn!( + target: LOG_TARGET, + ?relay_parent, + para_id = ?para, + "No candidate storage for active para", + ); - let _ = tx.send(vec![]); - return - }, - Some(s) => s, + let _ = tx.send(vec![]); + return }; - let backable_candidates: Vec<_> = tree + gum::trace!( + target: LOG_TARGET, + ?relay_parent, + para_id = ?para, + "Candidate storage for para: {:?}", + storage.candidates().map(|candidate| candidate.hash()).collect::>() + ); + + gum::trace!( + target: LOG_TARGET, + ?relay_parent, + para_id = ?para, + "Candidate chain for para: {:?}", + chain.to_vec() + ); + + let backable_candidates: Vec<_> = chain .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( + storage.relay_parent_of_candidate(&child_hash).map_or_else( || { + // Here, we'd actually need to trim all of the candidates that follow. Or + // not, the runtime will do this. Impossible scenario anyway. gum::error!( target: LOG_TARGET, ?child_hash, para_id = ?para, - "Candidate is present in fragment tree but not in candidate's storage!", + "Candidate is present in fragment chain but not in candidate's storage!", ); None }, @@ -639,6 +719,7 @@ fn answer_get_backable_candidates( target: LOG_TARGET, ?relay_parent, ?backable_candidates, + ?ancestors, "Found backable candidates", ); } @@ -646,58 +727,32 @@ fn answer_get_backable_candidates( let _ = tx.send(backable_candidates); } -fn answer_hypothetical_frontier_request( +fn answer_hypothetical_membership_request( view: &View, - request: HypotheticalFrontierRequest, - tx: oneshot::Sender>, + request: HypotheticalMembershipRequest, + tx: oneshot::Sender>, + metrics: &Metrics, ) { + let _timer = metrics.time_hypothetical_membership_request(); + let mut response = Vec::with_capacity(request.candidates.len()); for candidate in request.candidates { - response.push((candidate, Vec::new())); + response.push((candidate, vec![])); } - let required_active_leaf = request.fragment_tree_relay_parent; + let required_active_leaf = request.fragment_chain_relay_parent; for (active_leaf, leaf_view) in view .active_leaves .iter() .filter(|(h, _)| required_active_leaf.as_ref().map_or(true, |x| h == &x)) { - for &mut (ref c, ref mut membership) in &mut response { - let fragment_tree = match leaf_view.fragment_trees.get(&c.candidate_para()) { - None => continue, - Some(f) => f, - }; - let candidate_storage = match view.candidate_storage.get(&c.candidate_para()) { - None => continue, - Some(storage) => storage, - }; - - let candidate_hash = c.candidate_hash(); - let hypothetical = match c { - HypotheticalCandidate::Complete { receipt, persisted_validation_data, .. } => - fragment_tree::HypotheticalCandidate::Complete { - receipt: Cow::Borrowed(receipt), - persisted_validation_data: Cow::Borrowed(persisted_validation_data), - }, - HypotheticalCandidate::Incomplete { - parent_head_data_hash, - candidate_relay_parent, - .. - } => fragment_tree::HypotheticalCandidate::Incomplete { - relay_parent: *candidate_relay_parent, - parent_head_data_hash: *parent_head_data_hash, - }, - }; - - let depths = fragment_tree.hypothetical_depths( - candidate_hash, - hypothetical, - candidate_storage, - request.backed_in_path_only, - ); + for &mut (ref candidate, ref mut membership) in &mut response { + let para_id = &candidate.candidate_para(); + let Some(fragment_chain) = leaf_view.fragment_chains.get(para_id) else { continue }; + let Some(candidate_storage) = view.candidate_storage.get(para_id) else { continue }; - if !depths.is_empty() { - membership.push((*active_leaf, depths)); + if fragment_chain.hypothetical_membership(candidate.clone(), candidate_storage) { + membership.push(*active_leaf); } } } @@ -705,31 +760,6 @@ fn answer_hypothetical_frontier_request( let _ = tx.send(response); } -fn fragment_tree_membership( - active_leaves: &HashMap, - para: ParaId, - candidate: CandidateHash, -) -> FragmentTreeMembership { - let mut membership = Vec::new(); - for (relay_parent, view_data) in active_leaves { - if let Some(tree) = view_data.fragment_trees.get(¶) { - if let Some(depths) = tree.candidate(&candidate) { - membership.push((*relay_parent, depths)); - } - } - } - membership -} - -fn answer_tree_membership_request( - view: &View, - para: ParaId, - candidate: CandidateHash, - tx: oneshot::Sender, -) { - let _ = tx.send(fragment_tree_membership(&view.active_leaves, para, candidate)); -} - fn answer_minimum_relay_parents_request( view: &View, relay_parent: Hash, @@ -737,8 +767,8 @@ fn answer_minimum_relay_parents_request( ) { let mut v = Vec::new(); if let Some(leaf_data) = view.active_leaves.get(&relay_parent) { - for (para_id, fragment_tree) in &leaf_data.fragment_trees { - v.push((*para_id, fragment_tree.scope().earliest_relay_parent().number)); + for (para_id, fragment_chain) in &leaf_data.fragment_chains { + v.push((*para_id, fragment_chain.scope().earliest_relay_parent().number)); } } @@ -752,9 +782,9 @@ fn answer_prospective_validation_data_request( ) { // 1. Try to get the head-data from the candidate store if known. // 2. Otherwise, it might exist as the base in some relay-parent and we can find it by iterating - // fragment trees. + // fragment chains. // 3. Otherwise, it is unknown. - // 4. Also try to find the relay parent block info by scanning fragment trees. + // 4. Also try to find the relay parent block info by scanning fragment chains. // 5. If head data and relay parent block info are found - success. Otherwise, failure. let storage = match view.candidate_storage.get(&request.para_id) { @@ -776,35 +806,32 @@ fn answer_prospective_validation_data_request( let mut relay_parent_info = None; let mut max_pov_size = None; - for fragment_tree in view + for fragment_chain in view .active_leaves .values() - .filter_map(|x| x.fragment_trees.get(&request.para_id)) + .filter_map(|x| x.fragment_chains.get(&request.para_id)) { if head_data.is_some() && relay_parent_info.is_some() && max_pov_size.is_some() { break } if relay_parent_info.is_none() { - relay_parent_info = - fragment_tree.scope().ancestor_by_hash(&request.candidate_relay_parent); + relay_parent_info = fragment_chain.scope().ancestor(&request.candidate_relay_parent); } if head_data.is_none() { - let required_parent = &fragment_tree.scope().base_constraints().required_parent; + let required_parent = &fragment_chain.scope().base_constraints().required_parent; if required_parent.hash() == parent_head_data_hash { head_data = Some(required_parent.clone()); } } if max_pov_size.is_none() { - let contains_ancestor = fragment_tree - .scope() - .ancestor_by_hash(&request.candidate_relay_parent) - .is_some(); + let contains_ancestor = + fragment_chain.scope().ancestor(&request.candidate_relay_parent).is_some(); if contains_ancestor { // We are leaning hard on two assumptions here. - // 1. That the fragment tree never contains allowed relay-parents whose session for + // 1. That the fragment chain never contains allowed relay-parents whose session for // children is different from that of the base block's. // 2. That the max_pov_size is only configurable per session. - max_pov_size = Some(fragment_tree.scope().base_constraints().max_pov_size); + max_pov_size = Some(fragment_chain.scope().base_constraints().max_pov_size); } } } @@ -843,7 +870,6 @@ async fn fetch_backing_state( async fn fetch_upcoming_paras( ctx: &mut Context, relay_parent: Hash, - pending_availability: &mut HashSet, ) -> JfyiErrorResult> { let (tx, rx) = oneshot::channel(); @@ -860,8 +886,6 @@ async fn fetch_upcoming_paras( for core in cores { match core { CoreState::Occupied(occupied) => { - pending_availability.insert(occupied.candidate_hash); - if let Some(next_up_on_available) = occupied.next_up_on_available { upcoming.insert(next_up_on_available.para_id); } diff --git a/polkadot/node/core/prospective-parachains/src/metrics.rs b/polkadot/node/core/prospective-parachains/src/metrics.rs index 57061497a1c0d2923dedeea341a4cf4cf2ed8807..5abd9f56f306cdad515b93c794a51de516417b88 100644 --- a/polkadot/node/core/prospective-parachains/src/metrics.rs +++ b/polkadot/node/core/prospective-parachains/src/metrics.rs @@ -14,11 +14,18 @@ // You should have received a copy of the GNU General Public License // along with Polkadot. If not, see . -use polkadot_node_subsystem_util::metrics::{self, prometheus}; +use polkadot_node_subsystem::prometheus::Opts; +use polkadot_node_subsystem_util::metrics::{ + self, + prometheus::{self, GaugeVec, U64}, +}; #[derive(Clone)] pub(crate) struct MetricsInner { - pub(crate) prune_view_candidate_storage: prometheus::Histogram, + prune_view_candidate_storage: prometheus::Histogram, + introduce_seconded_candidate: prometheus::Histogram, + hypothetical_membership: prometheus::Histogram, + candidate_storage_count: prometheus::GaugeVec, } /// Candidate backing metrics. @@ -34,6 +41,40 @@ impl Metrics { .as_ref() .map(|metrics| metrics.prune_view_candidate_storage.start_timer()) } + + /// Provide a timer for handling `IntroduceSecondedCandidate` which observes on drop. + pub fn time_introduce_seconded_candidate( + &self, + ) -> Option { + self.0 + .as_ref() + .map(|metrics| metrics.introduce_seconded_candidate.start_timer()) + } + + /// Provide a timer for handling `GetHypotheticalMembership` which observes on drop. + pub fn time_hypothetical_membership_request( + &self, + ) -> Option { + self.0.as_ref().map(|metrics| metrics.hypothetical_membership.start_timer()) + } + + /// Record the size of the candidate storage. First param is the connected candidates count, + /// second param is the unconnected candidates count. + pub fn record_candidate_storage_size(&self, connected_count: u64, unconnected_count: u64) { + self.0.as_ref().map(|metrics| { + metrics + .candidate_storage_count + .with_label_values(&["connected"]) + .set(connected_count) + }); + + self.0.as_ref().map(|metrics| { + metrics + .candidate_storage_count + .with_label_values(&["unconnected"]) + .set(unconnected_count) + }); + } } impl metrics::Metrics for Metrics { @@ -46,6 +87,30 @@ impl metrics::Metrics for Metrics { ))?, registry, )?, + introduce_seconded_candidate: prometheus::register( + prometheus::Histogram::with_opts(prometheus::HistogramOpts::new( + "polkadot_parachain_prospective_parachains_introduce_seconded_candidate", + "Time spent within `prospective_parachains::handle_introduce_seconded_candidate`", + ))?, + registry, + )?, + hypothetical_membership: prometheus::register( + prometheus::Histogram::with_opts(prometheus::HistogramOpts::new( + "polkadot_parachain_prospective_parachains_hypothetical_membership", + "Time spent responding to `GetHypotheticalMembership`", + ))?, + registry, + )?, + candidate_storage_count: prometheus::register( + GaugeVec::new( + Opts::new( + "polkadot_parachain_prospective_parachains_candidate_storage_count", + "Number of candidates present in the candidate storage, split by connected and unconnected" + ), + &["type"], + )?, + registry, + )?, }; Ok(Metrics(Some(metrics))) } diff --git a/polkadot/node/core/prospective-parachains/src/tests.rs b/polkadot/node/core/prospective-parachains/src/tests.rs index 8989911a33239d3b6f775bcf6271c6f40d9a0bac..4bc47367278864e6f5e7136fe07a4fe1d1be88a5 100644 --- a/polkadot/node/core/prospective-parachains/src/tests.rs +++ b/polkadot/node/core/prospective-parachains/src/tests.rs @@ -19,7 +19,7 @@ use assert_matches::assert_matches; use polkadot_node_subsystem::{ errors::RuntimeApiError, messages::{ - AllMessages, HypotheticalFrontierRequest, ParentHeadData, ProspectiveParachainsMessage, + AllMessages, HypotheticalMembershipRequest, ParentHeadData, ProspectiveParachainsMessage, ProspectiveValidationDataRequest, }, }; @@ -340,36 +340,42 @@ async fn deactivate_leaf(virtual_overseer: &mut VirtualOverseer, hash: Hash) { .await; } -async fn introduce_candidate( +async fn introduce_seconded_candidate( virtual_overseer: &mut VirtualOverseer, candidate: CommittedCandidateReceipt, pvd: PersistedValidationData, ) { - let req = IntroduceCandidateRequest { + let req = IntroduceSecondedCandidateRequest { candidate_para: candidate.descriptor().para_id, candidate_receipt: candidate, persisted_validation_data: pvd, }; - let (tx, _) = oneshot::channel(); + let (tx, rx) = oneshot::channel(); virtual_overseer .send(overseer::FromOrchestra::Communication { - msg: ProspectiveParachainsMessage::IntroduceCandidate(req, tx), + msg: ProspectiveParachainsMessage::IntroduceSecondedCandidate(req, tx), }) .await; + assert!(rx.await.unwrap()); } -async fn second_candidate( +async fn introduce_seconded_candidate_failed( virtual_overseer: &mut VirtualOverseer, candidate: CommittedCandidateReceipt, + pvd: PersistedValidationData, ) { + let req = IntroduceSecondedCandidateRequest { + candidate_para: candidate.descriptor().para_id, + candidate_receipt: candidate, + persisted_validation_data: pvd, + }; + let (tx, rx) = oneshot::channel(); virtual_overseer .send(overseer::FromOrchestra::Communication { - msg: ProspectiveParachainsMessage::CandidateSeconded( - candidate.descriptor.para_id, - candidate.hash(), - ), + msg: ProspectiveParachainsMessage::IntroduceSecondedCandidate(req, tx), }) .await; + assert!(!rx.await.unwrap()); } async fn back_candidate( @@ -387,22 +393,6 @@ async fn back_candidate( .await; } -async fn get_membership( - virtual_overseer: &mut VirtualOverseer, - para_id: ParaId, - candidate_hash: CandidateHash, - expected_membership_response: Vec<(Hash, Vec)>, -) { - let (tx, rx) = oneshot::channel(); - virtual_overseer - .send(overseer::FromOrchestra::Communication { - msg: ProspectiveParachainsMessage::GetTreeMembership(para_id, candidate_hash, tx), - }) - .await; - let resp = rx.await.unwrap(); - assert_eq!(resp, expected_membership_response); -} - async fn get_backable_candidates( virtual_overseer: &mut VirtualOverseer, leaf: &TestLeaf, @@ -420,42 +410,39 @@ async fn get_backable_candidates( }) .await; let resp = rx.await.unwrap(); - assert_eq!(resp.len(), expected_result.len()); assert_eq!(resp, expected_result); } -async fn get_hypothetical_frontier( +async fn get_hypothetical_membership( virtual_overseer: &mut VirtualOverseer, candidate_hash: CandidateHash, receipt: CommittedCandidateReceipt, persisted_validation_data: PersistedValidationData, - fragment_tree_relay_parent: Hash, - backed_in_path_only: bool, - expected_depths: Vec, + expected_membership: Vec, ) { let hypothetical_candidate = HypotheticalCandidate::Complete { candidate_hash, receipt: Arc::new(receipt), persisted_validation_data, }; - let request = HypotheticalFrontierRequest { + let request = HypotheticalMembershipRequest { candidates: vec![hypothetical_candidate.clone()], - fragment_tree_relay_parent: Some(fragment_tree_relay_parent), - backed_in_path_only, + fragment_chain_relay_parent: None, }; let (tx, rx) = oneshot::channel(); virtual_overseer .send(overseer::FromOrchestra::Communication { - msg: ProspectiveParachainsMessage::GetHypotheticalFrontier(request, tx), + msg: ProspectiveParachainsMessage::GetHypotheticalMembership(request, tx), }) .await; - let resp = rx.await.unwrap(); - let expected_frontier = if expected_depths.is_empty() { - vec![(hypothetical_candidate, vec![])] - } else { - vec![(hypothetical_candidate, vec![(fragment_tree_relay_parent, expected_depths)])] - }; - assert_eq!(resp, expected_frontier); + let mut resp = rx.await.unwrap(); + assert_eq!(resp.len(), 1); + let (candidate, membership) = resp.remove(0); + assert_eq!(candidate, hypothetical_candidate); + assert_eq!( + membership.into_iter().collect::>(), + expected_membership.into_iter().collect::>() + ); } async fn get_pvd( @@ -513,11 +500,11 @@ fn should_do_no_work_if_async_backing_disabled_for_leaf() { } // Send some candidates and make sure all are found: -// - Two for the same leaf A +// - Two for the same leaf A (one for parachain 1 and one for parachain 2) // - One for leaf B on parachain 1 // - One for leaf C on parachain 2 #[test] -fn send_candidates_and_check_if_found() { +fn introduce_candidates_basic() { let test_state = TestState::default(); let view = test_harness(|mut virtual_overseer| async move { // Leaf A @@ -563,7 +550,7 @@ fn send_candidates_and_check_if_found() { test_state.validation_code_hash, ); let candidate_hash_a1 = candidate_a1.hash(); - let response_a1 = vec![(leaf_a.hash, vec![0])]; + let response_a1 = vec![(candidate_hash_a1, leaf_a.hash)]; // Candidate A2 let (candidate_a2, pvd_a2) = make_candidate( @@ -575,7 +562,7 @@ fn send_candidates_and_check_if_found() { test_state.validation_code_hash, ); let candidate_hash_a2 = candidate_a2.hash(); - let response_a2 = vec![(leaf_a.hash, vec![0])]; + let response_a2 = vec![(candidate_hash_a2, leaf_a.hash)]; // Candidate B let (candidate_b, pvd_b) = make_candidate( @@ -587,7 +574,7 @@ fn send_candidates_and_check_if_found() { test_state.validation_code_hash, ); let candidate_hash_b = candidate_b.hash(); - let response_b = vec![(leaf_b.hash, vec![0])]; + let response_b = vec![(candidate_hash_b, leaf_b.hash)]; // Candidate C let (candidate_c, pvd_c) = make_candidate( @@ -599,25 +586,78 @@ fn send_candidates_and_check_if_found() { test_state.validation_code_hash, ); let candidate_hash_c = candidate_c.hash(); - let response_c = vec![(leaf_c.hash, vec![0])]; + let response_c = vec![(candidate_hash_c, leaf_c.hash)]; // Introduce candidates. - introduce_candidate(&mut virtual_overseer, candidate_a1, pvd_a1).await; - introduce_candidate(&mut virtual_overseer, candidate_a2, pvd_a2).await; - introduce_candidate(&mut virtual_overseer, candidate_b, pvd_b).await; - introduce_candidate(&mut virtual_overseer, candidate_c, pvd_c).await; + introduce_seconded_candidate(&mut virtual_overseer, candidate_a1.clone(), pvd_a1).await; + introduce_seconded_candidate(&mut virtual_overseer, candidate_a2.clone(), pvd_a2).await; + introduce_seconded_candidate(&mut virtual_overseer, candidate_b.clone(), pvd_b).await; + introduce_seconded_candidate(&mut virtual_overseer, candidate_c.clone(), pvd_c).await; + + // Back candidates. Otherwise, we cannot check membership with GetBackableCandidates. + back_candidate(&mut virtual_overseer, &candidate_a1, candidate_hash_a1).await; + back_candidate(&mut virtual_overseer, &candidate_a2, candidate_hash_a2).await; + back_candidate(&mut virtual_overseer, &candidate_b, candidate_hash_b).await; + back_candidate(&mut virtual_overseer, &candidate_c, candidate_hash_c).await; // Check candidate tree membership. - get_membership(&mut virtual_overseer, 1.into(), candidate_hash_a1, response_a1).await; - get_membership(&mut virtual_overseer, 2.into(), candidate_hash_a2, response_a2).await; - get_membership(&mut virtual_overseer, 1.into(), candidate_hash_b, response_b).await; - get_membership(&mut virtual_overseer, 2.into(), candidate_hash_c, response_c).await; + get_backable_candidates( + &mut virtual_overseer, + &leaf_a, + 1.into(), + Ancestors::default(), + 5, + response_a1, + ) + .await; + get_backable_candidates( + &mut virtual_overseer, + &leaf_a, + 2.into(), + Ancestors::default(), + 5, + response_a2, + ) + .await; + get_backable_candidates( + &mut virtual_overseer, + &leaf_b, + 1.into(), + Ancestors::default(), + 5, + response_b, + ) + .await; + get_backable_candidates( + &mut virtual_overseer, + &leaf_c, + 2.into(), + Ancestors::default(), + 5, + response_c, + ) + .await; + + // Check membership on other leaves. + get_backable_candidates( + &mut virtual_overseer, + &leaf_b, + 2.into(), + Ancestors::default(), + 5, + vec![], + ) + .await; - // The candidates should not be found on other parachains. - get_membership(&mut virtual_overseer, 2.into(), candidate_hash_a1, vec![]).await; - get_membership(&mut virtual_overseer, 1.into(), candidate_hash_a2, vec![]).await; - get_membership(&mut virtual_overseer, 2.into(), candidate_hash_b, vec![]).await; - get_membership(&mut virtual_overseer, 1.into(), candidate_hash_c, vec![]).await; + get_backable_candidates( + &mut virtual_overseer, + &leaf_c, + 1.into(), + Ancestors::default(), + 5, + vec![], + ) + .await; virtual_overseer }); @@ -629,10 +669,8 @@ fn send_candidates_and_check_if_found() { assert_eq!(view.candidate_storage.get(&2.into()).unwrap().len(), (2, 2)); } -// Send some candidates, check if the candidate won't be found once its relay parent leaves the -// view. #[test] -fn check_candidate_parent_leaving_view() { +fn introduce_candidate_multiple_times() { let test_state = TestState::default(); let view = test_harness(|mut virtual_overseer| async move { // Leaf A @@ -644,32 +682,11 @@ fn check_candidate_parent_leaving_view() { (2.into(), PerParaData::new(100, HeadData(vec![2, 3, 4]))), ], }; - // Leaf B - let leaf_b = TestLeaf { - number: 101, - hash: Hash::from_low_u64_be(131), - para_data: vec![ - (1.into(), PerParaData::new(99, HeadData(vec![3, 4, 5]))), - (2.into(), PerParaData::new(101, HeadData(vec![4, 5, 6]))), - ], - }; - // Leaf C - let leaf_c = TestLeaf { - number: 102, - hash: Hash::from_low_u64_be(132), - para_data: vec![ - (1.into(), PerParaData::new(102, HeadData(vec![5, 6, 7]))), - (2.into(), PerParaData::new(98, HeadData(vec![6, 7, 8]))), - ], - }; - // Activate leaves. activate_leaf(&mut virtual_overseer, &leaf_a, &test_state).await; - activate_leaf(&mut virtual_overseer, &leaf_b, &test_state).await; - activate_leaf(&mut virtual_overseer, &leaf_c, &test_state).await; - // Candidate A1 - let (candidate_a1, pvd_a1) = make_candidate( + // Candidate A. + let (candidate_a, pvd_a) = make_candidate( leaf_a.hash, leaf_a.number, 1.into(), @@ -677,86 +694,45 @@ fn check_candidate_parent_leaving_view() { HeadData(vec![1]), test_state.validation_code_hash, ); - let candidate_hash_a1 = candidate_a1.hash(); - - // Candidate A2 - let (candidate_a2, pvd_a2) = make_candidate( - leaf_a.hash, - leaf_a.number, - 2.into(), - HeadData(vec![2, 3, 4]), - HeadData(vec![2]), - test_state.validation_code_hash, - ); - let candidate_hash_a2 = candidate_a2.hash(); - - // Candidate B - let (candidate_b, pvd_b) = make_candidate( - leaf_b.hash, - leaf_b.number, - 1.into(), - HeadData(vec![3, 4, 5]), - HeadData(vec![3]), - test_state.validation_code_hash, - ); - let candidate_hash_b = candidate_b.hash(); - let response_b = vec![(leaf_b.hash, vec![0])]; - - // Candidate C - let (candidate_c, pvd_c) = make_candidate( - leaf_c.hash, - leaf_c.number, - 2.into(), - HeadData(vec![6, 7, 8]), - HeadData(vec![4]), - test_state.validation_code_hash, - ); - let candidate_hash_c = candidate_c.hash(); - let response_c = vec![(leaf_c.hash, vec![0])]; + let candidate_hash_a = candidate_a.hash(); + let response_a = vec![(candidate_hash_a, leaf_a.hash)]; // Introduce candidates. - introduce_candidate(&mut virtual_overseer, candidate_a1, pvd_a1).await; - introduce_candidate(&mut virtual_overseer, candidate_a2, pvd_a2).await; - introduce_candidate(&mut virtual_overseer, candidate_b, pvd_b).await; - introduce_candidate(&mut virtual_overseer, candidate_c, pvd_c).await; - - // Deactivate leaf A. - deactivate_leaf(&mut virtual_overseer, leaf_a.hash).await; - - // Candidates A1 and A2 should be gone. Candidates B and C should remain. - get_membership(&mut virtual_overseer, 1.into(), candidate_hash_a1, vec![]).await; - get_membership(&mut virtual_overseer, 2.into(), candidate_hash_a2, vec![]).await; - get_membership(&mut virtual_overseer, 1.into(), candidate_hash_b, response_b).await; - get_membership(&mut virtual_overseer, 2.into(), candidate_hash_c, response_c.clone()).await; - - // Deactivate leaf B. - deactivate_leaf(&mut virtual_overseer, leaf_b.hash).await; + introduce_seconded_candidate(&mut virtual_overseer, candidate_a.clone(), pvd_a.clone()) + .await; - // Candidate B should be gone, C should remain. - get_membership(&mut virtual_overseer, 1.into(), candidate_hash_a1, vec![]).await; - get_membership(&mut virtual_overseer, 2.into(), candidate_hash_a2, vec![]).await; - get_membership(&mut virtual_overseer, 1.into(), candidate_hash_b, vec![]).await; - get_membership(&mut virtual_overseer, 2.into(), candidate_hash_c, response_c).await; + // Back candidates. Otherwise, we cannot check membership with GetBackableCandidates. + back_candidate(&mut virtual_overseer, &candidate_a, candidate_hash_a).await; - // Deactivate leaf C. - deactivate_leaf(&mut virtual_overseer, leaf_c.hash).await; + // Check candidate tree membership. + get_backable_candidates( + &mut virtual_overseer, + &leaf_a, + 1.into(), + Ancestors::default(), + 5, + response_a, + ) + .await; - // Candidate C should be gone. - get_membership(&mut virtual_overseer, 1.into(), candidate_hash_a1, vec![]).await; - get_membership(&mut virtual_overseer, 2.into(), candidate_hash_a2, vec![]).await; - get_membership(&mut virtual_overseer, 1.into(), candidate_hash_b, vec![]).await; - get_membership(&mut virtual_overseer, 2.into(), candidate_hash_c, vec![]).await; + // Introduce the same candidate multiple times. It'll return true but it won't be added. + // We'll check below that the candidate count remains 1. + for _ in 0..5 { + introduce_seconded_candidate(&mut virtual_overseer, candidate_a.clone(), pvd_a.clone()) + .await; + } virtual_overseer }); - assert_eq!(view.active_leaves.len(), 0); - assert_eq!(view.candidate_storage.len(), 0); + assert_eq!(view.active_leaves.len(), 1); + assert_eq!(view.candidate_storage.len(), 2); + assert_eq!(view.candidate_storage.get(&1.into()).unwrap().len(), (1, 1)); + assert_eq!(view.candidate_storage.get(&2.into()).unwrap().len(), (0, 0)); } -// Introduce a candidate to multiple forks, see how the membership is returned. #[test] -fn check_candidate_on_multiple_forks() { +fn fragment_chain_length_is_bounded() { let test_state = TestState::default(); let view = test_harness(|mut virtual_overseer| async move { // Leaf A @@ -768,31 +744,16 @@ fn check_candidate_on_multiple_forks() { (2.into(), PerParaData::new(100, HeadData(vec![2, 3, 4]))), ], }; - // Leaf B - let leaf_b = TestLeaf { - number: 101, - hash: Hash::from_low_u64_be(131), - para_data: vec![ - (1.into(), PerParaData::new(99, HeadData(vec![3, 4, 5]))), - (2.into(), PerParaData::new(101, HeadData(vec![4, 5, 6]))), - ], - }; - // Leaf C - let leaf_c = TestLeaf { - number: 102, - hash: Hash::from_low_u64_be(132), - para_data: vec![ - (1.into(), PerParaData::new(102, HeadData(vec![5, 6, 7]))), - (2.into(), PerParaData::new(98, HeadData(vec![6, 7, 8]))), - ], - }; - // Activate leaves. - activate_leaf(&mut virtual_overseer, &leaf_a, &test_state).await; - activate_leaf(&mut virtual_overseer, &leaf_b, &test_state).await; - activate_leaf(&mut virtual_overseer, &leaf_c, &test_state).await; + activate_leaf_with_params( + &mut virtual_overseer, + &leaf_a, + &test_state, + AsyncBackingParams { max_candidate_depth: 1, allowed_ancestry_len: 3 }, + ) + .await; - // Candidate on leaf A. + // Candidates A, B and C form a chain. let (candidate_a, pvd_a) = make_candidate( leaf_a.hash, leaf_a.number, @@ -801,56 +762,59 @@ fn check_candidate_on_multiple_forks() { HeadData(vec![1]), test_state.validation_code_hash, ); - let candidate_hash_a = candidate_a.hash(); - let response_a = vec![(leaf_a.hash, vec![0])]; - - // Candidate on leaf B. let (candidate_b, pvd_b) = make_candidate( - leaf_b.hash, - leaf_b.number, + leaf_a.hash, + leaf_a.number, 1.into(), - HeadData(vec![3, 4, 5]), HeadData(vec![1]), + HeadData(vec![2]), test_state.validation_code_hash, ); - let candidate_hash_b = candidate_b.hash(); - let response_b = vec![(leaf_b.hash, vec![0])]; - - // Candidate on leaf C. let (candidate_c, pvd_c) = make_candidate( - leaf_c.hash, - leaf_c.number, + leaf_a.hash, + leaf_a.number, 1.into(), - HeadData(vec![5, 6, 7]), - HeadData(vec![1]), + HeadData(vec![2]), + HeadData(vec![3]), test_state.validation_code_hash, ); - let candidate_hash_c = candidate_c.hash(); - let response_c = vec![(leaf_c.hash, vec![0])]; - // Introduce candidates on all three leaves. - introduce_candidate(&mut virtual_overseer, candidate_a.clone(), pvd_a).await; - introduce_candidate(&mut virtual_overseer, candidate_b.clone(), pvd_b).await; - introduce_candidate(&mut virtual_overseer, candidate_c.clone(), pvd_c).await; + // Introduce candidates A and B. Since max depth is 1, only these two will be allowed. + introduce_seconded_candidate(&mut virtual_overseer, candidate_a.clone(), pvd_a.clone()) + .await; + introduce_seconded_candidate(&mut virtual_overseer, candidate_b.clone(), pvd_b.clone()) + .await; + + // Back candidates. Otherwise, we cannot check membership with GetBackableCandidates. + back_candidate(&mut virtual_overseer, &candidate_a, candidate_a.hash()).await; + back_candidate(&mut virtual_overseer, &candidate_b, candidate_b.hash()).await; // Check candidate tree membership. - get_membership(&mut virtual_overseer, 1.into(), candidate_hash_a, response_a).await; - get_membership(&mut virtual_overseer, 1.into(), candidate_hash_b, response_b).await; - get_membership(&mut virtual_overseer, 1.into(), candidate_hash_c, response_c).await; + get_backable_candidates( + &mut virtual_overseer, + &leaf_a, + 1.into(), + Ancestors::default(), + 5, + vec![(candidate_a.hash(), leaf_a.hash), (candidate_b.hash(), leaf_a.hash)], + ) + .await; + + // Introducing C will fail. + introduce_seconded_candidate_failed(&mut virtual_overseer, candidate_c, pvd_c.clone()) + .await; virtual_overseer }); - assert_eq!(view.active_leaves.len(), 3); + assert_eq!(view.active_leaves.len(), 1); assert_eq!(view.candidate_storage.len(), 2); - // Three parents and three candidates on para 1. - assert_eq!(view.candidate_storage.get(&1.into()).unwrap().len(), (3, 3)); + assert_eq!(view.candidate_storage.get(&1.into()).unwrap().len(), (2, 2)); assert_eq!(view.candidate_storage.get(&2.into()).unwrap().len(), (0, 0)); } -// Backs some candidates and tests `GetBackableCandidates` when requesting a single candidate. #[test] -fn check_backable_query_single_candidate() { +fn unconnected_candidate_count_is_bounded() { let test_state = TestState::default(); let view = test_harness(|mut virtual_overseer| async move { // Leaf A @@ -862,54 +826,534 @@ fn check_backable_query_single_candidate() { (2.into(), PerParaData::new(100, HeadData(vec![2, 3, 4]))), ], }; - // Activate leaves. - activate_leaf(&mut virtual_overseer, &leaf_a, &test_state).await; + activate_leaf_with_params( + &mut virtual_overseer, + &leaf_a, + &test_state, + AsyncBackingParams { max_candidate_depth: 1, allowed_ancestry_len: 3 }, + ) + .await; - // Candidate A + // Candidates A, B and C are all potential candidates but don't form a chain. let (candidate_a, pvd_a) = make_candidate( leaf_a.hash, leaf_a.number, 1.into(), - HeadData(vec![1, 2, 3]), HeadData(vec![1]), + HeadData(vec![2]), test_state.validation_code_hash, ); - let candidate_hash_a = candidate_a.hash(); - - // Candidate B - let (mut candidate_b, pvd_b) = make_candidate( + let (candidate_b, pvd_b) = make_candidate( leaf_a.hash, leaf_a.number, 1.into(), - HeadData(vec![1]), - HeadData(vec![2]), + HeadData(vec![3]), + HeadData(vec![4]), + test_state.validation_code_hash, + ); + let (candidate_c, pvd_c) = make_candidate( + leaf_a.hash, + leaf_a.number, + 1.into(), + HeadData(vec![4]), + HeadData(vec![5]), test_state.validation_code_hash, ); - // Set a field to make this candidate unique. - candidate_b.descriptor.para_head = Hash::from_low_u64_le(1000); - let candidate_hash_b = candidate_b.hash(); - - // Introduce candidates. - introduce_candidate(&mut virtual_overseer, candidate_a.clone(), pvd_a).await; - introduce_candidate(&mut virtual_overseer, candidate_b.clone(), pvd_b).await; - // Should not get any backable candidates. - get_backable_candidates( + // Introduce candidates A and B. Although max depth is 1 (which should allow for two + // candidates), only 1 is allowed, because the last candidate must be a connected candidate. + introduce_seconded_candidate(&mut virtual_overseer, candidate_a.clone(), pvd_a.clone()) + .await; + introduce_seconded_candidate_failed( &mut virtual_overseer, - &leaf_a, + candidate_b.clone(), + pvd_b.clone(), + ) + .await; + + // Back candidates. Otherwise, we cannot check membership with GetBackableCandidates. + back_candidate(&mut virtual_overseer, &candidate_a, candidate_a.hash()).await; + + // Check candidate tree membership. Should be empty. + get_backable_candidates( + &mut virtual_overseer, + &leaf_a, + 1.into(), + Ancestors::default(), + 5, + vec![], + ) + .await; + + // Introducing C will also fail. + introduce_seconded_candidate_failed(&mut virtual_overseer, candidate_c, pvd_c.clone()) + .await; + + virtual_overseer + }); + + assert_eq!(view.active_leaves.len(), 1); + assert_eq!(view.candidate_storage.len(), 2); + assert_eq!(view.candidate_storage.get(&1.into()).unwrap().len(), (1, 1)); + assert_eq!(view.candidate_storage.get(&2.into()).unwrap().len(), (0, 0)); +} + +// Send some candidates, check if the candidate won't be found once its relay parent leaves the +// view. +#[test] +fn introduce_candidate_parent_leaving_view() { + 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]))), + ], + }; + // Leaf B + let leaf_b = TestLeaf { + number: 101, + hash: Hash::from_low_u64_be(131), + para_data: vec![ + (1.into(), PerParaData::new(99, HeadData(vec![3, 4, 5]))), + (2.into(), PerParaData::new(101, HeadData(vec![4, 5, 6]))), + ], + }; + // Leaf C + let leaf_c = TestLeaf { + number: 102, + hash: Hash::from_low_u64_be(132), + para_data: vec![ + (1.into(), PerParaData::new(102, HeadData(vec![5, 6, 7]))), + (2.into(), PerParaData::new(98, HeadData(vec![6, 7, 8]))), + ], + }; + + // Activate leaves. + activate_leaf(&mut virtual_overseer, &leaf_a, &test_state).await; + activate_leaf(&mut virtual_overseer, &leaf_b, &test_state).await; + activate_leaf(&mut virtual_overseer, &leaf_c, &test_state).await; + + // Candidate A1 + let (candidate_a1, pvd_a1) = make_candidate( + leaf_a.hash, + leaf_a.number, + 1.into(), + HeadData(vec![1, 2, 3]), + HeadData(vec![1]), + test_state.validation_code_hash, + ); + let candidate_hash_a1 = candidate_a1.hash(); + + // Candidate A2 + let (candidate_a2, pvd_a2) = make_candidate( + leaf_a.hash, + leaf_a.number, + 2.into(), + HeadData(vec![2, 3, 4]), + HeadData(vec![2]), + test_state.validation_code_hash, + ); + let candidate_hash_a2 = candidate_a2.hash(); + + // Candidate B + let (candidate_b, pvd_b) = make_candidate( + leaf_b.hash, + leaf_b.number, + 1.into(), + HeadData(vec![3, 4, 5]), + HeadData(vec![3]), + test_state.validation_code_hash, + ); + let candidate_hash_b = candidate_b.hash(); + let response_b = vec![(candidate_hash_b, leaf_b.hash)]; + + // Candidate C + let (candidate_c, pvd_c) = make_candidate( + leaf_c.hash, + leaf_c.number, + 2.into(), + HeadData(vec![6, 7, 8]), + HeadData(vec![4]), + test_state.validation_code_hash, + ); + let candidate_hash_c = candidate_c.hash(); + let response_c = vec![(candidate_hash_c, leaf_c.hash)]; + + // Introduce candidates. + introduce_seconded_candidate(&mut virtual_overseer, candidate_a1.clone(), pvd_a1).await; + introduce_seconded_candidate(&mut virtual_overseer, candidate_a2.clone(), pvd_a2).await; + introduce_seconded_candidate(&mut virtual_overseer, candidate_b.clone(), pvd_b).await; + introduce_seconded_candidate(&mut virtual_overseer, candidate_c.clone(), pvd_c).await; + + // Back candidates. Otherwise, we cannot check membership with GetBackableCandidates. + back_candidate(&mut virtual_overseer, &candidate_a1, candidate_hash_a1).await; + back_candidate(&mut virtual_overseer, &candidate_a2, candidate_hash_a2).await; + back_candidate(&mut virtual_overseer, &candidate_b, candidate_hash_b).await; + back_candidate(&mut virtual_overseer, &candidate_c, candidate_hash_c).await; + + // Deactivate leaf A. + deactivate_leaf(&mut virtual_overseer, leaf_a.hash).await; + + // Candidates A1 and A2 should be gone. Candidates B and C should remain. + get_backable_candidates( + &mut virtual_overseer, + &leaf_a, + 1.into(), + Ancestors::default(), + 5, + vec![], + ) + .await; + get_backable_candidates( + &mut virtual_overseer, + &leaf_a, + 2.into(), + Ancestors::default(), + 5, + vec![], + ) + .await; + get_backable_candidates( + &mut virtual_overseer, + &leaf_b, + 1.into(), + Ancestors::default(), + 5, + response_b, + ) + .await; + get_backable_candidates( + &mut virtual_overseer, + &leaf_c, + 2.into(), + Ancestors::default(), + 5, + response_c.clone(), + ) + .await; + + // Deactivate leaf B. + deactivate_leaf(&mut virtual_overseer, leaf_b.hash).await; + + // Candidate B should be gone, C should remain. + get_backable_candidates( + &mut virtual_overseer, + &leaf_a, + 1.into(), + Ancestors::default(), + 5, + vec![], + ) + .await; + get_backable_candidates( + &mut virtual_overseer, + &leaf_a, + 2.into(), + Ancestors::default(), + 5, + vec![], + ) + .await; + get_backable_candidates( + &mut virtual_overseer, + &leaf_b, + 1.into(), + Ancestors::default(), + 5, + vec![], + ) + .await; + get_backable_candidates( + &mut virtual_overseer, + &leaf_c, + 2.into(), + Ancestors::default(), + 5, + response_c, + ) + .await; + + // Deactivate leaf C. + deactivate_leaf(&mut virtual_overseer, leaf_c.hash).await; + + // Candidate C should be gone. + get_backable_candidates( + &mut virtual_overseer, + &leaf_a, + 1.into(), + Ancestors::default(), + 5, + vec![], + ) + .await; + get_backable_candidates( + &mut virtual_overseer, + &leaf_a, + 2.into(), + Ancestors::default(), + 5, + vec![], + ) + .await; + get_backable_candidates( + &mut virtual_overseer, + &leaf_b, + 1.into(), + Ancestors::default(), + 5, + vec![], + ) + .await; + get_backable_candidates( + &mut virtual_overseer, + &leaf_c, + 2.into(), + Ancestors::default(), + 5, + vec![], + ) + .await; + + virtual_overseer + }); + + assert_eq!(view.active_leaves.len(), 0); + assert_eq!(view.candidate_storage.len(), 0); +} + +// Introduce a candidate to multiple forks, see how the membership is returned. +#[test] +fn introduce_candidate_on_multiple_forks() { + let test_state = TestState::default(); + let view = test_harness(|mut virtual_overseer| async move { + // Leaf B + let leaf_b = TestLeaf { + number: 101, + hash: Hash::from_low_u64_be(131), + para_data: vec![ + (1.into(), PerParaData::new(99, HeadData(vec![1, 2, 3]))), + (2.into(), PerParaData::new(101, HeadData(vec![4, 5, 6]))), + ], + }; + // Leaf A + let leaf_a = TestLeaf { + number: 100, + hash: get_parent_hash(leaf_b.hash), + 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; + activate_leaf(&mut virtual_overseer, &leaf_b, &test_state).await; + + // Candidate built on leaf A. + let (candidate_a, pvd_a) = make_candidate( + leaf_a.hash, + leaf_a.number, + 1.into(), + HeadData(vec![1, 2, 3]), + HeadData(vec![1]), + test_state.validation_code_hash, + ); + let candidate_hash_a = candidate_a.hash(); + let response_a = vec![(candidate_hash_a, leaf_a.hash)]; + + // Introduce candidate. Should be present on leaves B and C. + introduce_seconded_candidate(&mut virtual_overseer, candidate_a.clone(), pvd_a).await; + back_candidate(&mut virtual_overseer, &candidate_a, candidate_hash_a).await; + + // Check candidate tree membership. + get_backable_candidates( + &mut virtual_overseer, + &leaf_a, + 1.into(), + Ancestors::default(), + 5, + response_a.clone(), + ) + .await; + get_backable_candidates( + &mut virtual_overseer, + &leaf_b, + 1.into(), + Ancestors::default(), + 5, + response_a.clone(), + ) + .await; + + virtual_overseer + }); + + assert_eq!(view.active_leaves.len(), 2); + assert_eq!(view.candidate_storage.len(), 2); + assert_eq!(view.candidate_storage.get(&1.into()).unwrap().len(), (1, 1)); + assert_eq!(view.candidate_storage.get(&2.into()).unwrap().len(), (0, 0)); +} + +#[test] +fn unconnected_candidates_become_connected() { + 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; + + // Candidates A, B, C and D all form a chain, but we'll first introduce A, C and D. + let (candidate_a, pvd_a) = make_candidate( + leaf_a.hash, + leaf_a.number, 1.into(), - vec![candidate_hash_a].into_iter().collect(), - 1, - vec![], + HeadData(vec![1, 2, 3]), + HeadData(vec![1]), + test_state.validation_code_hash, + ); + let (candidate_b, pvd_b) = make_candidate( + leaf_a.hash, + leaf_a.number, + 1.into(), + HeadData(vec![1]), + HeadData(vec![2]), + test_state.validation_code_hash, + ); + let (candidate_c, pvd_c) = make_candidate( + leaf_a.hash, + leaf_a.number, + 1.into(), + HeadData(vec![2]), + HeadData(vec![3]), + test_state.validation_code_hash, + ); + let (candidate_d, pvd_d) = make_candidate( + leaf_a.hash, + leaf_a.number, + 1.into(), + HeadData(vec![3]), + HeadData(vec![4]), + test_state.validation_code_hash, + ); + + // Introduce candidates A, C and D. + introduce_seconded_candidate(&mut virtual_overseer, candidate_a.clone(), pvd_a.clone()) + .await; + introduce_seconded_candidate(&mut virtual_overseer, candidate_c.clone(), pvd_c.clone()) + .await; + introduce_seconded_candidate(&mut virtual_overseer, candidate_d.clone(), pvd_d.clone()) + .await; + + // Back candidates. Otherwise, we cannot check membership with GetBackableCandidates. + back_candidate(&mut virtual_overseer, &candidate_a, candidate_a.hash()).await; + back_candidate(&mut virtual_overseer, &candidate_c, candidate_c.hash()).await; + back_candidate(&mut virtual_overseer, &candidate_d, candidate_d.hash()).await; + + // Check candidate tree membership. Only A should be returned. + get_backable_candidates( + &mut virtual_overseer, + &leaf_a, + 1.into(), + Ancestors::default(), + 5, + vec![(candidate_a.hash(), leaf_a.hash)], + ) + .await; + + // Introduce C and check membership. Full chain should be returned. + introduce_seconded_candidate(&mut virtual_overseer, candidate_b.clone(), pvd_b.clone()) + .await; + back_candidate(&mut virtual_overseer, &candidate_b, candidate_b.hash()).await; + get_backable_candidates( + &mut virtual_overseer, + &leaf_a, + 1.into(), + Ancestors::default(), + 5, + vec![ + (candidate_a.hash(), leaf_a.hash), + (candidate_b.hash(), leaf_a.hash), + (candidate_c.hash(), leaf_a.hash), + (candidate_d.hash(), leaf_a.hash), + ], ) .await; + + virtual_overseer + }); + + assert_eq!(view.active_leaves.len(), 1); + assert_eq!(view.candidate_storage.len(), 2); + assert_eq!(view.candidate_storage.get(&1.into()).unwrap().len(), (4, 4)); + assert_eq!(view.candidate_storage.get(&2.into()).unwrap().len(), (0, 0)); +} + +// Backs some candidates and tests `GetBackableCandidates` when requesting a single candidate. +#[test] +fn check_backable_query_single_candidate() { + 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 A + let (candidate_a, pvd_a) = make_candidate( + leaf_a.hash, + leaf_a.number, + 1.into(), + HeadData(vec![1, 2, 3]), + HeadData(vec![1]), + test_state.validation_code_hash, + ); + let candidate_hash_a = candidate_a.hash(); + + // Candidate B + let (mut candidate_b, pvd_b) = make_candidate( + leaf_a.hash, + leaf_a.number, + 1.into(), + HeadData(vec![1]), + HeadData(vec![2]), + test_state.validation_code_hash, + ); + // Set a field to make this candidate unique. + candidate_b.descriptor.para_head = Hash::from_low_u64_le(1000); + let candidate_hash_b = candidate_b.hash(); + + // Introduce candidates. + introduce_seconded_candidate(&mut virtual_overseer, candidate_a.clone(), pvd_a).await; + introduce_seconded_candidate(&mut virtual_overseer, candidate_b.clone(), pvd_b).await; + + // Should not get any backable candidates. get_backable_candidates( &mut virtual_overseer, &leaf_a, 1.into(), vec![candidate_hash_a].into_iter().collect(), - 0, + 1, vec![], ) .await; @@ -917,23 +1361,17 @@ fn check_backable_query_single_candidate() { &mut virtual_overseer, &leaf_a, 1.into(), - Ancestors::new(), + vec![candidate_hash_a].into_iter().collect(), 0, vec![], ) .await; - - // Second candidates. - second_candidate(&mut virtual_overseer, candidate_a.clone()).await; - second_candidate(&mut virtual_overseer, candidate_b.clone()).await; - - // Should not get any backable candidates. get_backable_candidates( &mut virtual_overseer, &leaf_a, 1.into(), - vec![candidate_hash_a].into_iter().collect(), - 1, + Ancestors::new(), + 0, vec![], ) .await; @@ -1019,392 +1457,327 @@ fn check_backable_query_multiple_candidates() { // Set a field to make this candidate unique. candidate.descriptor.para_head = Hash::from_low_u64_le($index); let candidate_hash = candidate.hash(); - introduce_candidate(&mut $virtual_overseer, candidate.clone(), pvd).await; - second_candidate(&mut $virtual_overseer, candidate.clone()).await; + introduce_seconded_candidate(&mut $virtual_overseer, candidate.clone(), pvd).await; back_candidate(&mut $virtual_overseer, &candidate, candidate_hash).await; (candidate, candidate_hash) }}; } - // Parachain 1 looks like this: - // +---A----+ - // | | - // +----B---+ 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 A - let (candidate_a, pvd_a) = make_candidate( - leaf_a.hash, - leaf_a.number, - 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_b, candidate_hash_b) = - make_and_back_candidate!(test_state, virtual_overseer, leaf_a, &candidate_a, 2); - 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); - - // Should not get any backable candidates for the other para. - get_backable_candidates( - &mut virtual_overseer, - &leaf_a, - 2.into(), - 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![], - ) - .await; - - // Test various scenarios with various counts. - - // empty required_path - { - get_backable_candidates( - &mut virtual_overseer, - &leaf_a, - 1.into(), - Ancestors::new(), - 1, - vec![(candidate_hash_a, leaf_a.hash)], - ) - .await; - get_backable_candidates( - &mut virtual_overseer, - &leaf_a, - 1.into(), - Ancestors::new(), - 4, - vec![ - (candidate_hash_a, leaf_a.hash), - (candidate_hash_b, leaf_a.hash), - (candidate_hash_f, leaf_a.hash), - (candidate_hash_g, leaf_a.hash), - ], - ) - .await; - } - - // required path of 1 - { - get_backable_candidates( - &mut virtual_overseer, - &leaf_a, - 1.into(), - vec![candidate_hash_a].into_iter().collect(), - 1, - vec![(candidate_hash_b, leaf_a.hash)], - ) - .await; - get_backable_candidates( - &mut virtual_overseer, - &leaf_a, - 1.into(), - vec![candidate_hash_a].into_iter().collect(), - 3, - vec![ - (candidate_hash_b, leaf_a.hash), - (candidate_hash_f, leaf_a.hash), - (candidate_hash_g, leaf_a.hash), - ], - ) - .await; + 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]))), + ], + }; - // If the requested count exceeds the largest chain, return the longest - // chain we can get. - for count in 5..10 { - get_backable_candidates( - &mut virtual_overseer, - &leaf_a, - 1.into(), - vec![candidate_hash_a].into_iter().collect(), - count, - 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; - } - } + // Activate leaves. + activate_leaf(&mut virtual_overseer, &leaf_a, &test_state).await; - // required path of 2 and higher - { - get_backable_candidates( - &mut virtual_overseer, - &leaf_a, - 1.into(), - vec![candidate_hash_a, candidate_hash_i, candidate_hash_h, candidate_hash_c] - .into_iter() - .collect(), - 1, - vec![(candidate_hash_j, leaf_a.hash)], - ) - .await; + // Candidate A + let (candidate_a, pvd_a) = make_candidate( + leaf_a.hash, + leaf_a.number, + 1.into(), + HeadData(vec![1, 2, 3]), + HeadData(vec![1]), + test_state.validation_code_hash, + ); + let candidate_hash_a = candidate_a.hash(); + introduce_seconded_candidate(&mut virtual_overseer, candidate_a.clone(), pvd_a).await; + back_candidate(&mut virtual_overseer, &candidate_a, candidate_hash_a).await; - get_backable_candidates( - &mut virtual_overseer, - &leaf_a, - 1.into(), - vec![candidate_hash_a, candidate_hash_b].into_iter().collect(), - 1, - vec![(candidate_hash_d, leaf_a.hash)], - ) - .await; + let (candidate_b, candidate_hash_b) = + make_and_back_candidate!(test_state, virtual_overseer, leaf_a, &candidate_a, 2); + let (candidate_c, candidate_hash_c) = + make_and_back_candidate!(test_state, virtual_overseer, leaf_a, &candidate_b, 3); + let (_candidate_d, candidate_hash_d) = + make_and_back_candidate!(test_state, virtual_overseer, leaf_a, &candidate_c, 4); - // 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].into_iter().collect(), - count, - vec![ - (candidate_hash_h, leaf_a.hash), - (candidate_hash_i, leaf_a.hash), - (candidate_hash_j, leaf_a.hash), - ], - ) - .await; - } - } + // Should not get any backable candidates for the other para. + get_backable_candidates( + &mut virtual_overseer, + &leaf_a, + 2.into(), + 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![], + ) + .await; - // No more candidates in any chain. - { - 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; - } - } + // Test various scenarios with various counts. - // Wrong paths. + // empty ancestors + { get_backable_candidates( &mut virtual_overseer, &leaf_a, 1.into(), - vec![candidate_hash_b].into_iter().collect(), + Ancestors::new(), 1, vec![(candidate_hash_a, leaf_a.hash)], ) .await; + for count in 4..10 { + get_backable_candidates( + &mut virtual_overseer, + &leaf_a, + 1.into(), + Ancestors::new(), + count, + vec![ + (candidate_hash_a, leaf_a.hash), + (candidate_hash_b, leaf_a.hash), + (candidate_hash_c, leaf_a.hash), + (candidate_hash_d, leaf_a.hash), + ], + ) + .await; + } + } + + // ancestors of size 1 + { get_backable_candidates( &mut virtual_overseer, &leaf_a, 1.into(), - vec![candidate_hash_b, candidate_hash_f].into_iter().collect(), - 3, - 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_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), - ], + vec![candidate_hash_a].into_iter().collect(), + 1, + vec![(candidate_hash_b, leaf_a.hash)], ) .await; get_backable_candidates( &mut virtual_overseer, &leaf_a, 1.into(), - vec![candidate_hash_e, candidate_hash_h].into_iter().collect(), + vec![candidate_hash_a].into_iter().collect(), 2, - vec![(candidate_hash_a, leaf_a.hash), (candidate_hash_b, leaf_a.hash)], + vec![(candidate_hash_b, leaf_a.hash), (candidate_hash_c, leaf_a.hash)], ) .await; - get_backable_candidates( - &mut virtual_overseer, - &leaf_a, - 1.into(), - 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; + // If the requested count exceeds the largest chain, return the longest + // chain we can get. + for count in 3..10 { + get_backable_candidates( + &mut virtual_overseer, + &leaf_a, + 1.into(), + vec![candidate_hash_a].into_iter().collect(), + count, + vec![ + (candidate_hash_b, leaf_a.hash), + (candidate_hash_c, leaf_a.hash), + (candidate_hash_d, leaf_a.hash), + ], + ) + .await; + } + } - // Parachain fork. + // ancestor count 2 and higher + { get_backable_candidates( &mut virtual_overseer, &leaf_a, 1.into(), vec![candidate_hash_a, candidate_hash_b, candidate_hash_c].into_iter().collect(), 1, - vec![], + vec![(candidate_hash_d, leaf_a.hash)], ) .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)], + vec![candidate_hash_a, candidate_hash_b].into_iter().collect(), + 1, + vec![(candidate_hash_c, leaf_a.hash)], ) .await; - // Requested count is zero. - 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![candidate_hash_a].into_iter().collect(), - 0, - vec![], - ) - .await; + // If the requested count exceeds the largest chain, return the longest + // chain we can get. + for count in 3..10 { + get_backable_candidates( + &mut virtual_overseer, + &leaf_a, + 1.into(), + vec![candidate_hash_a, candidate_hash_b].into_iter().collect(), + count, + vec![(candidate_hash_c, leaf_a.hash), (candidate_hash_d, leaf_a.hash)], + ) + .await; + } + } + + // No more candidates in the chain. + for count in 1..4 { get_backable_candidates( &mut virtual_overseer, &leaf_a, 1.into(), - vec![candidate_hash_a, candidate_hash_b].into_iter().collect(), - 0, + vec![candidate_hash_a, candidate_hash_b, candidate_hash_c, candidate_hash_d] + .into_iter() + .collect(), + count, vec![], ) .await; + } + + // Wrong paths. + get_backable_candidates( + &mut virtual_overseer, + &leaf_a, + 1.into(), + vec![candidate_hash_b].into_iter().collect(), + 1, + vec![(candidate_hash_a, leaf_a.hash)], + ) + .await; + get_backable_candidates( + &mut virtual_overseer, + &leaf_a, + 1.into(), + vec![candidate_hash_b, candidate_hash_c].into_iter().collect(), + 3, + vec![ + (candidate_hash_a, leaf_a.hash), + (candidate_hash_b, leaf_a.hash), + (candidate_hash_c, leaf_a.hash), + ], + ) + .await; + + get_backable_candidates( + &mut virtual_overseer, + &leaf_a, + 1.into(), + vec![candidate_hash_a, candidate_hash_c, candidate_hash_d].into_iter().collect(), + 2, + vec![(candidate_hash_b, leaf_a.hash), (candidate_hash_c, leaf_a.hash)], + ) + .await; - virtual_overseer - }); + // 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_c, leaf_a.hash)], + ) + .await; - 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)); - } + // Requested count is zero. + 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![candidate_hash_a].into_iter().collect(), + 0, + vec![], + ) + .await; + get_backable_candidates( + &mut virtual_overseer, + &leaf_a, + 1.into(), + vec![candidate_hash_a, candidate_hash_b].into_iter().collect(), + 0, + vec![], + ) + .await; + + virtual_overseer + }); + + assert_eq!(view.active_leaves.len(), 1); + assert_eq!(view.candidate_storage.len(), 2); + // 4 candidates on para 1. + assert_eq!(view.candidate_storage.get(&1.into()).unwrap().len(), (4, 4)); + assert_eq!(view.candidate_storage.get(&2.into()).unwrap().len(), (0, 0)); } -// Test depth query. +// Test hypothetical membership query. #[test] -fn check_hypothetical_frontier_query() { +fn check_hypothetical_membership_query() { let test_state = TestState::default(); let view = test_harness(|mut virtual_overseer| async move { + // Leaf B + let leaf_b = TestLeaf { + number: 101, + hash: Hash::from_low_u64_be(131), + para_data: vec![ + (1.into(), PerParaData::new(97, HeadData(vec![1, 2, 3]))), + (2.into(), PerParaData::new(100, HeadData(vec![2, 3, 4]))), + ], + }; // Leaf A let leaf_a = TestLeaf { number: 100, - hash: Hash::from_low_u64_be(130), + hash: get_parent_hash(leaf_b.hash), para_data: vec![ - (1.into(), PerParaData::new(97, HeadData(vec![1, 2, 3]))), + (1.into(), PerParaData::new(98, 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; + activate_leaf_with_params( + &mut virtual_overseer, + &leaf_a, + &test_state, + AsyncBackingParams { allowed_ancestry_len: 3, max_candidate_depth: 1 }, + ) + .await; + activate_leaf_with_params( + &mut virtual_overseer, + &leaf_b, + &test_state, + AsyncBackingParams { allowed_ancestry_len: 3, max_candidate_depth: 1 }, + ) + .await; + + // Candidates will be valid on both leaves. // Candidate A. let (candidate_a, pvd_a) = make_candidate( @@ -1415,7 +1788,6 @@ fn check_hypothetical_frontier_query() { HeadData(vec![1]), test_state.validation_code_hash, ); - let candidate_hash_a = candidate_a.hash(); // Candidate B. let (candidate_b, pvd_b) = make_candidate( @@ -1426,7 +1798,6 @@ fn check_hypothetical_frontier_query() { HeadData(vec![2]), test_state.validation_code_hash, ); - let candidate_hash_b = candidate_b.hash(); // Candidate C. let (candidate_c, pvd_c) = make_candidate( @@ -1437,127 +1808,99 @@ fn check_hypothetical_frontier_query() { HeadData(vec![3]), test_state.validation_code_hash, ); - let candidate_hash_c = candidate_c.hash(); - // Get hypothetical frontier of candidate A before adding it. - get_hypothetical_frontier( - &mut virtual_overseer, - candidate_hash_a, - candidate_a.clone(), - pvd_a.clone(), - leaf_a.hash, - false, - vec![0], - ) - .await; - // Should work with `backed_in_path_only: true`, too. - get_hypothetical_frontier( - &mut virtual_overseer, - candidate_hash_a, - candidate_a.clone(), - pvd_a.clone(), - leaf_a.hash, - true, - vec![0], - ) - .await; + // Get hypothetical membership of candidates before adding candidate A. + // Candidate A can be added directly, candidates B and C are potential candidates. + for (candidate, pvd) in [ + (candidate_a.clone(), pvd_a.clone()), + (candidate_b.clone(), pvd_b.clone()), + (candidate_c.clone(), pvd_c.clone()), + ] { + get_hypothetical_membership( + &mut virtual_overseer, + candidate.hash(), + candidate, + pvd, + vec![leaf_a.hash, leaf_b.hash], + ) + .await; + } // Add candidate A. - introduce_candidate(&mut virtual_overseer, candidate_a.clone(), pvd_a.clone()).await; - - // Get frontier of candidate A after adding it. - get_hypothetical_frontier( - &mut virtual_overseer, - candidate_hash_a, - candidate_a.clone(), - pvd_a.clone(), - leaf_a.hash, - false, - vec![0], - ) - .await; - - // Get hypothetical frontier of candidate B before adding it. - get_hypothetical_frontier( - &mut virtual_overseer, - candidate_hash_b, - candidate_b.clone(), - pvd_b.clone(), - leaf_a.hash, - false, - vec![1], - ) - .await; - - // Add candidate B. - introduce_candidate(&mut virtual_overseer, candidate_b.clone(), pvd_b.clone()).await; + introduce_seconded_candidate(&mut virtual_overseer, candidate_a.clone(), pvd_a.clone()) + .await; - // Get frontier of candidate B after adding it. - get_hypothetical_frontier( - &mut virtual_overseer, - candidate_hash_b, - candidate_b, - pvd_b.clone(), - leaf_a.hash, - false, - vec![1], - ) - .await; + // Get membership of candidates after adding A. C is not a potential candidate because we + // may only add one more candidate, which must be a connected candidate. + for (candidate, pvd) in + [(candidate_a.clone(), pvd_a.clone()), (candidate_b.clone(), pvd_b.clone())] + { + get_hypothetical_membership( + &mut virtual_overseer, + candidate.hash(), + candidate, + pvd, + vec![leaf_a.hash, leaf_b.hash], + ) + .await; + } - // Get hypothetical frontier of candidate C before adding it. - get_hypothetical_frontier( - &mut virtual_overseer, - candidate_hash_c, - candidate_c.clone(), - pvd_c.clone(), - leaf_a.hash, - false, - vec![2], - ) - .await; - // Should be empty with `backed_in_path_only` because we haven't backed anything. - get_hypothetical_frontier( + get_hypothetical_membership( &mut virtual_overseer, - candidate_hash_c, + candidate_c.hash(), candidate_c.clone(), pvd_c.clone(), - leaf_a.hash, - true, vec![], ) .await; - // Add candidate C. - introduce_candidate(&mut virtual_overseer, candidate_c.clone(), pvd_c.clone()).await; + // Candidate D has invalid relay parent. + let (candidate_d, pvd_d) = make_candidate( + Hash::from_low_u64_be(200), + leaf_a.number, + 1.into(), + HeadData(vec![1]), + HeadData(vec![2]), + test_state.validation_code_hash, + ); + introduce_seconded_candidate_failed(&mut virtual_overseer, candidate_d, pvd_d).await; - // Get frontier of candidate C after adding it. - get_hypothetical_frontier( - &mut virtual_overseer, - candidate_hash_c, - candidate_c.clone(), - pvd_c.clone(), - leaf_a.hash, - false, - vec![2], - ) - .await; - // Should be empty with `backed_in_path_only` because we haven't backed anything. - get_hypothetical_frontier( + // Add candidate B. + introduce_seconded_candidate(&mut virtual_overseer, candidate_b.clone(), pvd_b.clone()) + .await; + + // Get membership of candidates after adding B. + for (candidate, pvd) in + [(candidate_a.clone(), pvd_a.clone()), (candidate_b.clone(), pvd_b.clone())] + { + get_hypothetical_membership( + &mut virtual_overseer, + candidate.hash(), + candidate, + pvd, + vec![leaf_a.hash, leaf_b.hash], + ) + .await; + } + + get_hypothetical_membership( &mut virtual_overseer, - candidate_hash_c, + candidate_c.hash(), candidate_c.clone(), pvd_c.clone(), - leaf_a.hash, - true, vec![], ) .await; + // Add candidate C. It will fail because we have enough candidates for the configured depth. + introduce_seconded_candidate_failed(&mut virtual_overseer, candidate_c, pvd_c).await; + virtual_overseer }); - assert_eq!(view.active_leaves.len(), 1); + assert_eq!(view.active_leaves.len(), 2); assert_eq!(view.candidate_storage.len(), 2); + assert_eq!(view.candidate_storage.get(&1.into()).unwrap().len(), (2, 2)); } #[test] @@ -1618,7 +1961,8 @@ fn check_pvd_query() { .await; // Add candidate A. - introduce_candidate(&mut virtual_overseer, candidate_a.clone(), pvd_a.clone()).await; + introduce_seconded_candidate(&mut virtual_overseer, candidate_a.clone(), pvd_a.clone()) + .await; back_candidate(&mut virtual_overseer, &candidate_a, candidate_a.hash()).await; // Get pvd of candidate A after adding it. @@ -1642,7 +1986,7 @@ fn check_pvd_query() { .await; // Add candidate B. - introduce_candidate(&mut virtual_overseer, candidate_b, pvd_b.clone()).await; + introduce_seconded_candidate(&mut virtual_overseer, candidate_b, pvd_b.clone()).await; // Get pvd of candidate B after adding it. get_pvd( @@ -1665,7 +2009,7 @@ fn check_pvd_query() { .await; // Add candidate C. - introduce_candidate(&mut virtual_overseer, candidate_c, pvd_c.clone()).await; + introduce_seconded_candidate(&mut virtual_overseer, candidate_c, pvd_c.clone()).await; // Get pvd of candidate C after adding it. get_pvd( @@ -1849,8 +2193,7 @@ fn persists_pending_availability_candidate() { ); let candidate_hash_b = candidate_b.hash(); - introduce_candidate(&mut virtual_overseer, candidate_a.clone(), pvd_a).await; - second_candidate(&mut virtual_overseer, candidate_a.clone()).await; + introduce_seconded_candidate(&mut virtual_overseer, candidate_a.clone(), pvd_a).await; back_candidate(&mut virtual_overseer, &candidate_a, candidate_hash_a).await; let candidate_a_pending_av = CandidatePendingAvailability { @@ -1874,8 +2217,7 @@ fn persists_pending_availability_candidate() { }; activate_leaf(&mut virtual_overseer, &leaf_b, &test_state).await; - introduce_candidate(&mut virtual_overseer, candidate_b.clone(), pvd_b).await; - second_candidate(&mut virtual_overseer, candidate_b.clone()).await; + introduce_seconded_candidate(&mut virtual_overseer, candidate_b.clone(), pvd_b).await; back_candidate(&mut virtual_overseer, &candidate_b, candidate_hash_b).await; get_backable_candidates( @@ -1942,8 +2284,7 @@ fn backwards_compatible() { ); 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; + introduce_seconded_candidate(&mut virtual_overseer, candidate_a.clone(), pvd_a).await; back_candidate(&mut virtual_overseer, &candidate_a, candidate_hash_a).await; get_backable_candidates( diff --git a/polkadot/node/core/provisioner/Cargo.toml b/polkadot/node/core/provisioner/Cargo.toml index ec1a4abb3ece0a3dc8a01e090f9bf3302dde3294..d197832126442cd7bf67236395cfcc5800f00153 100644 --- a/polkadot/node/core/provisioner/Cargo.toml +++ b/polkadot/node/core/provisioner/Cargo.toml @@ -19,7 +19,7 @@ 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" +fatality = "0.1.1" schnellru = "0.2.1" [dev-dependencies] diff --git a/polkadot/node/core/provisioner/src/lib.rs b/polkadot/node/core/provisioner/src/lib.rs index 5cfcb96dc2bc710c42400fa49fa888195c79aa48..fa16b38d28bda4e364c5b6d8b74bb85ca727036d 100644 --- a/polkadot/node/core/provisioner/src/lib.rs +++ b/polkadot/node/core/provisioner/src/lib.rs @@ -877,7 +877,7 @@ async fn get_block_number_under_construction( } /// Requests backable candidates from Prospective Parachains based on -/// the given ancestors in the fragment tree. The ancestors may not be ordered. +/// the given ancestors in the fragment chain. The ancestors may not be ordered. async fn get_backable_candidates( relay_parent: Hash, para_id: ParaId, diff --git a/polkadot/node/core/pvf/Cargo.toml b/polkadot/node/core/pvf/Cargo.toml index a0233d6b751769a4f51f3eda0f7ca0ec75fa1cb7..ba9954a10668e154ee44cccc9888a6e3d3c5ed09 100644 --- a/polkadot/node/core/pvf/Cargo.toml +++ b/polkadot/node/core/pvf/Cargo.toml @@ -11,14 +11,13 @@ workspace = true [dependencies] always-assert = "0.1" -array-bytes = "6.1" +array-bytes = "6.2.2" blake3 = "1.5" cfg-if = "1.0" futures = "0.3.30" futures-timer = "3.0.2" gum = { package = "tracing-gum", path = "../../gum" } -is_executable = "1.0.1" -libc = "0.2.152" +is_executable = { version = "1.0.1", optional = true } pin-project = "1.0.9" rand = "0.8.5" slotmap = "1.0" @@ -26,7 +25,9 @@ tempfile = "3.3.0" thiserror = { workspace = true } tokio = { version = "1.24.2", features = ["fs", "process"] } -parity-scale-codec = { version = "3.6.1", default-features = false, features = ["derive"] } +parity-scale-codec = { version = "3.6.12", default-features = false, features = [ + "derive", +] } polkadot-parachain-primitives = { path = "../../../parachain" } polkadot-core-primitives = { path = "../../../core-primitives" } @@ -37,14 +38,16 @@ polkadot-node-subsystem = { path = "../../subsystem" } polkadot-primitives = { path = "../../../primitives" } sp-core = { path = "../../../../substrate/primitives/core" } -sp-wasm-interface = { path = "../../../../substrate/primitives/wasm-interface" } -sp-maybe-compressed-blob = { path = "../../../../substrate/primitives/maybe-compressed-blob" } +sp-maybe-compressed-blob = { path = "../../../../substrate/primitives/maybe-compressed-blob", optional = true } polkadot-node-core-pvf-prepare-worker = { path = "prepare-worker", optional = true } polkadot-node-core-pvf-execute-worker = { path = "execute-worker", optional = true } [dev-dependencies] assert_matches = "1.4.0" -criterion = { version = "0.4.0", default-features = false, features = ["async_tokio", "cargo_bench_support"] } +criterion = { version = "0.5.1", default-features = false, features = [ + "async_tokio", + "cargo_bench_support", +] } hex-literal = "0.4.1" polkadot-node-core-pvf-common = { path = "common", features = ["test-utils"] } @@ -57,6 +60,7 @@ adder = { package = "test-parachain-adder", path = "../../../parachain/test-para halt = { package = "test-parachain-halt", path = "../../../parachain/test-parachains/halt" } [target.'cfg(target_os = "linux")'.dev-dependencies] +libc = "0.2.153" procfs = "0.16.0" rusty-fork = "0.3.0" sc-sysinfo = { path = "../../../../substrate/client/sysinfo" } @@ -70,6 +74,8 @@ ci-only-tests = [] jemalloc-allocator = ["polkadot-node-core-pvf-common/jemalloc-allocator"] # This feature is used to export test code to other crates without putting it in the production build. test-utils = [ - "polkadot-node-core-pvf-execute-worker", - "polkadot-node-core-pvf-prepare-worker", + "dep:is_executable", + "dep:polkadot-node-core-pvf-execute-worker", + "dep:polkadot-node-core-pvf-prepare-worker", + "dep:sp-maybe-compressed-blob", ] diff --git a/polkadot/node/core/pvf/benches/host_prepare_rococo_runtime.rs b/polkadot/node/core/pvf/benches/host_prepare_rococo_runtime.rs index 2aea21361a3e8fcb4114eb533539f09b1d660fc7..97a03e6596d16e2d10219331e58dd2d19647b531 100644 --- a/polkadot/node/core/pvf/benches/host_prepare_rococo_runtime.rs +++ b/polkadot/node/core/pvf/benches/host_prepare_rococo_runtime.rs @@ -48,6 +48,9 @@ impl TestHost { false, prepare_worker_path, execute_worker_path, + 2, + 1, + 2, ); f(&mut config); let (host, task) = start(config, Metrics::default()).await.unwrap(); diff --git a/polkadot/node/core/pvf/common/Cargo.toml b/polkadot/node/core/pvf/common/Cargo.toml index f3eb9d919aae6ea6ded7df58a088d22ebbe66325..5ad7409cc6c78d16cf292c1bf1c1542417abeb5d 100644 --- a/polkadot/node/core/pvf/common/Cargo.toml +++ b/polkadot/node/core/pvf/common/Cargo.toml @@ -10,14 +10,16 @@ license.workspace = true workspace = true [dependencies] -cfg-if = "1.0" cpu-time = "1.0.0" futures = "0.3.30" gum = { package = "tracing-gum", path = "../../../gum" } libc = "0.2.152" +nix = { version = "0.28.0", features = ["resource", "sched"] } thiserror = { workspace = true } -parity-scale-codec = { version = "3.6.1", default-features = false, features = ["derive"] } +parity-scale-codec = { version = "3.6.12", default-features = false, features = [ + "derive", +] } polkadot-parachain-primitives = { path = "../../../../parachain" } polkadot-primitives = { path = "../../../../primitives" } @@ -34,7 +36,6 @@ 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" diff --git a/polkadot/node/core/pvf/common/src/error.rs b/polkadot/node/core/pvf/common/src/error.rs index cf274044456f3ea2db6770fbd61b3319f6420996..adeb40c0b1958df624662f8e7533b6d06f49f543 100644 --- a/polkadot/node/core/pvf/common/src/error.rs +++ b/polkadot/node/core/pvf/common/src/error.rs @@ -136,6 +136,9 @@ pub enum InternalValidationError { /// Could not find or open compiled artifact file. #[error("validation: could not find or open compiled artifact file: {0}")] CouldNotOpenFile(String), + /// Could not create a pipe between the worker and a child process. + #[error("validation: could not create pipe: {0}")] + CouldNotCreatePipe(String), /// Host could not clear the worker cache after a job. #[error("validation: host could not clear the worker cache ({path:?}) after a job: {err}")] CouldNotClearWorkerDir { diff --git a/polkadot/node/core/pvf/common/src/execute.rs b/polkadot/node/core/pvf/common/src/execute.rs index 18c97b03cbcd6fccc03cb27cb9f9e3aba9c7cf2a..ae6096cacec457a209d656541999f915f4dbbc3b 100644 --- a/polkadot/node/core/pvf/common/src/execute.rs +++ b/polkadot/node/core/pvf/common/src/execute.rs @@ -30,35 +30,36 @@ pub struct Handshake { /// The response from the execution worker. #[derive(Debug, Encode, Decode)] -pub enum WorkerResponse { - /// The job completed successfully. - Ok { - /// The result of parachain validation. - result_descriptor: ValidationResult, - /// The amount of CPU time taken by the job. - duration: Duration, - }, - /// 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), +pub struct WorkerResponse { + /// The response from the execute job process. + pub job_response: JobResponse, + /// The amount of CPU time taken by the job. + pub duration: Duration, +} + +/// An error occurred in the worker process. +#[derive(thiserror::Error, Debug, Clone, Encode, Decode)] +pub enum WorkerError { /// The job timed out. + #[error("The job timed out")] JobTimedOut, /// The job process has died. We must kill the worker just in case. /// /// We cannot treat this as an internal error because malicious code may have killed the job. /// We still retry it, because in the non-malicious case it is likely spurious. + #[error("The job process (pid {job_pid}) has died: {err}")] JobDied { err: String, job_pid: i32 }, /// An unexpected error occurred in the job process, e.g. failing to spawn a thread, panic, /// etc. /// /// Because malicious code can cause a job error, we must not treat it as an internal error. We /// still retry it, because in the non-malicious case it is likely spurious. - JobError(String), + #[error("An unexpected error occurred in the job process: {0}")] + JobError(#[from] JobError), /// Some internal error occurred. - InternalError(InternalValidationError), + #[error("An internal error occurred: {0}")] + InternalError(#[from] InternalValidationError), } /// The result of a job on the execution worker. @@ -101,7 +102,7 @@ impl JobResponse { /// An unexpected error occurred in the execution job process. Because this comes from the job, /// which executes untrusted code, this error must likewise be treated as untrusted. That is, we /// cannot raise an internal error based on this. -#[derive(thiserror::Error, Debug, Encode, Decode)] +#[derive(thiserror::Error, Clone, Debug, Encode, Decode)] pub enum JobError { #[error("The job timed out")] TimedOut, @@ -114,4 +115,7 @@ pub enum JobError { CouldNotSpawnThread(String), #[error("An error occurred in the CPU time monitor thread: {0}")] CpuTimeMonitorThread(String), + /// Since the job can return any exit status it wants, we have to treat this as untrusted. + #[error("Unexpected exit status: {0}")] + UnexpectedExitStatus(i32), } diff --git a/polkadot/node/core/pvf/common/src/lib.rs b/polkadot/node/core/pvf/common/src/lib.rs index 15097dbd3af5c29d1fceabc8d04f6ee9a395ef30..0cd928201639636bd1e5725685e97ea57361313a 100644 --- a/polkadot/node/core/pvf/common/src/lib.rs +++ b/polkadot/node/core/pvf/common/src/lib.rs @@ -15,6 +15,7 @@ // along with Polkadot. If not, see . //! Contains functionality related to PVFs that is shared by the PVF host and the PVF workers. +#![deny(unused_crate_dependencies)] pub mod error; pub mod execute; diff --git a/polkadot/node/core/pvf/common/src/pvf.rs b/polkadot/node/core/pvf/common/src/pvf.rs index 340dffe07c3fd3e8b049f1a126a348a7ff4e326f..5f248f49b9a381c9f250f911bc1989518280c6de 100644 --- a/polkadot/node/core/pvf/common/src/pvf.rs +++ b/polkadot/node/core/pvf/common/src/pvf.rs @@ -18,12 +18,7 @@ use crate::prepare::PrepareJobKind; use parity_scale_codec::{Decode, Encode}; use polkadot_parachain_primitives::primitives::ValidationCodeHash; use polkadot_primitives::ExecutorParams; -use std::{ - cmp::{Eq, PartialEq}, - fmt, - sync::Arc, - time::Duration, -}; +use std::{fmt, sync::Arc, time::Duration}; /// A struct that carries the exhaustive set of data to prepare an artifact out of plain /// Wasm binary diff --git a/polkadot/node/core/pvf/common/src/worker/mod.rs b/polkadot/node/core/pvf/common/src/worker/mod.rs index d7c95d9e7047f940a236e6d9abf1146ad8073566..67e7bece407d13b012d85ee28bd369fc585a6c6f 100644 --- a/polkadot/node/core/pvf/common/src/worker/mod.rs +++ b/polkadot/node/core/pvf/common/src/worker/mod.rs @@ -18,10 +18,13 @@ pub mod security; -use crate::{framed_recv_blocking, SecurityStatus, WorkerHandshake, LOG_TARGET}; +use crate::{ + framed_recv_blocking, framed_send_blocking, SecurityStatus, WorkerHandshake, LOG_TARGET, +}; use cpu_time::ProcessTime; use futures::never::Never; -use parity_scale_codec::Decode; +use nix::{errno::Errno, sys::resource::Usage}; +use parity_scale_codec::{Decode, Encode}; use std::{ any::Any, fmt::{self}, @@ -58,8 +61,6 @@ macro_rules! decl_worker_main { $crate::sp_tracing::try_init_simple(); - let worker_pid = std::process::id(); - let args = std::env::args().collect::>(); if args.len() == 1 { print_help($expected_command); @@ -548,6 +549,81 @@ fn recv_worker_handshake(stream: &mut UnixStream) -> io::Result Ok(worker_handshake) } +/// Calculate the total CPU time from the given `usage` structure, returned from +/// [`nix::sys::resource::getrusage`], and calculates the total CPU time spent, including both user +/// and system time. +/// +/// # Arguments +/// +/// - `rusage`: Contains resource usage information. +/// +/// # Returns +/// +/// Returns a `Duration` representing the total CPU time. +pub fn get_total_cpu_usage(rusage: Usage) -> Duration { + let micros = (((rusage.user_time().tv_sec() + rusage.system_time().tv_sec()) * 1_000_000) + + (rusage.system_time().tv_usec() + rusage.user_time().tv_usec()) as i64) as u64; + + return Duration::from_micros(micros) +} + +/// Get a job response. +pub fn recv_child_response( + received_data: &mut io::BufReader<&[u8]>, + context: &'static str, +) -> io::Result +where + T: Decode, +{ + let response_bytes = framed_recv_blocking(received_data)?; + T::decode(&mut response_bytes.as_slice()).map_err(|e| { + io::Error::new( + io::ErrorKind::Other, + format!("{} pvf recv_child_response: decode error: {}", context, e), + ) + }) +} + +pub fn send_result( + stream: &mut UnixStream, + result: Result, + worker_info: &WorkerInfo, +) -> io::Result<()> +where + T: std::fmt::Debug, + E: std::fmt::Debug + std::fmt::Display, + Result: Encode, +{ + if let Err(ref err) = result { + gum::warn!( + target: LOG_TARGET, + ?worker_info, + "worker: error occurred: {}", + err + ); + } + gum::trace!( + target: LOG_TARGET, + ?worker_info, + "worker: sending result to host: {:?}", + result + ); + + framed_send_blocking(stream, &result.encode()).map_err(|err| { + gum::warn!( + target: LOG_TARGET, + ?worker_info, + "worker: error occurred sending result to host: {}", + err + ); + err + }) +} + +pub fn stringify_errno(context: &'static str, errno: Errno) -> String { + format!("{}: {}: {}", context, errno, io::Error::last_os_error()) +} + /// Functionality related to threads spawned by the workers. /// /// The motivation for this module is to coordinate worker threads without using async Rust. diff --git a/polkadot/node/core/pvf/execute-worker/Cargo.toml b/polkadot/node/core/pvf/execute-worker/Cargo.toml index 04a620573b2eceb311bdce67006e282778442191..ac90fac4d57ad69db5bcf00df1fb9af15cdbd2e2 100644 --- a/polkadot/node/core/pvf/execute-worker/Cargo.toml +++ b/polkadot/node/core/pvf/execute-worker/Cargo.toml @@ -13,10 +13,10 @@ workspace = true cpu-time = "1.0.0" gum = { package = "tracing-gum", path = "../../../gum" } cfg-if = "1.0" -nix = { version = "0.27.1", features = ["process", "resource", "sched"] } +nix = { version = "0.28.0", features = ["process", "resource", "sched"] } libc = "0.2.152" -parity-scale-codec = { version = "3.6.1", default-features = false, features = ["derive"] } +parity-scale-codec = { version = "3.6.12", default-features = false, features = ["derive"] } polkadot-node-core-pvf-common = { path = "../common" } polkadot-parachain-primitives = { path = "../../../../parachain" } diff --git a/polkadot/node/core/pvf/execute-worker/src/lib.rs b/polkadot/node/core/pvf/execute-worker/src/lib.rs index bd7e76010a6dfedb339fd2fc1c17aa7f4007babe..55f5290bd87ee88ce55157a1988c63a2c9670bbf 100644 --- a/polkadot/node/core/pvf/execute-worker/src/lib.rs +++ b/polkadot/node/core/pvf/execute-worker/src/lib.rs @@ -16,6 +16,9 @@ //! Contains the logic for executing PVFs. Used by the polkadot-execute-worker binary. +#![deny(unused_crate_dependencies)] +#![warn(missing_docs)] + pub use polkadot_node_core_pvf_common::{ error::ExecuteError, executor_interface::execute_artifact, }; @@ -36,11 +39,12 @@ use nix::{ use parity_scale_codec::{Decode, Encode}; use polkadot_node_core_pvf_common::{ error::InternalValidationError, - execute::{Handshake, JobError, JobResponse, JobResult, WorkerResponse}, + execute::{Handshake, JobError, JobResponse, JobResult, WorkerError, WorkerResponse}, executor_interface::params_to_wasmtime_semantics, framed_recv_blocking, framed_send_blocking, worker::{ - cpu_time_monitor_loop, pipe2_cloexec, run_worker, stringify_panic_payload, + cpu_time_monitor_loop, get_total_cpu_usage, pipe2_cloexec, recv_child_response, run_worker, + send_result, stringify_errno, stringify_panic_payload, thread::{self, WaitOutcome}, PipeFd, WorkerInfo, WorkerKind, }, @@ -93,8 +97,14 @@ fn recv_request(stream: &mut UnixStream) -> io::Result<(Vec, Duration)> { Ok((params, execution_timeout)) } -fn send_response(stream: &mut UnixStream, response: WorkerResponse) -> io::Result<()> { - framed_send_blocking(stream, &response.encode()) +/// Sends an error to the host and returns the original error wrapped in `io::Error`. +macro_rules! map_and_send_err { + ($error:expr, $err_constructor:expr, $stream:expr, $worker_info:expr) => {{ + let err: WorkerError = $err_constructor($error.to_string()).into(); + let io_err = io::Error::new(io::ErrorKind::Other, err.to_string()); + let _ = send_result::($stream, Err(err), $worker_info); + io_err + }}; } /// The entrypoint that the spawned execute worker should start with. @@ -110,8 +120,6 @@ fn send_response(stream: &mut UnixStream, response: WorkerResponse) -> io::Resul /// check is not necessary. /// /// - `worker_version`: see above -/// -/// - `security_status`: contains the detected status of security features. pub fn worker_entrypoint( socket_path: PathBuf, worker_dir_path: PathBuf, @@ -127,13 +135,28 @@ pub fn worker_entrypoint( |mut stream, worker_info, security_status| { let artifact_path = worker_dir::execute_artifact(&worker_info.worker_dir_path); - let Handshake { executor_params } = recv_execute_handshake(&mut stream)?; + let Handshake { executor_params } = + recv_execute_handshake(&mut stream).map_err(|e| { + map_and_send_err!( + e, + InternalValidationError::HostCommunication, + &mut stream, + worker_info + ) + })?; let executor_params: Arc = Arc::new(executor_params); let execute_thread_stack_size = max_stack_size(&executor_params); loop { - let (params, execution_timeout) = recv_request(&mut stream)?; + let (params, execution_timeout) = recv_request(&mut stream).map_err(|e| { + map_and_send_err!( + e, + InternalValidationError::HostCommunication, + &mut stream, + worker_info + ) + })?; gum::debug!( target: LOG_TARGET, ?worker_info, @@ -143,27 +166,34 @@ pub fn worker_entrypoint( ); // Get the artifact bytes. - let compiled_artifact_blob = match std::fs::read(&artifact_path) { - Ok(bytes) => bytes, - Err(err) => { - let response = WorkerResponse::InternalError( - InternalValidationError::CouldNotOpenFile(err.to_string()), - ); - send_response(&mut stream, response)?; - continue - }, - }; - - let (pipe_read_fd, pipe_write_fd) = pipe2_cloexec()?; - - let usage_before = match nix::sys::resource::getrusage(UsageWho::RUSAGE_CHILDREN) { - Ok(usage) => usage, - Err(errno) => { - let response = internal_error_from_errno("getrusage before", errno); - send_response(&mut stream, response)?; - continue - }, - }; + let compiled_artifact_blob = std::fs::read(&artifact_path).map_err(|e| { + map_and_send_err!( + e, + InternalValidationError::CouldNotOpenFile, + &mut stream, + worker_info + ) + })?; + + let (pipe_read_fd, pipe_write_fd) = pipe2_cloexec().map_err(|e| { + map_and_send_err!( + e, + InternalValidationError::CouldNotCreatePipe, + &mut stream, + worker_info + ) + })?; + + let usage_before = nix::sys::resource::getrusage(UsageWho::RUSAGE_CHILDREN) + .map_err(|errno| { + let e = stringify_errno("getrusage before", errno); + map_and_send_err!( + e, + InternalValidationError::Kernel, + &mut stream, + worker_info + ) + })?; let stream_fd = stream.as_raw_fd(); let compiled_artifact_blob = Arc::new(compiled_artifact_blob); @@ -222,7 +252,7 @@ pub fn worker_entrypoint( "worker: sending result to host: {:?}", result ); - send_response(&mut stream, result)?; + send_result(&mut stream, result, worker_info)?; } }, ); @@ -270,7 +300,7 @@ fn handle_clone( worker_info: &WorkerInfo, have_unshare_newuser: bool, usage_before: Usage, -) -> io::Result { +) -> io::Result> { use polkadot_node_core_pvf_common::worker::security; // SAFETY: new process is spawned within a single threaded process. This invariant @@ -301,7 +331,8 @@ fn handle_clone( usage_before, execution_timeout, ), - Err(security::clone::Error::Clone(errno)) => Ok(internal_error_from_errno("clone", errno)), + Err(security::clone::Error::Clone(errno)) => + Ok(Err(internal_error_from_errno("clone", errno))), } } @@ -316,7 +347,7 @@ fn handle_fork( execute_worker_stack_size: usize, worker_info: &WorkerInfo, usage_before: Usage, -) -> io::Result { +) -> io::Result> { // SAFETY: new process is spawned within a single threaded process. This invariant // is enforced by tests. match unsafe { nix::unistd::fork() } { @@ -338,7 +369,7 @@ fn handle_fork( usage_before, execution_timeout, ), - Err(errno) => Ok(internal_error_from_errno("fork", errno)), + Err(errno) => Ok(Err(internal_error_from_errno("fork", errno))), } } @@ -483,11 +514,11 @@ fn handle_parent_process( job_pid: Pid, usage_before: Usage, timeout: Duration, -) -> io::Result { +) -> io::Result> { // the read end will wait until all write ends have been closed, // this drop is necessary to avoid deadlock if let Err(errno) = nix::unistd::close(pipe_write_fd) { - return Ok(internal_error_from_errno("closing pipe write fd", errno)); + return Ok(Err(internal_error_from_errno("closing pipe write fd", errno))); }; // SAFETY: pipe_read_fd is an open and owned file descriptor at this point. @@ -512,7 +543,7 @@ fn handle_parent_process( let usage_after = match nix::sys::resource::getrusage(UsageWho::RUSAGE_CHILDREN) { Ok(usage) => usage, - Err(errno) => return Ok(internal_error_from_errno("getrusage after", errno)), + Err(errno) => return Ok(Err(internal_error_from_errno("getrusage after", errno))), }; // Using `getrusage` is needed to check whether child has timedout since we cannot rely on @@ -530,32 +561,25 @@ fn handle_parent_process( cpu_tv.as_millis(), timeout.as_millis(), ); - return Ok(WorkerResponse::JobTimedOut) + return Ok(Err(WorkerError::JobTimedOut)) } match status { Ok(WaitStatus::Exited(_, exit_status)) => { let mut reader = io::BufReader::new(received_data.as_slice()); - let result = match recv_child_response(&mut reader) { - Ok(result) => result, - Err(err) => return Ok(WorkerResponse::JobError(err.to_string())), - }; + let result = recv_child_response(&mut reader, "execute")?; match result { - Ok(JobResponse::Ok { result_descriptor }) => { + Ok(job_response) => { // The exit status should have been zero if no error occurred. if exit_status != 0 { - return Ok(WorkerResponse::JobError(format!( - "unexpected exit status: {}", - exit_status - ))) + return Ok(Err(WorkerError::JobError(JobError::UnexpectedExitStatus( + exit_status, + )))); } - Ok(WorkerResponse::Ok { result_descriptor, duration: cpu_tv }) + Ok(Ok(WorkerResponse { job_response, 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, @@ -565,9 +589,9 @@ fn handle_parent_process( job_error, ); if matches!(job_error, JobError::TimedOut) { - Ok(WorkerResponse::JobTimedOut) + Ok(Err(WorkerError::JobTimedOut)) } else { - Ok(WorkerResponse::JobError(job_error.to_string())) + Ok(Err(WorkerError::JobError(job_error.into()))) } }, } @@ -576,50 +600,21 @@ fn handle_parent_process( // // The job gets SIGSYS on seccomp violations, but this signal may have been sent for some // other reason, so we still need to check for seccomp violations elsewhere. - Ok(WaitStatus::Signaled(_pid, signal, _core_dump)) => Ok(WorkerResponse::JobDied { + Ok(WaitStatus::Signaled(_pid, signal, _core_dump)) => Ok(Err(WorkerError::JobDied { err: format!("received signal: {signal:?}"), job_pid: job_pid.as_raw(), - }), - Err(errno) => Ok(internal_error_from_errno("waitpid", errno)), + })), + Err(errno) => Ok(Err(internal_error_from_errno("waitpid", errno))), // It is within an attacker's power to send an unexpected exit status. So we cannot treat // this as an internal error (which would make us abstain), but must vote against. - Ok(unexpected_wait_status) => Ok(WorkerResponse::JobDied { + Ok(unexpected_wait_status) => Ok(Err(WorkerError::JobDied { err: format!("unexpected status from wait: {unexpected_wait_status:?}"), job_pid: job_pid.as_raw(), - }), + })), } } -/// Calculate the total CPU time from the given `usage` structure, returned from -/// [`nix::sys::resource::getrusage`], and calculates the total CPU time spent, including both user -/// and system time. -/// -/// # Arguments -/// -/// - `rusage`: Contains resource usage information. -/// -/// # Returns -/// -/// Returns a `Duration` representing the total CPU time. -fn get_total_cpu_usage(rusage: Usage) -> Duration { - let micros = (((rusage.user_time().tv_sec() + rusage.system_time().tv_sec()) * 1_000_000) + - (rusage.system_time().tv_usec() + rusage.user_time().tv_usec()) as i64) as u64; - - return Duration::from_micros(micros) -} - -/// Get a job response. -fn recv_child_response(received_data: &mut io::BufReader<&[u8]>) -> io::Result { - let response_bytes = framed_recv_blocking(received_data)?; - JobResult::decode(&mut response_bytes.as_slice()).map_err(|e| { - io::Error::new( - io::ErrorKind::Other, - format!("execute pvf recv_child_response: decode error: {}", e), - ) - }) -} - /// Write a job response to the pipe and exit process after. /// /// # Arguments @@ -638,15 +633,10 @@ fn send_child_response(pipe_write: &mut PipeFd, response: JobResult) -> ! { } } -fn internal_error_from_errno(context: &'static str, errno: Errno) -> WorkerResponse { - WorkerResponse::InternalError(InternalValidationError::Kernel(format!( - "{}: {}: {}", - context, - errno, - io::Error::last_os_error() - ))) +fn internal_error_from_errno(context: &'static str, errno: Errno) -> WorkerError { + WorkerError::InternalError(InternalValidationError::Kernel(stringify_errno(context, errno))) } fn job_error_from_errno(context: &'static str, errno: Errno) -> JobResult { - Err(JobError::Kernel(format!("{}: {}: {}", context, errno, io::Error::last_os_error()))) + Err(JobError::Kernel(stringify_errno(context, errno))) } diff --git a/polkadot/node/core/pvf/prepare-worker/Cargo.toml b/polkadot/node/core/pvf/prepare-worker/Cargo.toml index 24efbec4be7d0552abdf9e7a9324636820347950..1850a204890720e697b9e505d8656597dd946844 100644 --- a/polkadot/node/core/pvf/prepare-worker/Cargo.toml +++ b/polkadot/node/core/pvf/prepare-worker/Cargo.toml @@ -18,9 +18,9 @@ rayon = "1.5.1" tracking-allocator = { package = "staging-tracking-allocator", path = "../../../tracking-allocator" } tikv-jemalloc-ctl = { version = "0.5.0", optional = true } tikv-jemallocator = { version = "0.5.0", optional = true } -nix = { version = "0.27.1", features = ["process", "resource", "sched"] } +nix = { version = "0.28.0", features = ["process", "resource", "sched"] } -parity-scale-codec = { version = "3.6.1", default-features = false, features = ["derive"] } +parity-scale-codec = { version = "3.6.12", default-features = false, features = ["derive"] } polkadot-node-core-pvf-common = { path = "../common" } polkadot-primitives = { path = "../../../../primitives" } @@ -41,7 +41,7 @@ jemalloc-allocator = [ ] [dev-dependencies] -criterion = { version = "0.4.0", default-features = false, features = ["cargo_bench_support"] } +criterion = { version = "0.5.1", default-features = false, features = ["cargo_bench_support"] } rococo-runtime = { path = "../../../../runtime/rococo" } sp-maybe-compressed-blob = { path = "../../../../../substrate/primitives/maybe-compressed-blob" } diff --git a/polkadot/node/core/pvf/prepare-worker/src/lib.rs b/polkadot/node/core/pvf/prepare-worker/src/lib.rs index 82a56107ef535743a1838d50358241e3cc64b711..d1b218f48ae897fb663f8285521f251f8a6817d3 100644 --- a/polkadot/node/core/pvf/prepare-worker/src/lib.rs +++ b/polkadot/node/core/pvf/prepare-worker/src/lib.rs @@ -26,7 +26,6 @@ const LOG_TARGET: &str = "parachain::pvf-prepare-worker"; use crate::memory_stats::max_rss_stat::{extract_max_rss_stat, get_max_rss_thread}; #[cfg(any(target_os = "linux", feature = "jemalloc-allocator"))] use crate::memory_stats::memory_tracker::{get_memory_tracker_loop_stats, memory_tracker_loop}; -use libc; use nix::{ errno::Errno, sys::{ @@ -48,7 +47,8 @@ use polkadot_node_core_pvf_common::{ prepare::{MemoryStats, PrepareJobKind, PrepareStats, PrepareWorkerSuccess}, pvf::PvfPrepData, worker::{ - cpu_time_monitor_loop, run_worker, stringify_panic_payload, + cpu_time_monitor_loop, get_total_cpu_usage, recv_child_response, run_worker, send_result, + stringify_errno, stringify_panic_payload, thread::{self, spawn_worker_thread, WaitOutcome}, WorkerKind, }, @@ -117,11 +117,6 @@ fn recv_request(stream: &mut UnixStream) -> io::Result { Ok(pvf) } -/// Send a worker response. -fn send_response(stream: &mut UnixStream, result: PrepareWorkerResult) -> io::Result<()> { - framed_send_blocking(stream, &result.encode()) -} - fn start_memory_tracking(fd: RawFd, limit: Option) { unsafe { // SAFETY: Inside the failure handler, the allocator is locked and no allocations or @@ -178,8 +173,6 @@ fn end_memory_tracking() -> isize { /// /// - `worker_version`: see above /// -/// - `security_status`: contains the detected status of security features. -/// /// # Flow /// /// This runs the following in a loop: @@ -233,8 +226,9 @@ pub fn worker_entrypoint( let usage_before = match nix::sys::resource::getrusage(UsageWho::RUSAGE_CHILDREN) { Ok(usage) => usage, Err(errno) => { - let result = Err(error_from_errno("getrusage before", errno)); - send_response(&mut stream, result)?; + let result: PrepareWorkerResult = + Err(error_from_errno("getrusage before", errno)); + send_result(&mut stream, result, worker_info)?; continue }, }; @@ -294,7 +288,7 @@ pub fn worker_entrypoint( "worker: sending result to host: {:?}", result ); - send_response(&mut stream, result)?; + send_result(&mut stream, result, worker_info)?; } }, ); @@ -666,7 +660,7 @@ fn handle_parent_process( match status { Ok(WaitStatus::Exited(_pid, exit_status)) => { let mut reader = io::BufReader::new(received_data.as_slice()); - let result = recv_child_response(&mut reader) + let result = recv_child_response(&mut reader, "prepare") .map_err(|err| PrepareError::JobError(err.to_string()))?; match result { @@ -726,35 +720,6 @@ fn handle_parent_process( } } -/// Calculate the total CPU time from the given `usage` structure, returned from -/// [`nix::sys::resource::getrusage`], and calculates the total CPU time spent, including both user -/// and system time. -/// -/// # Arguments -/// -/// - `rusage`: Contains resource usage information. -/// -/// # Returns -/// -/// Returns a `Duration` representing the total CPU time. -fn get_total_cpu_usage(rusage: Usage) -> Duration { - let micros = (((rusage.user_time().tv_sec() + rusage.system_time().tv_sec()) * 1_000_000) + - (rusage.system_time().tv_usec() + rusage.user_time().tv_usec()) as i64) as u64; - - return Duration::from_micros(micros) -} - -/// Get a job response. -fn recv_child_response(received_data: &mut io::BufReader<&[u8]>) -> io::Result { - let response_bytes = framed_recv_blocking(received_data)?; - JobResult::decode(&mut response_bytes.as_slice()).map_err(|e| { - io::Error::new( - io::ErrorKind::Other, - format!("prepare pvf recv_child_response: decode error: {:?}", e), - ) - }) -} - /// Write a job response to the pipe and exit process after. /// /// # Arguments @@ -774,7 +739,7 @@ fn send_child_response(pipe_write: &mut PipeFd, response: JobResult) -> ! { } fn error_from_errno(context: &'static str, errno: Errno) -> PrepareError { - PrepareError::Kernel(format!("{}: {}: {}", context, errno, io::Error::last_os_error())) + PrepareError::Kernel(stringify_errno(context, errno)) } type JobResult = Result; diff --git a/polkadot/node/core/pvf/src/artifacts.rs b/polkadot/node/core/pvf/src/artifacts.rs index 6288755526d497812027f7bf04e11e5a67ab799e..a3a48b61acb1743d2ed5df62457c6f9f4ba5fa79 100644 --- a/polkadot/node/core/pvf/src/artifacts.rs +++ b/polkadot/node/core/pvf/src/artifacts.rs @@ -58,7 +58,7 @@ use crate::{host::PrecheckResultSender, worker_interface::WORKER_DIR_PREFIX}; use always_assert::always; use polkadot_node_core_pvf_common::{error::PrepareError, prepare::PrepareStats, pvf::PvfPrepData}; use polkadot_parachain_primitives::primitives::ValidationCodeHash; -use polkadot_primitives::ExecutorParamsHash; +use polkadot_primitives::ExecutorParamsPrepHash; use std::{ collections::HashMap, fs, @@ -85,22 +85,27 @@ pub fn generate_artifact_path(cache_path: &Path) -> PathBuf { artifact_path } -/// Identifier of an artifact. Encodes a code hash of the PVF and a hash of executor parameter set. +/// Identifier of an artifact. Encodes a code hash of the PVF and a hash of preparation-related +/// executor parameter set. #[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)] pub struct ArtifactId { pub(crate) code_hash: ValidationCodeHash, - pub(crate) executor_params_hash: ExecutorParamsHash, + pub(crate) executor_params_prep_hash: ExecutorParamsPrepHash, } impl ArtifactId { /// Creates a new artifact ID with the given hash. - pub fn new(code_hash: ValidationCodeHash, executor_params_hash: ExecutorParamsHash) -> Self { - Self { code_hash, executor_params_hash } + pub fn new( + code_hash: ValidationCodeHash, + executor_params_prep_hash: ExecutorParamsPrepHash, + ) -> Self { + Self { code_hash, executor_params_prep_hash } } - /// Returns an artifact ID that corresponds to the PVF with given executor params. + /// Returns an artifact ID that corresponds to the PVF with given preparation-related + /// executor parameters. pub fn from_pvf_prep_data(pvf: &PvfPrepData) -> Self { - Self::new(pvf.code_hash(), pvf.executor_params().hash()) + Self::new(pvf.code_hash(), pvf.executor_params().prep_hash()) } } diff --git a/polkadot/node/core/pvf/src/execute/queue.rs b/polkadot/node/core/pvf/src/execute/queue.rs index bdc3c7327b06079eaaeebf737ffa7ca2c8c8270c..bb00a5a652d6434cd06327803d9ce51a3d5c1e93 100644 --- a/polkadot/node/core/pvf/src/execute/queue.rs +++ b/polkadot/node/core/pvf/src/execute/queue.rs @@ -16,7 +16,7 @@ //! A queue that handles requests for PVF execution. -use super::worker_interface::Outcome; +use super::worker_interface::{Error as WorkerInterfaceError, Response as WorkerInterfaceResponse}; use crate::{ artifacts::{ArtifactId, ArtifactPathId}, host::ResultSender, @@ -30,7 +30,10 @@ use futures::{ stream::{FuturesUnordered, StreamExt as _}, Future, FutureExt, }; -use polkadot_node_core_pvf_common::SecurityStatus; +use polkadot_node_core_pvf_common::{ + execute::{JobResponse, WorkerError, WorkerResponse}, + SecurityStatus, +}; use polkadot_primitives::{ExecutorParams, ExecutorParamsHash}; use slotmap::HopSlotMap; use std::{ @@ -133,7 +136,12 @@ impl Workers { enum QueueEvent { Spawn(IdleWorker, WorkerHandle, ExecuteJob), - StartWork(Worker, Outcome, ArtifactId, ResultSender), + StartWork( + Worker, + Result, + ArtifactId, + ResultSender, + ), } type Mux = FuturesUnordered>; @@ -340,23 +348,34 @@ fn handle_worker_spawned( async fn handle_job_finish( queue: &mut Queue, worker: Worker, - outcome: Outcome, + worker_result: Result, artifact_id: ArtifactId, result_tx: ResultSender, ) { - let (idle_worker, result, duration, sync_channel) = match outcome { - Outcome::Ok { result_descriptor, duration, idle_worker } => { + let (idle_worker, result, duration, sync_channel) = match worker_result { + Ok(WorkerInterfaceResponse { + worker_response: + WorkerResponse { job_response: JobResponse::Ok { result_descriptor }, duration }, + idle_worker, + }) => { // TODO: propagate the soft timeout (Some(idle_worker), Ok(result_descriptor), Some(duration), None) }, - Outcome::InvalidCandidate { err, idle_worker } => ( + Ok(WorkerInterfaceResponse { + worker_response: WorkerResponse { job_response: JobResponse::InvalidCandidate(err), .. }, + idle_worker, + }) => ( Some(idle_worker), Err(ValidationError::Invalid(InvalidCandidate::WorkerReportedInvalid(err))), None, None, ), - Outcome::RuntimeConstruction { err, idle_worker } => { + Ok(WorkerInterfaceResponse { + worker_response: + WorkerResponse { job_response: JobResponse::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(); @@ -376,27 +395,31 @@ async fn handle_job_finish( Some(result_rx), ) }, - Outcome::InternalError { err } => (None, Err(ValidationError::Internal(err)), None, None), + + Err(WorkerInterfaceError::InternalError(err)) | + Err(WorkerInterfaceError::WorkerError(WorkerError::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 => + Err(WorkerInterfaceError::HardTimeout) | + Err(WorkerInterfaceError::WorkerError(WorkerError::JobTimedOut)) => (None, Err(ValidationError::Invalid(InvalidCandidate::HardTimeout)), None, None), // "Maybe invalid" errors (will retry). - Outcome::WorkerIntfErr => ( + Err(WorkerInterfaceError::CommunicationErr(_err)) => ( None, Err(ValidationError::PossiblyInvalid(PossiblyInvalidError::AmbiguousWorkerDeath)), None, None, ), - Outcome::JobDied { err } => ( + Err(WorkerInterfaceError::WorkerError(WorkerError::JobDied { err, .. })) => ( None, Err(ValidationError::PossiblyInvalid(PossiblyInvalidError::AmbiguousJobDeath(err))), None, None, ), - Outcome::JobError { err } => ( + Err(WorkerInterfaceError::WorkerError(WorkerError::JobError(err))) => ( None, - Err(ValidationError::PossiblyInvalid(PossiblyInvalidError::JobError(err))), + Err(ValidationError::PossiblyInvalid(PossiblyInvalidError::JobError(err.to_string()))), None, None, ), @@ -539,18 +562,21 @@ fn assign(queue: &mut Queue, worker: Worker, job: ExecuteJob) { thus claim_idle cannot return None; qed.", ); + queue + .metrics + .observe_execution_queued_time(job.waiting_since.elapsed().as_millis() as u32); let execution_timer = queue.metrics.time_execution(); queue.mux.push( async move { let _timer = execution_timer; - let outcome = super::worker_interface::start_work( + let result = super::worker_interface::start_work( idle, job.artifact.clone(), job.exec_timeout, job.params, ) .await; - QueueEvent::StartWork(worker, outcome, job.artifact.id, job.result_tx) + QueueEvent::StartWork(worker, result, job.artifact.id, job.result_tx) } .boxed(), ); diff --git a/polkadot/node/core/pvf/src/execute/worker_interface.rs b/polkadot/node/core/pvf/src/execute/worker_interface.rs index db81da118d7b5563ea7b4bec1b6c76bd3bf842e2..9dcadfb4c2a73fbbb27532709de8dd410146fd11 100644 --- a/polkadot/node/core/pvf/src/execute/worker_interface.rs +++ b/polkadot/node/core/pvf/src/execute/worker_interface.rs @@ -29,10 +29,9 @@ use futures_timer::Delay; use parity_scale_codec::{Decode, Encode}; use polkadot_node_core_pvf_common::{ error::InternalValidationError, - execute::{Handshake, WorkerResponse}, + execute::{Handshake, WorkerError, WorkerResponse}, worker_dir, SecurityStatus, }; -use polkadot_parachain_primitives::primitives::ValidationResult; use polkadot_primitives::ExecutorParams; use std::{path::Path, time::Duration}; use tokio::{io, net::UnixStream}; @@ -69,7 +68,8 @@ pub async fn spawn( gum::warn!( target: LOG_TARGET, worker_pid = %idle_worker.pid, - %err + "failed to send a handshake to the spawned worker: {}", + error ); err })?; @@ -78,39 +78,40 @@ pub async fn spawn( /// Outcome of PVF execution. /// -/// If the idle worker token is not returned, it means the worker must be terminated. -pub enum Outcome { - /// PVF execution completed successfully and the result is returned. The worker is ready for - /// another job. - Ok { result_descriptor: ValidationResult, duration: Duration, idle_worker: IdleWorker }, - /// The candidate validation failed. It may be for example because the wasm execution triggered - /// 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 }, +/// PVF execution completed and the result is returned. The worker is ready for +/// another job. +pub struct Response { + /// The response (valid/invalid) from the worker. + pub worker_response: WorkerResponse, + /// Returning the idle worker token means the worker can be reused. + pub idle_worker: IdleWorker, +} +/// The idle worker token is not returned for any of these cases, meaning the worker must be +/// terminated. +/// +/// NOTE: Errors related to the preparation process are not expected to be encountered by the +/// execution workers. +#[derive(thiserror::Error, Debug)] +pub enum Error { /// The execution time exceeded the hard limit. The worker is terminated. + #[error("The communication with the worker exceeded the hard limit")] HardTimeout, /// An I/O error happened during communication with the worker. This may mean that the worker /// process already died. The token is not returned in any case. - WorkerIntfErr, - /// The job process has died. We must kill the worker just in case. - /// - /// We cannot treat this as an internal error because malicious code may have caused this. - JobDied { err: String }, - /// An unexpected error occurred in the job process. - /// - /// Because malicious code can cause a job error, we must not treat it as an internal error. - JobError { err: String }, + #[error("An I/O error happened during communication with the worker: {0}")] + CommunicationErr(#[from] io::Error), + /// The worker reported an error (can be from itself or from the job). The worker should not be + /// reused. + #[error("The worker reported an error: {0}")] + WorkerError(#[from] WorkerError), /// An internal error happened during the validation. Such an error is most likely related to /// some transient glitch. /// /// Should only ever be used for errors independent of the candidate and PVF. Therefore it may /// be a problem with the worker, so we terminate it. - InternalError { err: InternalValidationError }, + #[error("An internal error occurred: {0}")] + InternalError(#[from] InternalValidationError), } /// Given the idle token of a worker and parameters of work, communicates with the worker and @@ -123,7 +124,7 @@ pub async fn start_work( artifact: ArtifactPathId, execution_timeout: Duration, validation_params: Vec, -) -> Outcome { +) -> Result { let IdleWorker { mut stream, pid, worker_dir } = worker; gum::debug!( @@ -136,16 +137,18 @@ pub async fn start_work( ); with_worker_dir_setup(worker_dir, pid, &artifact.path, |worker_dir| async move { - if let Err(error) = send_request(&mut stream, &validation_params, execution_timeout).await { - gum::warn!( - target: LOG_TARGET, - worker_pid = %pid, - validation_code_hash = ?artifact.id.code_hash, - ?error, - "failed to send an execute request", - ); - return Outcome::WorkerIntfErr - } + send_request(&mut stream, &validation_params, execution_timeout).await.map_err( + |error| { + gum::warn!( + target: LOG_TARGET, + worker_pid = %pid, + validation_code_hash = ?artifact.id.code_hash, + "failed to send an execute request: {}", + error, + ); + Error::InternalError(InternalValidationError::HostCommunication(error.to_string())) + }, + )?; // We use a generous timeout here. This is in addition to the one in the child process, in // case the child stalls. We have a wall clock timeout here in the host, but a CPU timeout @@ -153,12 +156,12 @@ pub async fn start_work( // load, but the CPU resources of the child can only be measured from the parent after the // child process terminates. let timeout = execution_timeout * JOB_TIMEOUT_WALL_CLOCK_FACTOR; - let response = futures::select! { - response = recv_response(&mut stream).fuse() => { - match response { - Ok(response) => - handle_response( - response, + let worker_result = futures::select! { + worker_result = recv_result(&mut stream).fuse() => { + match worker_result { + Ok(result) => + handle_result( + result, pid, execution_timeout, ) @@ -168,11 +171,11 @@ pub async fn start_work( target: LOG_TARGET, worker_pid = %pid, validation_code_hash = ?artifact.id.code_hash, - ?error, - "failed to recv an execute response", + "failed to recv an execute result: {}", + error, ); - return Outcome::WorkerIntfErr + return Err(Error::CommunicationErr(error)) }, } }, @@ -183,29 +186,16 @@ pub async fn start_work( validation_code_hash = ?artifact.id.code_hash, "execution worker exceeded lenient timeout for execution, child worker likely stalled", ); - WorkerResponse::JobTimedOut + return Err(Error::HardTimeout) }, }; - match response { - WorkerResponse::Ok { result_descriptor, duration } => Outcome::Ok { - result_descriptor, - duration, - idle_worker: IdleWorker { stream, pid, worker_dir }, - }, - WorkerResponse::InvalidCandidate(err) => Outcome::InvalidCandidate { - err, - idle_worker: IdleWorker { stream, pid, worker_dir }, - }, - WorkerResponse::RuntimeConstruction(err) => Outcome::RuntimeConstruction { - err, + match worker_result { + Ok(worker_response) => Ok(Response { + worker_response, 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 }, - - WorkerResponse::InternalError(err) => Outcome::InternalError { err }, + }), + Err(worker_error) => Err(worker_error.into()), } }) .await @@ -215,12 +205,12 @@ pub async fn start_work( /// /// Here we know the artifact exists, but is still located in a temporary file which will be cleared /// by [`with_worker_dir_setup`]. -async fn handle_response( - response: WorkerResponse, +async fn handle_result( + worker_result: Result, worker_pid: u32, execution_timeout: Duration, -) -> WorkerResponse { - if let WorkerResponse::Ok { duration, .. } = response { +) -> Result { + if let Ok(WorkerResponse { duration, .. }) = worker_result { if duration > execution_timeout { // The job didn't complete within the timeout. gum::warn!( @@ -232,11 +222,11 @@ async fn handle_response( ); // Return a timeout error. - return WorkerResponse::JobTimedOut + return Err(WorkerError::JobTimedOut) } } - response + worker_result } /// Create a temporary file for an artifact in the worker cache, execute the given future/closure @@ -249,9 +239,9 @@ async fn with_worker_dir_setup( pid: u32, artifact_path: &Path, f: F, -) -> Outcome +) -> Result where - Fut: futures::Future, + Fut: futures::Future>, F: FnOnce(WorkerDir) -> Fut, { // Cheaply create a hard link to the artifact. The artifact is always at a known location in the @@ -263,16 +253,14 @@ where target: LOG_TARGET, worker_pid = %pid, ?worker_dir, - "failed to clear worker cache after the job: {:?}", + "failed to clear worker cache after the job: {}", err, ); - return Outcome::InternalError { - err: InternalValidationError::CouldNotCreateLink(format!("{:?}", err)), - } + return Err(InternalValidationError::CouldNotCreateLink(format!("{:?}", err)).into()); } let worker_dir_path = worker_dir.path().to_owned(); - let outcome = f(worker_dir).await; + let result = f(worker_dir).await; // Try to clear the worker dir. if let Err(err) = clear_worker_dir_path(&worker_dir_path) { @@ -283,15 +271,14 @@ where "failed to clear worker cache after the job: {:?}", err, ); - return Outcome::InternalError { - err: InternalValidationError::CouldNotClearWorkerDir { - err: format!("{:?}", err), - path: worker_dir_path.to_str().map(String::from), - }, + return Err(InternalValidationError::CouldNotClearWorkerDir { + err: format!("{:?}", err), + path: worker_dir_path.to_str().map(String::from), } + .into()) } - outcome + result } /// Sends a handshake with information specific to the execute worker. @@ -308,12 +295,12 @@ async fn send_request( framed_send(stream, &execution_timeout.encode()).await } -async fn recv_response(stream: &mut UnixStream) -> io::Result { - let response_bytes = framed_recv(stream).await?; - WorkerResponse::decode(&mut response_bytes.as_slice()).map_err(|e| { +async fn recv_result(stream: &mut UnixStream) -> io::Result> { + let result_bytes = framed_recv(stream).await?; + Result::::decode(&mut result_bytes.as_slice()).map_err(|e| { io::Error::new( io::ErrorKind::Other, - format!("execute pvf recv_response: decode error: {:?}", e), + format!("execute pvf recv_result: decode error: {:?}", e), ) }) } diff --git a/polkadot/node/core/pvf/src/host.rs b/polkadot/node/core/pvf/src/host.rs index 59d5a7e20a887ef35282f0a8ae8c0998625d825a..4065598a3ac46c32b4d821aac7712f62767a973e 100644 --- a/polkadot/node/core/pvf/src/host.rs +++ b/polkadot/node/core/pvf/src/host.rs @@ -188,6 +188,9 @@ impl Config { secure_validator_mode: bool, prepare_worker_program_path: PathBuf, execute_worker_program_path: PathBuf, + execute_workers_max_num: usize, + prepare_workers_soft_max_num: usize, + prepare_workers_hard_max_num: usize, ) -> Self { Self { cache_path, @@ -196,12 +199,12 @@ impl Config { prepare_worker_program_path, prepare_worker_spawn_timeout: Duration::from_secs(3), - prepare_workers_soft_max_num: 1, - prepare_workers_hard_max_num: 1, + prepare_workers_soft_max_num, + prepare_workers_hard_max_num, execute_worker_program_path, execute_worker_spawn_timeout: Duration::from_secs(3), - execute_workers_max_num: 2, + execute_workers_max_num, } } } @@ -959,10 +962,7 @@ pub(crate) mod tests { use crate::{artifacts::generate_artifact_path, PossiblyInvalidError}; use assert_matches::assert_matches; use futures::future::BoxFuture; - use polkadot_node_core_pvf_common::{ - error::PrepareError, - prepare::{PrepareStats, PrepareSuccess}, - }; + use polkadot_node_core_pvf_common::prepare::PrepareStats; const TEST_EXECUTION_TIMEOUT: Duration = Duration::from_secs(3); pub(crate) const TEST_PREPARATION_TIMEOUT: Duration = Duration::from_secs(30); diff --git a/polkadot/node/core/pvf/src/metrics.rs b/polkadot/node/core/pvf/src/metrics.rs index 7fd876cf17405f4815173ab289d34f41d7e1e1cc..bc8d300037fe8e1d7c70b575d99b101b8343e94b 100644 --- a/polkadot/node/core/pvf/src/metrics.rs +++ b/polkadot/node/core/pvf/src/metrics.rs @@ -74,6 +74,12 @@ impl Metrics { self.0.as_ref().map(|metrics| metrics.execution_time.start_timer()) } + pub(crate) fn observe_execution_queued_time(&self, queued_for_millis: u32) { + self.0.as_ref().map(|metrics| { + metrics.execution_queued_time.observe(queued_for_millis as f64 / 1000 as f64) + }); + } + /// Observe memory stats for preparation. #[allow(unused_variables)] pub(crate) fn observe_preparation_memory_metrics(&self, memory_stats: MemoryStats) { @@ -112,6 +118,7 @@ struct MetricsInner { execute_finished: prometheus::Counter, preparation_time: prometheus::Histogram, execution_time: prometheus::Histogram, + execution_queued_time: prometheus::Histogram, #[cfg(target_os = "linux")] preparation_max_rss: prometheus::Histogram, // Max. allocated memory, tracked by Jemallocator, polling-based @@ -240,6 +247,31 @@ impl metrics::Metrics for Metrics { )?, registry, )?, + execution_queued_time: prometheus::register( + prometheus::Histogram::with_opts( + prometheus::HistogramOpts::new( + "polkadot_pvf_execution_queued_time", + "Time spent in queue waiting for PVFs execution job to be assigned", + ).buckets(vec![ + 0.01, + 0.025, + 0.05, + 0.1, + 0.25, + 0.5, + 1.0, + 2.0, + 3.0, + 4.0, + 5.0, + 6.0, + 12.0, + 24.0, + 48.0, + ]), + )?, + registry, + )?, #[cfg(target_os = "linux")] preparation_max_rss: prometheus::register( prometheus::Histogram::with_opts( diff --git a/polkadot/node/core/pvf/src/priority.rs b/polkadot/node/core/pvf/src/priority.rs index d1ef9c604b117d10aca5b99cc8ccd1953fa522f5..0d18d4b484cabbde70361019e7008887e419b350 100644 --- a/polkadot/node/core/pvf/src/priority.rs +++ b/polkadot/node/core/pvf/src/priority.rs @@ -14,17 +14,18 @@ // You should have received a copy of the GNU General Public License // along with Polkadot. If not, see . -/// A priority assigned to execution of a PVF. +/// A priority assigned to preparation of a PVF. #[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord)] pub enum Priority { /// Normal priority for things that do not require immediate response, but still need to be /// done pretty quick. /// - /// Approvals and disputes fall into this category. + /// Backing falls into this category. Normal, /// This priority is used for requests that are required to be processed as soon as possible. /// - /// For example, backing is on a critical path and requires execution as soon as possible. + /// Disputes and approvals are on a critical path and require execution as soon as + /// possible to not delay finality. Critical, } diff --git a/polkadot/node/core/pvf/tests/it/main.rs b/polkadot/node/core/pvf/tests/it/main.rs index 16ef23c69cad9d40d6cd79d2a754d8a347bfac3c..6961b93832abed0d8608e8363a1fac3d2d510fdf 100644 --- a/polkadot/node/core/pvf/tests/it/main.rs +++ b/polkadot/node/core/pvf/tests/it/main.rs @@ -26,7 +26,7 @@ use polkadot_node_core_pvf::{ ValidationHost, JOB_TIMEOUT_WALL_CLOCK_FACTOR, }; use polkadot_parachain_primitives::primitives::{BlockData, ValidationParams, ValidationResult}; -use polkadot_primitives::{ExecutorParam, ExecutorParams}; +use polkadot_primitives::{ExecutorParam, ExecutorParams, PvfExecKind, PvfPrepKind}; use std::{io::Write, time::Duration}; use tokio::sync::Mutex; @@ -63,6 +63,9 @@ impl TestHost { false, prepare_worker_path, execute_worker_path, + 2, + 1, + 2, ); f(&mut config); let (host, task) = start(config, Metrics::default()).await.unwrap(); @@ -556,3 +559,73 @@ async fn nonexistent_cache_dir() { .await .unwrap(); } + +// Checks the the artifact is not re-prepared when the executor environment parameters change +// in a way not affecting the preparation +#[tokio::test] +async fn artifact_does_not_reprepare_on_non_meaningful_exec_parameter_change() { + let host = TestHost::new_with_config(|cfg| { + cfg.prepare_workers_hard_max_num = 1; + }) + .await; + let cache_dir = host.cache_dir.path(); + + let set1 = ExecutorParams::default(); + let set2 = + ExecutorParams::from(&[ExecutorParam::PvfExecTimeout(PvfExecKind::Backing, 2500)][..]); + + let _stats = host.precheck_pvf(halt::wasm_binary_unwrap(), set1).await.unwrap(); + + let md1 = { + let mut cache_dir: Vec<_> = std::fs::read_dir(cache_dir).unwrap().collect(); + 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(); + } + std::fs::metadata(artifact_path.path()).unwrap() + }; + + // FS times are not monotonical so we wait 2 secs here to be sure that the creation time of the + // second attifact will be different + tokio::time::sleep(Duration::from_secs(2)).await; + + let _stats = host.precheck_pvf(halt::wasm_binary_unwrap(), set2).await.unwrap(); + + let md2 = { + let mut cache_dir: Vec<_> = std::fs::read_dir(cache_dir).unwrap().collect(); + 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(); + } + std::fs::metadata(artifact_path.path()).unwrap() + }; + + assert_eq!(md1.created().unwrap(), md2.created().unwrap()); +} + +// Checks if the artifact is re-prepared if the re-preparation is needed by the nature of +// the execution environment parameters change +#[tokio::test] +async fn artifact_does_reprepare_on_meaningful_exec_parameter_change() { + let host = TestHost::new_with_config(|cfg| { + cfg.prepare_workers_hard_max_num = 1; + }) + .await; + let cache_dir = host.cache_dir.path(); + + let set1 = ExecutorParams::default(); + let set2 = + ExecutorParams::from(&[ExecutorParam::PvfPrepTimeout(PvfPrepKind::Prepare, 60000)][..]); + + let _stats = host.precheck_pvf(halt::wasm_binary_unwrap(), set1).await.unwrap(); + let cache_dir_contents: Vec<_> = std::fs::read_dir(cache_dir).unwrap().collect(); + + assert_eq!(cache_dir_contents.len(), 2); + + let _stats = host.precheck_pvf(halt::wasm_binary_unwrap(), set2).await.unwrap(); + let cache_dir_contents: Vec<_> = std::fs::read_dir(cache_dir).unwrap().collect(); + + assert_eq!(cache_dir_contents.len(), 3); // new artifact has been added +} diff --git a/polkadot/node/core/runtime-api/src/cache.rs b/polkadot/node/core/runtime-api/src/cache.rs index 7cd1f7ce7281719a0875394871858c65b8f6045a..05efbc533d0204f25d4e55cc36e4a354f655f437 100644 --- a/polkadot/node/core/runtime-api/src/cache.rs +++ b/polkadot/node/core/runtime-api/src/cache.rs @@ -24,8 +24,8 @@ use polkadot_primitives::{ CandidateCommitments, CandidateEvent, CandidateHash, CommittedCandidateReceipt, CoreIndex, CoreState, DisputeState, ExecutorParams, GroupRotationInfo, Hash, Id as ParaId, InboundDownwardMessage, InboundHrmpMessage, NodeFeatures, OccupiedCoreAssumption, - PersistedValidationData, PvfCheckStatement, ScrapedOnChainVotes, SessionIndex, SessionInfo, - ValidationCode, ValidationCodeHash, ValidatorId, ValidatorIndex, ValidatorSignature, + PersistedValidationData, ScrapedOnChainVotes, SessionIndex, SessionInfo, ValidationCode, + ValidationCodeHash, ValidatorId, ValidatorIndex, }; /// For consistency we have the same capacity for all caches. We use 128 as we'll only need that @@ -561,7 +561,7 @@ pub(crate) enum RequestResult { // The structure of each variant is (relay_parent, [params,]*, result) Authorities(Hash, Vec), Validators(Hash, Vec), - MinimumBackingVotes(Hash, SessionIndex, u32), + MinimumBackingVotes(SessionIndex, u32), ValidatorGroups(Hash, (Vec>, GroupRotationInfo)), AvailabilityCores(Hash, Vec), PersistedValidationData(Hash, ParaId, OccupiedCoreAssumption, Option), @@ -589,19 +589,16 @@ pub(crate) enum RequestResult { FetchOnChainVotes(Hash, Option), PvfsRequirePrecheck(Hash, Vec), // This is a request with side-effects and no result, hence (). - SubmitPvfCheckStatement(Hash, PvfCheckStatement, ValidatorSignature, ()), + #[allow(dead_code)] + SubmitPvfCheckStatement(()), ValidationCodeHash(Hash, ParaId, OccupiedCoreAssumption, Option), Version(Hash, u32), Disputes(Hash, Vec<(SessionIndex, CandidateHash, DisputeState)>), UnappliedSlashes(Hash, Vec<(SessionIndex, CandidateHash, slashing::PendingSlashes)>), KeyOwnershipProof(Hash, ValidatorId, Option), // This is a request with side-effects. - SubmitReportDisputeLost( - Hash, - slashing::DisputeProof, - slashing::OpaqueKeyOwnershipProof, - Option<()>, - ), + #[allow(dead_code)] + SubmitReportDisputeLost(Option<()>), ApprovalVotingParams(Hash, SessionIndex, ApprovalVotingParams), DisabledValidators(Hash, Vec), ParaBackingState(Hash, ParaId, Option), diff --git a/polkadot/node/core/runtime-api/src/lib.rs b/polkadot/node/core/runtime-api/src/lib.rs index b7995aeeee761e489262504f017e1c79b677b875..c8b1d61e7be720734a65484a86f4685fc61580b8 100644 --- a/polkadot/node/core/runtime-api/src/lib.rs +++ b/polkadot/node/core/runtime-api/src/lib.rs @@ -101,7 +101,7 @@ where self.requests_cache.cache_authorities(relay_parent, authorities), Validators(relay_parent, validators) => self.requests_cache.cache_validators(relay_parent, validators), - MinimumBackingVotes(_, session_index, minimum_backing_votes) => self + MinimumBackingVotes(session_index, minimum_backing_votes) => self .requests_cache .cache_minimum_backing_votes(session_index, minimum_backing_votes), ValidatorGroups(relay_parent, groups) => @@ -155,7 +155,7 @@ where self.requests_cache.cache_on_chain_votes(relay_parent, scraped), PvfsRequirePrecheck(relay_parent, pvfs) => self.requests_cache.cache_pvfs_require_precheck(relay_parent, pvfs), - SubmitPvfCheckStatement(_, _, _, ()) => {}, + SubmitPvfCheckStatement(()) => {}, ValidationCodeHash(relay_parent, para_id, assumption, hash) => self .requests_cache .cache_validation_code_hash((relay_parent, para_id, assumption), hash), @@ -170,7 +170,7 @@ where .cache_key_ownership_proof((relay_parent, validator_id), key_ownership_proof), RequestResult::ApprovalVotingParams(_relay_parent, session_index, params) => self.requests_cache.cache_approval_voting_params(session_index, params), - SubmitReportDisputeLost(_, _, _, _) => {}, + SubmitReportDisputeLost(_) => {}, DisabledValidators(relay_parent, disabled_validators) => self.requests_cache.cache_disabled_validators(relay_parent, disabled_validators), ParaBackingState(relay_parent, para_id, constraints) => self @@ -370,7 +370,7 @@ where async fn poll_requests(&mut self) { // If there are no active requests, this future should be pending forever. if self.active_requests.len() == 0 { - return futures::pending!() + return futures::pending!(); } // If there are active requests, this will always resolve to `Some(_)` when a request is @@ -439,7 +439,7 @@ where }}; ($req_variant:ident, $api_name:ident ($($param:expr),*), ver = $version:expr, $sender:expr, result = ( $($results:expr),* ) ) => {{ let sender = $sender; - let version: u32 = $version; // enforce type for the version expression + let version: u32 = $version; // enforce type for the version expression let runtime_version = client.api_version_parachain_host(relay_parent).await .unwrap_or_else(|e| { gum::warn!( @@ -570,7 +570,8 @@ where SubmitPvfCheckStatement, submit_pvf_check_statement(stmt, signature), ver = 2, - sender + sender, + result = () ) }, Request::PvfsRequirePrecheck(sender) => { @@ -606,13 +607,15 @@ where SubmitReportDisputeLost, submit_report_dispute_lost(dispute_proof, key_ownership_proof), ver = Request::SUBMIT_REPORT_DISPUTE_LOST_RUNTIME_REQUIREMENT, - sender + sender, + result = () ), Request::MinimumBackingVotes(index, sender) => query!( MinimumBackingVotes, minimum_backing_votes(index), ver = Request::MINIMUM_BACKING_VOTES_RUNTIME_REQUIREMENT, - sender + sender, + result = (index) ), Request::DisabledValidators(sender) => query!( DisabledValidators, diff --git a/polkadot/node/jaeger/Cargo.toml b/polkadot/node/jaeger/Cargo.toml index bee725c0876f0cd57692d754738219dd731f8d62..f879f9550d014c0571558f5238f13ce9dad5fe4e 100644 --- a/polkadot/node/jaeger/Cargo.toml +++ b/polkadot/node/jaeger/Cargo.toml @@ -21,4 +21,4 @@ sp-core = { path = "../../../substrate/primitives/core" } thiserror = { workspace = true } tokio = "1.37" log = { workspace = true, default-features = true } -parity-scale-codec = { version = "3.6.1", default-features = false } +parity-scale-codec = { version = "3.6.12", default-features = false } diff --git a/polkadot/node/malus/Cargo.toml b/polkadot/node/malus/Cargo.toml index 2f63c2f0938d72bea717ac5aff0b2faace47808b..750074fa9b3cb6209d640b75189768fd94faccf2 100644 --- a/polkadot/node/malus/Cargo.toml +++ b/polkadot/node/malus/Cargo.toml @@ -37,6 +37,7 @@ polkadot-node-core-dispute-coordinator = { path = "../core/dispute-coordinator" polkadot-node-core-candidate-validation = { path = "../core/candidate-validation" } polkadot-node-core-backing = { path = "../core/backing" } polkadot-node-primitives = { path = "../primitives" } +polkadot-node-network-protocol = { path = "../network/protocol" } polkadot-primitives = { path = "../../primitives" } color-eyre = { version = "0.6.1", default-features = false } assert_matches = "1.5" diff --git a/polkadot/node/malus/src/malus.rs b/polkadot/node/malus/src/malus.rs index 7a9e320e27368e51da0508910fea5b7c54f2d6c7..6257201537c8d417fc9abf972951340b144d110d 100644 --- a/polkadot/node/malus/src/malus.rs +++ b/polkadot/node/malus/src/malus.rs @@ -40,6 +40,8 @@ enum NemesisVariant { DisputeAncestor(DisputeAncestorOptions), /// Delayed disputing of finalized candidates. DisputeFinalizedCandidates(DisputeFinalizedCandidatesOptions), + /// Spam many request statements instead of sending a single one. + SpamStatementRequests(SpamStatementRequestsOptions), } #[derive(Debug, Parser)] @@ -98,6 +100,11 @@ impl MalusCli { finality_delay, )? }, + NemesisVariant::SpamStatementRequests(opts) => { + let SpamStatementRequestsOptions { spam_factor, cli } = opts; + + polkadot_cli::run_node(cli, SpamStatementRequests { spam_factor }, finality_delay)? + }, } Ok(()) } diff --git a/polkadot/node/malus/src/variants/mod.rs b/polkadot/node/malus/src/variants/mod.rs index 3ca1bf4b4696843476c3de2b6dc441224b0ea9bd..ec945ae1945735b368b173647a4135ac408ca392 100644 --- a/polkadot/node/malus/src/variants/mod.rs +++ b/polkadot/node/malus/src/variants/mod.rs @@ -20,6 +20,7 @@ mod back_garbage_candidate; mod common; mod dispute_finalized_candidates; mod dispute_valid_candidates; +mod spam_statement_requests; mod suggest_garbage_candidate; mod support_disabled; @@ -27,6 +28,7 @@ pub(crate) use self::{ back_garbage_candidate::{BackGarbageCandidateOptions, BackGarbageCandidates}, dispute_finalized_candidates::{DisputeFinalizedCandidates, DisputeFinalizedCandidatesOptions}, dispute_valid_candidates::{DisputeAncestorOptions, DisputeValidCandidates}, + spam_statement_requests::{SpamStatementRequests, SpamStatementRequestsOptions}, suggest_garbage_candidate::{SuggestGarbageCandidateOptions, SuggestGarbageCandidates}, support_disabled::{SupportDisabled, SupportDisabledOptions}, }; diff --git a/polkadot/node/malus/src/variants/spam_statement_requests.rs b/polkadot/node/malus/src/variants/spam_statement_requests.rs new file mode 100644 index 0000000000000000000000000000000000000000..c5970c988ac2a3417ba7a9974e6e44f32cf9b854 --- /dev/null +++ b/polkadot/node/malus/src/variants/spam_statement_requests.rs @@ -0,0 +1,155 @@ +// 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 malicious node variant that attempts spam statement requests. +//! +//! This malus variant behaves honestly in everything except when propagating statement distribution +//! requests through the network bridge subsystem. Instead of sending a single request when it needs +//! something it attempts to spam the peer with multiple requests. +//! +//! Attention: For usage with `zombienet` only! + +#![allow(missing_docs)] + +use polkadot_cli::{ + service::{ + AuxStore, Error, ExtendedOverseerGenArgs, Overseer, OverseerConnector, OverseerGen, + OverseerGenArgs, OverseerHandle, + }, + validator_overseer_builder, Cli, +}; +use polkadot_node_network_protocol::request_response::{outgoing::Requests, OutgoingRequest}; +use polkadot_node_subsystem::{messages::NetworkBridgeTxMessage, SpawnGlue}; +use polkadot_node_subsystem_types::{ChainApiBackend, RuntimeApiSubsystemClient}; +use sp_core::traits::SpawnNamed; + +// Filter wrapping related types. +use crate::{interceptor::*, shared::MALUS}; + +use std::sync::Arc; + +/// Wraps around network bridge and replaces it. +#[derive(Clone)] +struct RequestSpammer { + spam_factor: u32, // How many statement distribution requests to send. +} + +impl MessageInterceptor for RequestSpammer +where + Sender: overseer::NetworkBridgeTxSenderTrait + Clone + Send + 'static, +{ + type Message = NetworkBridgeTxMessage; + + /// Intercept NetworkBridgeTxMessage::SendRequests with Requests::AttestedCandidateV2 inside and + /// duplicate that request + fn intercept_incoming( + &self, + _subsystem_sender: &mut Sender, + msg: FromOrchestra, + ) -> Option> { + match msg { + FromOrchestra::Communication { + msg: NetworkBridgeTxMessage::SendRequests(requests, if_disconnected), + } => { + let mut new_requests = Vec::new(); + + for request in requests { + match request { + Requests::AttestedCandidateV2(ref req) => { + // Temporarily store peer and payload for duplication + let peer_to_duplicate = req.peer.clone(); + let payload_to_duplicate = req.payload.clone(); + // Push the original request + new_requests.push(request); + + // Duplicate for spam purposes + gum::info!( + target: MALUS, + "😈 Duplicating AttestedCandidateV2 request extra {:?} times to peer: {:?}.", self.spam_factor, peer_to_duplicate, + ); + new_requests.extend((0..self.spam_factor - 1).map(|_| { + let (new_outgoing_request, _) = OutgoingRequest::new( + peer_to_duplicate.clone(), + payload_to_duplicate.clone(), + ); + Requests::AttestedCandidateV2(new_outgoing_request) + })); + }, + _ => { + new_requests.push(request); + }, + } + } + + // Passthrough the message with a potentially modified number of requests + Some(FromOrchestra::Communication { + msg: NetworkBridgeTxMessage::SendRequests(new_requests, if_disconnected), + }) + }, + FromOrchestra::Communication { msg } => Some(FromOrchestra::Communication { msg }), + FromOrchestra::Signal(signal) => Some(FromOrchestra::Signal(signal)), + } + } +} + +//---------------------------------------------------------------------------------- + +#[derive(Debug, clap::Parser)] +#[clap(rename_all = "kebab-case")] +#[allow(missing_docs)] +pub struct SpamStatementRequestsOptions { + /// How many statement distribution requests to send. + #[clap(long, ignore_case = true, default_value_t = 1000, value_parser = clap::value_parser!(u32).range(0..=10000000))] + pub spam_factor: u32, + + #[clap(flatten)] + pub cli: Cli, +} + +/// SpamStatementRequests implementation wrapper which implements `OverseerGen` glue. +pub(crate) struct SpamStatementRequests { + /// How many statement distribution requests to send. + pub spam_factor: u32, +} + +impl OverseerGen for SpamStatementRequests { + fn generate( + &self, + connector: OverseerConnector, + args: OverseerGenArgs<'_, Spawner, RuntimeClient>, + ext_args: Option, + ) -> Result<(Overseer, Arc>, OverseerHandle), Error> + where + RuntimeClient: RuntimeApiSubsystemClient + ChainApiBackend + AuxStore + 'static, + Spawner: 'static + SpawnNamed + Clone + Unpin, + { + gum::info!( + target: MALUS, + "😈 Started Malus node that duplicates each statement distribution request spam_factor = {:?} times.", + &self.spam_factor, + ); + + let request_spammer = RequestSpammer { spam_factor: self.spam_factor }; + + validator_overseer_builder( + args, + ext_args.expect("Extended arguments required to build validator overseer are provided"), + )? + .replace_network_bridge_tx(move |cb| InterceptedSubsystem::new(cb, request_spammer)) + .build_with_connector(connector) + .map_err(|e| e.into()) + } +} diff --git a/polkadot/node/metrics/Cargo.toml b/polkadot/node/metrics/Cargo.toml index fbf0abf829e136a139f3de0db3aef216b2e49679..e3a53cc6df1b435d3e2361d388624252c2df9d3d 100644 --- a/polkadot/node/metrics/Cargo.toml +++ b/polkadot/node/metrics/Cargo.toml @@ -21,7 +21,7 @@ sc-cli = { path = "../../../substrate/client/cli" } substrate-prometheus-endpoint = { path = "../../../substrate/utils/prometheus" } sc-tracing = { path = "../../../substrate/client/tracing" } -codec = { package = "parity-scale-codec", version = "3.6.1" } +codec = { package = "parity-scale-codec", version = "3.6.12" } primitives = { package = "polkadot-primitives", path = "../../primitives" } bs58 = { version = "0.5.0", features = ["alloc"] } log = { workspace = true, default-features = true } diff --git a/polkadot/node/network/approval-distribution/Cargo.toml b/polkadot/node/network/approval-distribution/Cargo.toml index 4c04ad83f84f3c75e69ac8771670816b7ea7b4fa..d80519b9e2e95aa4d958bff5b9a08e3bddb2cf3c 100644 --- a/polkadot/node/network/approval-distribution/Cargo.toml +++ b/polkadot/node/network/approval-distribution/Cargo.toml @@ -18,7 +18,7 @@ polkadot-node-subsystem-util = { path = "../../subsystem-util" } polkadot-primitives = { path = "../../../primitives" } polkadot-node-jaeger = { path = "../../jaeger" } rand = "0.8" -itertools = "0.10.5" +itertools = "0.11" futures = "0.3.30" futures-timer = "3.0.2" diff --git a/polkadot/node/network/approval-distribution/src/lib.rs b/polkadot/node/network/approval-distribution/src/lib.rs index d360a18423e6bdea62ee0609cf5ea67f16e2e68e..369d82b45b094b30f0b65d72d54d5c14c1e28440 100644 --- a/polkadot/node/network/approval-distribution/src/lib.rs +++ b/polkadot/node/network/approval-distribution/src/lib.rs @@ -148,6 +148,7 @@ enum ApprovalEntryError { InvalidCandidateIndex, DuplicateApproval, UnknownAssignment, + #[allow(dead_code)] AssignmentsFollowedDifferentPaths(RequiredRouting, RequiredRouting), } diff --git a/polkadot/node/network/availability-distribution/Cargo.toml b/polkadot/node/network/availability-distribution/Cargo.toml index b5636203f166efdbc2d871df778d148c0f9ce3e4..39e2985a88cfa5de7309d367df32e3c9aa3c8328 100644 --- a/polkadot/node/network/availability-distribution/Cargo.toml +++ b/polkadot/node/network/availability-distribution/Cargo.toml @@ -12,7 +12,7 @@ workspace = true [dependencies] futures = "0.3.30" gum = { package = "tracing-gum", path = "../../gum" } -parity-scale-codec = { version = "3.6.1", features = ["std"] } +parity-scale-codec = { version = "3.6.12", features = ["std"] } polkadot-primitives = { path = "../../../primitives" } polkadot-erasure-coding = { path = "../../../erasure-coding" } polkadot-node-network-protocol = { path = "../protocol" } @@ -25,7 +25,7 @@ thiserror = { workspace = true } rand = "0.8.5" derive_more = "0.99.17" schnellru = "0.2.1" -fatality = "0.0.6" +fatality = "0.1.1" [dev-dependencies] polkadot-node-subsystem-test-helpers = { path = "../../subsystem-test-helpers" } diff --git a/polkadot/node/network/availability-distribution/benches/availability-distribution-regression-bench.rs b/polkadot/node/network/availability-distribution/benches/availability-distribution-regression-bench.rs index 0d4f4f49e31f4d77342a3c084431e75f3c9e0725..5e3072be3a8c13d08bfec7fc5840320fcc33c6c5 100644 --- a/polkadot/node/network/availability-distribution/benches/availability-distribution-regression-bench.rs +++ b/polkadot/node/network/availability-distribution/benches/availability-distribution-regression-bench.rs @@ -31,7 +31,7 @@ use polkadot_subsystem_bench::{ }; use std::io::Write; -const BENCH_COUNT: usize = 5; +const BENCH_COUNT: usize = 50; fn main() -> Result<(), String> { let mut messages = vec![]; @@ -40,8 +40,6 @@ fn main() -> Result<(), String> { config.n_cores = 10; config.n_validators = 500; config.num_blocks = 3; - config.connectivity = 100; - config.latency = None; config.generate_pov_sizes(); let state = TestState::new(&config); @@ -75,13 +73,13 @@ fn main() -> Result<(), String> { // We expect no variance for received and sent // but use 0.001 because we operate with floats messages.extend(average_usage.check_network_usage(&[ - ("Received from peers", 433.3, 0.001), - ("Sent to peers", 18480.0, 0.001), + ("Received from peers", 433.3333, 0.001), + ("Sent to peers", 18479.9000, 0.001), ])); messages.extend(average_usage.check_cpu_usage(&[ - ("availability-distribution", 0.012, 0.05), - ("availability-store", 0.153, 0.05), - ("bitfield-distribution", 0.026, 0.05), + ("availability-distribution", 0.0123, 0.1), + ("availability-store", 0.1597, 0.1), + ("bitfield-distribution", 0.0223, 0.1), ])); if messages.is_empty() { diff --git a/polkadot/node/network/availability-recovery/Cargo.toml b/polkadot/node/network/availability-recovery/Cargo.toml index dd0e0c432345ed7006fa4a18fbb05bc9efca8538..eb503f502b2983367fc036c1aea3723958eada7e 100644 --- a/polkadot/node/network/availability-recovery/Cargo.toml +++ b/polkadot/node/network/availability-recovery/Cargo.toml @@ -14,7 +14,7 @@ futures = "0.3.30" tokio = "1.37" schnellru = "0.2.1" rand = "0.8.5" -fatality = "0.0.6" +fatality = "0.1.1" thiserror = { workspace = true } async-trait = "0.1.79" gum = { package = "tracing-gum", path = "../../gum" } @@ -25,7 +25,7 @@ polkadot-node-primitives = { path = "../../primitives" } polkadot-node-subsystem = { path = "../../subsystem" } polkadot-node-subsystem-util = { path = "../../subsystem-util" } polkadot-node-network-protocol = { path = "../protocol" } -parity-scale-codec = { version = "3.6.1", default-features = false, features = ["derive"] } +parity-scale-codec = { version = "3.6.12", default-features = false, features = ["derive"] } sc-network = { path = "../../../../substrate/client/network" } [dev-dependencies] diff --git a/polkadot/node/network/availability-recovery/benches/availability-recovery-regression-bench.rs b/polkadot/node/network/availability-recovery/benches/availability-recovery-regression-bench.rs index 9be147bda93a8bdd3efac4e4ccce61d79d6501b8..d9bdc1a2d944d71231d0679fd5e5ef79a52cc782 100644 --- a/polkadot/node/network/availability-recovery/benches/availability-recovery-regression-bench.rs +++ b/polkadot/node/network/availability-recovery/benches/availability-recovery-regression-bench.rs @@ -32,7 +32,7 @@ use polkadot_subsystem_bench::{ }; use std::io::Write; -const BENCH_COUNT: usize = 5; +const BENCH_COUNT: usize = 10; fn main() -> Result<(), String> { let mut messages = vec![]; @@ -40,8 +40,6 @@ fn main() -> Result<(), String> { let options = DataAvailabilityReadOptions { fetch_from_backers: true }; let mut config = TestConfiguration::default(); config.num_blocks = 3; - config.connectivity = 100; - config.latency = None; config.generate_pov_sizes(); let state = TestState::new(&config); @@ -73,10 +71,10 @@ fn main() -> Result<(), String> { // We expect no variance for received and sent // but use 0.001 because we operate with floats messages.extend(average_usage.check_network_usage(&[ - ("Received from peers", 307200.000, 0.001), - ("Sent to peers", 1.667, 0.001), + ("Received from peers", 307203.0000, 0.001), + ("Sent to peers", 1.6667, 0.001), ])); - messages.extend(average_usage.check_cpu_usage(&[("availability-recovery", 11.500, 0.05)])); + messages.extend(average_usage.check_cpu_usage(&[("availability-recovery", 12.8338, 0.1)])); if messages.is_empty() { Ok(()) diff --git a/polkadot/node/network/bitfield-distribution/src/tests.rs b/polkadot/node/network/bitfield-distribution/src/tests.rs index 188b51ebcccae89fd6f69410fd054d25eeabbb01..dc37f73ec8a12fdf2ae3a44b41fef6902e0e9998 100644 --- a/polkadot/node/network/bitfield-distribution/src/tests.rs +++ b/polkadot/node/network/bitfield-distribution/src/tests.rs @@ -40,7 +40,7 @@ use sp_core::Pair as PairT; use sp_keyring::Sr25519Keyring; use sp_keystore::{testing::MemoryKeystore, Keystore, KeystorePtr}; -use std::{iter::FromIterator as _, sync::Arc, time::Duration}; +use std::{sync::Arc, time::Duration}; const TIMEOUT: Duration = Duration::from_millis(50); macro_rules! launch { diff --git a/polkadot/node/network/bridge/Cargo.toml b/polkadot/node/network/bridge/Cargo.toml index 9c2423e7e5810c3406ab4f40c219dbd8001245bb..b609fb1e071957868c4bff91e02ca5d110aae9ee 100644 --- a/polkadot/node/network/bridge/Cargo.toml +++ b/polkadot/node/network/bridge/Cargo.toml @@ -15,7 +15,7 @@ async-trait = "0.1.79" futures = "0.3.30" gum = { package = "tracing-gum", path = "../../gum" } polkadot-primitives = { path = "../../../primitives" } -parity-scale-codec = { version = "3.6.1", default-features = false, features = ["derive"] } +parity-scale-codec = { version = "3.6.12", default-features = false, features = ["derive"] } sc-network = { path = "../../../../substrate/client/network" } sp-consensus = { path = "../../../../substrate/primitives/consensus/common" } polkadot-node-metrics = { path = "../../metrics" } @@ -24,7 +24,7 @@ polkadot-node-subsystem = { path = "../../subsystem" } polkadot-overseer = { path = "../../overseer" } parking_lot = "0.12.1" bytes = "1" -fatality = "0.0.6" +fatality = "0.1.1" thiserror = { workspace = true } [dev-dependencies] diff --git a/polkadot/node/network/collator-protocol/Cargo.toml b/polkadot/node/network/collator-protocol/Cargo.toml index 2c7135742f56890a7ad147e95c545cbebde04c9b..c02999a59b5a976748a7afe641b069851f6eb3c8 100644 --- a/polkadot/node/network/collator-protocol/Cargo.toml +++ b/polkadot/node/network/collator-protocol/Cargo.toml @@ -24,7 +24,7 @@ polkadot-node-network-protocol = { path = "../protocol" } polkadot-node-primitives = { path = "../../primitives" } polkadot-node-subsystem-util = { path = "../../subsystem-util" } polkadot-node-subsystem = { path = "../../subsystem" } -fatality = "0.0.6" +fatality = "0.1.1" thiserror = { workspace = true } tokio-util = "0.7.1" @@ -32,12 +32,13 @@ tokio-util = "0.7.1" log = { workspace = true, default-features = true } env_logger = "0.11" assert_matches = "1.4.0" +rstest = "0.18.2" sp-core = { path = "../../../../substrate/primitives/core", features = ["std"] } sp-keyring = { path = "../../../../substrate/primitives/keyring" } sc-keystore = { path = "../../../../substrate/client/keystore" } sc-network = { path = "../../../../substrate/client/network" } -parity-scale-codec = { version = "3.6.1", features = ["std"] } +parity-scale-codec = { version = "3.6.12", features = ["std"] } polkadot-node-subsystem-test-helpers = { path = "../../subsystem-test-helpers" } polkadot-primitives-test-helpers = { path = "../../../primitives/test-helpers" } diff --git a/polkadot/node/network/collator-protocol/src/collator_side/mod.rs b/polkadot/node/network/collator-protocol/src/collator_side/mod.rs index e6aa55235b7a8094d54fff1c6b5d15a9d0c198ab..f227e3855fa0a72b268a5be9b6e33d8712111dc1 100644 --- a/polkadot/node/network/collator-protocol/src/collator_side/mod.rs +++ b/polkadot/node/network/collator-protocol/src/collator_side/mod.rs @@ -16,7 +16,6 @@ use std::{ collections::{HashMap, HashSet}, - convert::TryInto, time::Duration, }; @@ -262,7 +261,7 @@ struct State { /// `active_leaves`, the opposite doesn't hold true. /// /// Relay-chain blocks which don't support prospective parachains are - /// never included in the fragment trees of active leaves which do. In + /// never included in the fragment chains of active leaves which do. In /// particular, this means that if a given relay parent belongs to implicit /// ancestry of some active leaf, then it does support prospective parachains. implicit_view: ImplicitView, @@ -532,7 +531,7 @@ async fn distribute_collation( // Otherwise, it should be present in allowed ancestry of some leaf. // // It's collation-producer responsibility to verify that there exists - // a hypothetical membership in a fragment tree for candidate. + // a hypothetical membership in a fragment chain for the candidate. let interested = state .peer_data @@ -895,7 +894,7 @@ async fn process_msg( ); } }, - msg @ (ReportCollator(..) | Invalid(..) | Seconded(..) | Backed { .. }) => { + msg @ (ReportCollator(..) | Invalid(..) | Seconded(..)) => { gum::warn!( target: LOG_TARGET, "{:?} message is not expected on the collator side of the protocol", diff --git a/polkadot/node/network/collator-protocol/src/validator_side/collation.rs b/polkadot/node/network/collator-protocol/src/validator_side/collation.rs index 8c3889a3554865c919f2eb33a8f86cce15317ff3..001df1fb3da9b24a3c1acffc049cc7433903aea8 100644 --- a/polkadot/node/network/collator-protocol/src/validator_side/collation.rs +++ b/polkadot/node/network/collator-protocol/src/validator_side/collation.rs @@ -121,19 +121,15 @@ impl PendingCollation { } } -/// v2 or v3 advertisement that was rejected by the backing -/// subsystem. Validator may fetch it later if its fragment -/// membership gets recognized before relay parent goes out of view. -#[derive(Debug, Clone)] -pub struct BlockedAdvertisement { - /// Peer that advertised the collation. - pub peer_id: PeerId, - /// Collator id. - pub collator_id: CollatorId, - /// The relay-parent of the candidate. - pub candidate_relay_parent: Hash, - /// Hash of the candidate. - pub candidate_hash: CandidateHash, +/// An identifier for a fetched collation that was blocked from being seconded because we don't have +/// access to the parent's HeadData. Can be retried once the candidate outputting this head data is +/// seconded. +#[derive(Debug, Clone, Eq, PartialEq, Hash)] +pub struct BlockedCollationId { + /// Para id. + pub para_id: ParaId, + /// Hash of the parent head data. + pub parent_head_data_hash: Hash, } /// Performs a sanity check between advertised and fetched collations. 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 d23279e875419b19052380d8d25a1cda6f5d4dfa..9f037a983e51c33cb734ee65fc496541d1082bf2 100644 --- a/polkadot/node/network/collator-protocol/src/validator_side/mod.rs +++ b/polkadot/node/network/collator-protocol/src/validator_side/mod.rs @@ -20,9 +20,7 @@ use futures::{ use futures_timer::Delay; use std::{ collections::{hash_map::Entry, HashMap, HashSet}, - convert::TryInto, future::Future, - iter::FromIterator, time::{Duration, Instant}, }; use tokio_util::sync::CancellationToken; @@ -61,15 +59,17 @@ use polkadot_primitives::{ use crate::error::{Error, FetchError, Result, SecondingError}; +use self::collation::BlockedCollationId; + use super::{modify_reputation, tick_stream, LOG_TARGET}; mod collation; mod metrics; use collation::{ - fetched_collation_sanity_check, BlockedAdvertisement, CollationEvent, CollationFetchError, - CollationFetchRequest, CollationStatus, Collations, FetchedCollation, PendingCollation, - PendingCollationFetch, ProspectiveCandidate, + fetched_collation_sanity_check, CollationEvent, CollationFetchError, CollationFetchRequest, + CollationStatus, Collations, FetchedCollation, PendingCollation, PendingCollationFetch, + ProspectiveCandidate, }; #[cfg(test)] @@ -390,7 +390,7 @@ struct State { /// `active_leaves`, the opposite doesn't hold true. /// /// Relay-chain blocks which don't support prospective parachains are - /// never included in the fragment trees of active leaves which do. In + /// never included in the fragment chains of active leaves which do. In /// particular, this means that if a given relay parent belongs to implicit /// ancestry of some active leaf, then it does support prospective parachains. implicit_view: ImplicitView, @@ -423,14 +423,6 @@ struct State { /// Span per relay parent. span_per_relay_parent: HashMap, - /// Advertisements that were accepted as valid by collator protocol but rejected by backing. - /// - /// It's only legal to fetch collations that are either built on top of the root - /// of some fragment tree or have a parent node which represents backed candidate. - /// Otherwise, a validator will keep such advertisement in the memory and re-trigger - /// requests to backing on new backed candidates and activations. - blocked_advertisements: HashMap<(ParaId, Hash), Vec>, - /// When a timer in this `FuturesUnordered` triggers, we should dequeue the next request /// attempt in the corresponding `collations_per_relay_parent`. /// @@ -443,6 +435,12 @@ struct State { /// on validation. fetched_candidates: HashMap, + /// Collations which we haven't been able to second due to their parent not being known by + /// prospective-parachains. Mapped from the paraid and parent_head_hash to the fetched + /// collation data. Only needed for async backing. For elastic scaling, the fetched collation + /// must contain the full parent head data. + blocked_from_seconding: HashMap>, + /// Aggregated reputation change reputation: ReputationAggregator, } @@ -953,7 +951,10 @@ enum AdvertisementError { /// parent. ProtocolMisuse, /// Advertisement is invalid. + #[allow(dead_code)] Invalid(InsertAdvertisementError), + /// Seconding not allowed by backing subsystem + BlockedByBacking, } impl AdvertisementError { @@ -963,7 +964,7 @@ impl AdvertisementError { InvalidAssignment => Some(COST_WRONG_PARA), ProtocolMisuse => Some(COST_PROTOCOL_MISUSE), RelayParentUnknown | UndeclaredCollator | Invalid(_) => Some(COST_UNEXPECTED_MESSAGE), - UnknownPeer | SecondedLimitReached => None, + UnknownPeer | SecondedLimitReached | BlockedByBacking => None, } } } @@ -1002,57 +1003,55 @@ where }) } -/// Checks whether any of the advertisements are unblocked and attempts to fetch them. -async fn request_unblocked_collations(sender: &mut Sender, state: &mut State, blocked: I) -where - Sender: CollatorProtocolSenderTrait, - I: IntoIterator)>, -{ - let _timer = state.metrics.time_request_unblocked_collations(); +// Try seconding any collations which were waiting on the validation of their parent +#[overseer::contextbounds(CollatorProtocol, prefix = self::overseer)] +async fn second_unblocked_collations( + ctx: &mut Context, + state: &mut State, + para_id: ParaId, + head_data: HeadData, + head_data_hash: Hash, +) { + if let Some(unblocked_collations) = state + .blocked_from_seconding + .remove(&BlockedCollationId { para_id, parent_head_data_hash: head_data_hash }) + { + if !unblocked_collations.is_empty() { + gum::debug!( + target: LOG_TARGET, + "Candidate outputting head data with hash {} unblocked {} collations for seconding.", + head_data_hash, + unblocked_collations.len() + ); + } - for (key, mut value) in blocked { - let (para_id, para_head) = key; - let blocked = std::mem::take(&mut value); - for blocked in blocked { - let is_seconding_allowed = can_second( - sender, - para_id, - blocked.candidate_relay_parent, - blocked.candidate_hash, - para_head, - ) - .await; + for mut unblocked_collation in unblocked_collations { + unblocked_collation.maybe_parent_head_data = Some(head_data.clone()); + let peer_id = unblocked_collation.collation_event.pending_collation.peer_id; + let relay_parent = unblocked_collation.candidate_receipt.descriptor.relay_parent; - if is_seconding_allowed { - let result = enqueue_collation( - sender, - state, - blocked.candidate_relay_parent, - para_id, - blocked.peer_id, - blocked.collator_id, - Some((blocked.candidate_hash, para_head)), - ) - .await; - if let Err(fetch_error) = result { - gum::debug!( - target: LOG_TARGET, - relay_parent = ?blocked.candidate_relay_parent, - para_id = ?para_id, - peer_id = ?blocked.peer_id, - error = %fetch_error, - "Failed to request unblocked collation", - ); + if let Err(err) = kick_off_seconding(ctx, state, unblocked_collation).await { + gum::warn!( + target: LOG_TARGET, + ?relay_parent, + ?para_id, + ?peer_id, + error = %err, + "Seconding aborted due to an error", + ); + + if err.is_malicious() { + // Report malicious peer. + modify_reputation( + &mut state.reputation, + ctx.sender(), + peer_id, + COST_REPORT_BAD, + ) + .await; } - } else { - // Keep the advertisement. - value.push(blocked); } } - - if !value.is_empty() { - state.blocked_advertisements.insert(key, value); - } } } @@ -1111,10 +1110,10 @@ where } if let Some((candidate_hash, parent_head_data_hash)) = prospective_candidate { - // We need to queue the advertisement if we are not allowed to second it. + // Check if backing subsystem allows to second this candidate. // - // This is also only important when async backing is enabled. - let queue_advertisement = relay_parent_mode.is_enabled() && + // This is also only important when async backing or elastic scaling is enabled. + let seconding_not_allowed = relay_parent_mode.is_enabled() && !can_second( sender, collator_para_id, @@ -1124,26 +1123,8 @@ where ) .await; - if queue_advertisement { - gum::debug!( - target: LOG_TARGET, - relay_parent = ?relay_parent, - para_id = ?para_id, - ?candidate_hash, - "Seconding is not allowed by backing, queueing advertisement", - ); - state - .blocked_advertisements - .entry((collator_para_id, parent_head_data_hash)) - .or_default() - .push(BlockedAdvertisement { - peer_id, - collator_id: collator_id.clone(), - candidate_relay_parent: relay_parent, - candidate_hash, - }); - - return Ok(()) + if seconding_not_allowed { + return Err(AdvertisementError::BlockedByBacking) } } @@ -1359,20 +1340,17 @@ where state.span_per_relay_parent.remove(&removed); } } - // Remove blocked advertisements that left the view. - state.blocked_advertisements.retain(|_, ads| { - ads.retain(|ad| state.per_relay_parent.contains_key(&ad.candidate_relay_parent)); - !ads.is_empty() + // Remove blocked seconding requests that left the view. + state.blocked_from_seconding.retain(|_, collations| { + collations.retain(|collation| { + state + .per_relay_parent + .contains_key(&collation.candidate_receipt.descriptor.relay_parent) + }); + + !collations.is_empty() }); - // Re-trigger previously failed requests again. - // - // This makes sense for several reasons, one simple example: if a hypothetical depth - // for an advertisement initially exceeded the limit and the candidate was included - // in a new leaf. - let maybe_unblocked = std::mem::take(&mut state.blocked_advertisements); - // Could be optimized to only sanity check new leaves. - request_unblocked_collations(sender, state, maybe_unblocked).await; for (peer_id, peer_data) in state.peer_data.iter_mut() { peer_data.prune_old_advertisements( @@ -1509,6 +1487,8 @@ async fn process_msg( return }, }; + let output_head_data = receipt.commitments.head_data.clone(); + let output_head_data_hash = receipt.descriptor.para_head; let fetched_collation = FetchedCollation::from(&receipt.to_plain()); if let Some(CollationEvent { collator_id, pending_collation, .. }) = state.fetched_candidates.remove(&fetched_collation) @@ -1537,6 +1517,17 @@ async fn process_msg( rp_state.collations.status = CollationStatus::Seconded; rp_state.collations.note_seconded(); } + + // See if we've unblocked other collations for seconding. + second_unblocked_collations( + ctx, + state, + fetched_collation.para_id, + output_head_data, + output_head_data_hash, + ) + .await; + // If async backing is enabled, make an attempt to fetch next collation. let maybe_candidate_hash = prospective_candidate.as_ref().map(ProspectiveCandidate::candidate_hash); @@ -1555,11 +1546,13 @@ async fn process_msg( ); } }, - Backed { para_id, para_head } => { - let maybe_unblocked = state.blocked_advertisements.remove_entry(&(para_id, para_head)); - request_unblocked_collations(ctx.sender(), state, maybe_unblocked).await; - }, Invalid(parent, candidate_receipt) => { + // Remove collations which were blocked from seconding and had this candidate as parent. + state.blocked_from_seconding.remove(&BlockedCollationId { + para_id: candidate_receipt.descriptor.para_id, + parent_head_data_hash: candidate_receipt.descriptor.para_head, + }); + let fetched_collation = FetchedCollation::from(&candidate_receipt); let candidate_hash = fetched_collation.candidate_hash; let id = match state.fetched_candidates.entry(fetched_collation) { @@ -1669,29 +1662,45 @@ async fn run_inner( }; let CollationEvent {collator_id, pending_collation, .. } = res.collation_event.clone(); - if let Err(err) = kick_off_seconding(&mut ctx, &mut state, res).await { - gum::warn!( - target: LOG_TARGET, - relay_parent = ?pending_collation.relay_parent, - para_id = ?pending_collation.para_id, - peer_id = ?pending_collation.peer_id, - error = %err, - "Seconding aborted due to an error", - ); - if err.is_malicious() { - // Report malicious peer. - modify_reputation(&mut state.reputation, ctx.sender(), pending_collation.peer_id, COST_REPORT_BAD).await; + match kick_off_seconding(&mut ctx, &mut state, res).await { + Err(err) => { + gum::warn!( + target: LOG_TARGET, + relay_parent = ?pending_collation.relay_parent, + para_id = ?pending_collation.para_id, + peer_id = ?pending_collation.peer_id, + error = %err, + "Seconding aborted due to an error", + ); + + if err.is_malicious() { + // Report malicious peer. + modify_reputation(&mut state.reputation, ctx.sender(), pending_collation.peer_id, COST_REPORT_BAD).await; + } + let maybe_candidate_hash = + pending_collation.prospective_candidate.as_ref().map(ProspectiveCandidate::candidate_hash); + dequeue_next_collation_and_fetch( + &mut ctx, + &mut state, + pending_collation.relay_parent, + (collator_id, maybe_candidate_hash), + ) + .await; + }, + Ok(false) => { + // No hard error occurred, but we can try fetching another collation. + let maybe_candidate_hash = + pending_collation.prospective_candidate.as_ref().map(ProspectiveCandidate::candidate_hash); + dequeue_next_collation_and_fetch( + &mut ctx, + &mut state, + pending_collation.relay_parent, + (collator_id, maybe_candidate_hash), + ) + .await; } - let maybe_candidate_hash = - pending_collation.prospective_candidate.as_ref().map(ProspectiveCandidate::candidate_hash); - dequeue_next_collation_and_fetch( - &mut ctx, - &mut state, - pending_collation.relay_parent, - (collator_id, maybe_candidate_hash), - ) - .await; + Ok(true) => {} } } res = state.collation_fetch_timeouts.select_next_some() => { @@ -1801,12 +1810,13 @@ where } /// Handle a fetched collation result. +/// Returns whether or not seconding has begun. #[overseer::contextbounds(CollatorProtocol, prefix = self::overseer)] async fn kick_off_seconding( ctx: &mut Context, state: &mut State, PendingCollationFetch { mut collation_event, candidate_receipt, pov, maybe_parent_head_data }: PendingCollationFetch, -) -> std::result::Result<(), SecondingError> { +) -> std::result::Result { let pending_collation = collation_event.pending_collation; let relay_parent = pending_collation.relay_parent; @@ -1819,7 +1829,7 @@ async fn kick_off_seconding( relay_parent = ?relay_parent, "Fetched collation for a parent out of view", ); - return Ok(()) + return Ok(false) }, }; let collations = &mut per_relay_parent.collations; @@ -1829,7 +1839,7 @@ async fn kick_off_seconding( collation_event.pending_collation.commitments_hash = Some(candidate_receipt.commitments_hash); - let (maybe_pvd, maybe_parent_head_and_hash) = match ( + let (maybe_pvd, maybe_parent_head, maybe_parent_head_hash) = match ( collation_event.collator_protocol_version, collation_event.pending_collation.prospective_candidate, ) { @@ -1845,7 +1855,7 @@ async fn kick_off_seconding( ) .await?; - (pvd, maybe_parent_head_data.map(|head_data| (head_data, parent_head_data_hash))) + (pvd, maybe_parent_head_data, Some(parent_head_data_hash)) }, // Support V2 collators without async backing enabled. (CollationVersion::V2, Some(_)) | (CollationVersion::V1, _) => { @@ -1855,20 +1865,60 @@ async fn kick_off_seconding( candidate_receipt.descriptor().para_id, ) .await?; - (pvd, None) + ( + Some(pvd.ok_or(SecondingError::PersistedValidationDataNotFound)?), + maybe_parent_head_data, + None, + ) }, _ => { // `handle_advertisement` checks for protocol mismatch. - return Ok(()) + return Ok(false) + }, + }; + + let pvd = match (maybe_pvd, maybe_parent_head.clone(), maybe_parent_head_hash) { + (Some(pvd), _, _) => pvd, + (None, None, Some(parent_head_data_hash)) => { + // In this case, the collator did not supply the head data and neither could + // prospective-parachains. We add this to the blocked_from_seconding collection + // until we second its parent. + let blocked_collation = PendingCollationFetch { + collation_event, + candidate_receipt, + pov, + maybe_parent_head_data: None, + }; + gum::debug!( + target: LOG_TARGET, + candidate_hash = ?blocked_collation.candidate_receipt.hash(), + relay_parent = ?blocked_collation.candidate_receipt.descriptor.relay_parent, + "Collation having parent head data hash {} is blocked from seconding. Waiting on its parent to be validated.", + parent_head_data_hash + ); + state + .blocked_from_seconding + .entry(BlockedCollationId { + para_id: blocked_collation.candidate_receipt.descriptor.para_id, + parent_head_data_hash, + }) + .or_insert_with(Vec::new) + .push(blocked_collation); + + return Ok(false) + }, + (None, _, _) => { + // Even though we already have the parent head data, the pvd fetching failed. We + // don't need to wait for seconding another collation outputting this head data. + return Err(SecondingError::PersistedValidationDataNotFound) }, }; - let pvd = maybe_pvd.ok_or(SecondingError::PersistedValidationDataNotFound)?; fetched_collation_sanity_check( &collation_event.pending_collation, &candidate_receipt, &pvd, - maybe_parent_head_and_hash, + maybe_parent_head.and_then(|head| maybe_parent_head_hash.map(|hash| (head, hash))), )?; ctx.send_message(CandidateBackingMessage::Second( @@ -1883,7 +1933,7 @@ async fn kick_off_seconding( collations.status = CollationStatus::WaitingOnValidation; entry.insert(collation_event); - Ok(()) + Ok(true) } else { Err(SecondingError::Duplicate) } diff --git a/polkadot/node/network/collator-protocol/src/validator_side/tests/prospective_parachains.rs b/polkadot/node/network/collator-protocol/src/validator_side/tests/prospective_parachains.rs index eaa725f2642ed38e3a6f222f9624dd6e2bc4fcce..785690121dadd1858a4985459b515739842a1421 100644 --- a/polkadot/node/network/collator-protocol/src/validator_side/tests/prospective_parachains.rs +++ b/polkadot/node/network/collator-protocol/src/validator_side/tests/prospective_parachains.rs @@ -23,6 +23,7 @@ use polkadot_primitives::{ AsyncBackingParams, BlockNumber, CandidateCommitments, CommittedCandidateReceipt, Header, SigningContext, ValidatorId, }; +use rstest::rstest; const ASYNC_BACKING_PARAMETERS: AsyncBackingParams = AsyncBackingParams { max_candidate_depth: 4, allowed_ancestry_len: 3 }; @@ -262,6 +263,48 @@ async fn assert_collation_seconded( } } +/// Assert that the next message is a persisted validation data request and respond with the +/// supplied PVD. +async fn assert_persisted_validation_data( + virtual_overseer: &mut VirtualOverseer, + version: CollationVersion, + expected_relay_parent: Hash, + expected_para_id: ParaId, + expected_parent_head_data_hash: Option, + pvd: Option, +) { + // Depending on relay parent mode pvd will be either requested + // from the Runtime API or Prospective Parachains. + let msg = overseer_recv(virtual_overseer).await; + match version { + CollationVersion::V1 => assert_matches!( + msg, + AllMessages::RuntimeApi(RuntimeApiMessage::Request( + hash, + RuntimeApiRequest::PersistedValidationData(para_id, assumption, tx), + )) => { + assert_eq!(expected_relay_parent, hash); + assert_eq!(expected_para_id, para_id); + assert_eq!(OccupiedCoreAssumption::Free, assumption); + tx.send(Ok(pvd)).unwrap(); + } + ), + CollationVersion::V2 => assert_matches!( + msg, + AllMessages::ProspectiveParachains( + ProspectiveParachainsMessage::GetProspectiveValidationData(request, tx), + ) => { + assert_eq!(expected_relay_parent, request.candidate_relay_parent); + assert_eq!(expected_para_id, request.para_id); + if let Some(expected_parent_head_data_hash) = expected_parent_head_data_hash { + assert_eq!(expected_parent_head_data_hash, request.parent_head_data.hash()); + } + tx.send(pvd).unwrap(); + } + ), + } +} + #[test] fn v1_advertisement_accepted_and_seconded() { let test_state = TestState::default(); @@ -946,56 +989,73 @@ fn advertisement_spam_protection() { }); } -#[test] -fn backed_candidate_unblocks_advertisements() { +#[rstest] +#[case(true)] +#[case(false)] +fn child_blocked_from_seconding_by_parent(#[case] valid_parent: bool) { let test_state = TestState::default(); test_harness(ReputationAggregator::new(|_| true), |test_harness| async move { - let TestHarness { mut virtual_overseer, .. } = test_harness; + let TestHarness { mut virtual_overseer, keystore } = test_harness; - let pair_a = CollatorPair::generate().0; - let pair_b = CollatorPair::generate().0; + let pair = CollatorPair::generate().0; + // Grandparent of head `a`. let head_b = Hash::from_low_u64_be(128); let head_b_num: u32 = 2; - let head_c = get_parent_hash(head_b); // Grandparent of head `b`. - // Group rotation frequency is 1 by default, at `d` we're assigned + // Group rotation frequency is 1 by default, at `c` we're assigned // to the first para. - let head_d = get_parent_hash(head_c); + let head_c = Hash::from_low_u64_be(130); // Activated leaf is `b`, but the collation will be based on `c`. update_view(&mut virtual_overseer, &test_state, vec![(head_b, head_b_num)], 1).await; let peer_a = PeerId::random(); - let peer_b = PeerId::random(); - // Accept both collators from the implicit view. connect_and_declare_collator( &mut virtual_overseer, peer_a, - pair_a.clone(), + pair.clone(), test_state.chain_ids[0], CollationVersion::V2, ) .await; - connect_and_declare_collator( - &mut virtual_overseer, - peer_b, - pair_b.clone(), - test_state.chain_ids[1], - CollationVersion::V2, - ) - .await; - let candidate_hash = CandidateHash::default(); - let parent_head_data_hash = Hash::zero(); + // Candidate A transitions from head data 0 to 1. + // Candidate B transitions from head data 1 to 2. + + // Candidate B is advertised and fetched before candidate A. + + let mut candidate_b = dummy_candidate_receipt_bad_sig(head_c, Some(Default::default())); + candidate_b.descriptor.para_id = test_state.chain_ids[0]; + candidate_b.descriptor.para_head = HeadData(vec![2]).hash(); + candidate_b.descriptor.persisted_validation_data_hash = + PersistedValidationData:: { + parent_head: HeadData(vec![1]), + relay_parent_number: 5, + max_pov_size: 1024, + relay_parent_storage_root: Default::default(), + } + .hash(); + let candidate_b_commitments = CandidateCommitments { + head_data: HeadData(vec![2]), + horizontal_messages: Default::default(), + upward_messages: Default::default(), + new_validation_code: None, + processed_downward_messages: 0, + hrmp_watermark: 0, + }; + candidate_b.commitments_hash = candidate_b_commitments.hash(); + + let candidate_b_hash = candidate_b.hash(); + advertise_collation( &mut virtual_overseer, - peer_b, + peer_a, head_c, - Some((candidate_hash, parent_head_data_hash)), + Some((candidate_b_hash, HeadData(vec![1]).hash())), ) .await; assert_matches!( @@ -1003,40 +1063,73 @@ fn backed_candidate_unblocks_advertisements() { AllMessages::CandidateBacking( CandidateBackingMessage::CanSecond(request, tx), ) => { - assert_eq!(request.candidate_hash, candidate_hash); - assert_eq!(request.candidate_para_id, test_state.chain_ids[1]); - assert_eq!(request.parent_head_data_hash, parent_head_data_hash); - // Reject it. - tx.send(false).expect("receiving side should be alive"); + assert_eq!(request.candidate_hash, candidate_b_hash); + assert_eq!(request.candidate_para_id, test_state.chain_ids[0]); + assert_eq!(request.parent_head_data_hash, HeadData(vec![1]).hash()); + tx.send(true).expect("receiving side should be alive"); } ); - // Advertise with different para. - advertise_collation( + let response_channel = assert_fetch_collation_request( &mut virtual_overseer, - peer_a, - head_d, // Note different relay parent. - Some((candidate_hash, parent_head_data_hash)), + head_c, + test_state.chain_ids[0], + Some(candidate_b_hash), ) .await; - assert_matches!( - overseer_recv(&mut virtual_overseer).await, - AllMessages::CandidateBacking( - CandidateBackingMessage::CanSecond(request, tx), - ) => { - assert_eq!(request.candidate_hash, candidate_hash); - assert_eq!(request.candidate_para_id, test_state.chain_ids[0]); - assert_eq!(request.parent_head_data_hash, parent_head_data_hash); - tx.send(false).expect("receiving side should be alive"); + + response_channel + .send(Ok(( + request_v2::CollationFetchingResponse::Collation( + candidate_b.clone(), + PoV { block_data: BlockData(vec![1]) }, + ) + .encode(), + ProtocolName::from(""), + ))) + .expect("Sending response should succeed"); + + // Persisted validation data of candidate B is not found. + assert_persisted_validation_data( + &mut virtual_overseer, + CollationVersion::V2, + head_c, + test_state.chain_ids[0], + Some(HeadData(vec![1]).hash()), + None, + ) + .await; + + // Now advertise, fetch and validate candidate A, which is the parent of B. + + let mut candidate_a = dummy_candidate_receipt_bad_sig(head_c, Some(Default::default())); + candidate_a.descriptor.para_id = test_state.chain_ids[0]; + candidate_a.descriptor.para_head = HeadData(vec![1]).hash(); + candidate_a.descriptor.persisted_validation_data_hash = + PersistedValidationData:: { + parent_head: HeadData(vec![0]), + relay_parent_number: 5, + max_pov_size: 1024, + relay_parent_storage_root: Default::default(), } - ); + .hash(); + let candidate_a_commitments = CandidateCommitments { + head_data: HeadData(vec![1]), + horizontal_messages: Default::default(), + upward_messages: Default::default(), + new_validation_code: None, + processed_downward_messages: 0, + hrmp_watermark: 0, + }; + candidate_a.commitments_hash = candidate_a_commitments.hash(); + + let candidate_a_hash = candidate_a.hash(); - overseer_send( + advertise_collation( &mut virtual_overseer, - CollatorProtocolMessage::Backed { - para_id: test_state.chain_ids[0], - para_head: parent_head_data_hash, - }, + peer_a, + head_c, + Some((candidate_a_hash, HeadData(vec![0]).hash())), ) .await; assert_matches!( @@ -1044,174 +1137,155 @@ fn backed_candidate_unblocks_advertisements() { AllMessages::CandidateBacking( CandidateBackingMessage::CanSecond(request, tx), ) => { - assert_eq!(request.candidate_hash, candidate_hash); + assert_eq!(request.candidate_hash, candidate_a_hash); assert_eq!(request.candidate_para_id, test_state.chain_ids[0]); - assert_eq!(request.parent_head_data_hash, parent_head_data_hash); + assert_eq!(request.parent_head_data_hash, HeadData(vec![0]).hash()); tx.send(true).expect("receiving side should be alive"); } ); - assert_fetch_collation_request( + + let response_channel = assert_fetch_collation_request( &mut virtual_overseer, - head_d, + head_c, test_state.chain_ids[0], - Some(candidate_hash), + Some(candidate_a_hash), ) .await; - virtual_overseer - }); -} -#[test] -fn active_leave_unblocks_advertisements() { - let mut test_state = TestState::default(); - test_state.group_rotation_info.group_rotation_frequency = 100; + response_channel + .send(Ok(( + request_v2::CollationFetchingResponse::Collation( + candidate_a.clone(), + PoV { block_data: BlockData(vec![2]) }, + ) + .encode(), + ProtocolName::from(""), + ))) + .expect("Sending response should succeed"); - test_harness(ReputationAggregator::new(|_| true), |test_harness| async move { - let TestHarness { mut virtual_overseer, .. } = test_harness; + assert_persisted_validation_data( + &mut virtual_overseer, + CollationVersion::V2, + head_c, + test_state.chain_ids[0], + Some(HeadData(vec![0]).hash()), + Some(PersistedValidationData:: { + parent_head: HeadData(vec![0]), + relay_parent_number: 5, + max_pov_size: 1024, + relay_parent_storage_root: Default::default(), + }), + ) + .await; - let head_b = Hash::from_low_u64_be(128); - let head_b_num: u32 = 0; + assert_matches!( + overseer_recv(&mut virtual_overseer).await, + AllMessages::CandidateBacking(CandidateBackingMessage::Second( + relay_parent, + candidate_receipt, + received_pvd, + incoming_pov, + )) => { + assert_eq!(head_c, relay_parent); + assert_eq!(test_state.chain_ids[0], candidate_receipt.descriptor.para_id); + assert_eq!(PoV { block_data: BlockData(vec![2]) }, incoming_pov); + assert_eq!(PersistedValidationData:: { + parent_head: HeadData(vec![0]), + relay_parent_number: 5, + max_pov_size: 1024, + relay_parent_storage_root: Default::default(), + }, received_pvd); + candidate_receipt + } + ); - update_view(&mut virtual_overseer, &test_state, vec![(head_b, head_b_num)], 1).await; + // If candidate A is valid, proceed with seconding B. + if valid_parent { + send_seconded_statement( + &mut virtual_overseer, + keystore.clone(), + &CommittedCandidateReceipt { + descriptor: candidate_a.descriptor, + commitments: candidate_a_commitments, + }, + ) + .await; - let peers: Vec = (0..3).map(|_| CollatorPair::generate().0).collect(); - let peer_ids: Vec = (0..3).map(|_| PeerId::random()).collect(); - let candidates: Vec = - (0u8..3).map(|i| CandidateHash(Hash::repeat_byte(i))).collect(); + assert_collation_seconded(&mut virtual_overseer, head_c, peer_a, CollationVersion::V2) + .await; - for (peer, peer_id) in peers.iter().zip(&peer_ids) { - connect_and_declare_collator( + // Now that candidate A has been seconded, candidate B can be seconded as well. + + assert_persisted_validation_data( &mut virtual_overseer, - *peer_id, - peer.clone(), - test_state.chain_ids[0], CollationVersion::V2, + head_c, + test_state.chain_ids[0], + Some(HeadData(vec![1]).hash()), + Some(PersistedValidationData:: { + parent_head: HeadData(vec![1]), + relay_parent_number: 5, + max_pov_size: 1024, + relay_parent_storage_root: Default::default(), + }), ) .await; - } - let parent_head_data_hash = Hash::zero(); - for (peer, candidate) in peer_ids.iter().zip(&candidates).take(2) { - advertise_collation( + assert_matches!( + overseer_recv(&mut virtual_overseer).await, + AllMessages::CandidateBacking(CandidateBackingMessage::Second( + relay_parent, + candidate_receipt, + received_pvd, + incoming_pov, + )) => { + assert_eq!(head_c, relay_parent); + assert_eq!(test_state.chain_ids[0], candidate_receipt.descriptor.para_id); + assert_eq!(PoV { block_data: BlockData(vec![1]) }, incoming_pov); + assert_eq!(PersistedValidationData:: { + parent_head: HeadData(vec![1]), + relay_parent_number: 5, + max_pov_size: 1024, + relay_parent_storage_root: Default::default(), + }, received_pvd); + candidate_receipt + } + ); + + send_seconded_statement( &mut virtual_overseer, - *peer, - head_b, - Some((*candidate, parent_head_data_hash)), + keystore.clone(), + &CommittedCandidateReceipt { + descriptor: candidate_b.descriptor, + commitments: candidate_b_commitments, + }, + ) + .await; + + assert_collation_seconded(&mut virtual_overseer, head_c, peer_a, CollationVersion::V2) + .await; + } else { + // If candidate A is invalid, B won't be seconded. + overseer_send( + &mut virtual_overseer, + CollatorProtocolMessage::Invalid(head_c, candidate_a), ) .await; assert_matches!( overseer_recv(&mut virtual_overseer).await, - AllMessages::CandidateBacking( - CandidateBackingMessage::CanSecond(request, tx), + AllMessages::NetworkBridgeTx( + NetworkBridgeTxMessage::ReportPeer(ReportPeerMessage::Single(peer, rep)), ) => { - assert_eq!(request.candidate_hash, *candidate); - assert_eq!(request.candidate_para_id, test_state.chain_ids[0]); - assert_eq!(request.parent_head_data_hash, parent_head_data_hash); - // Send false. - tx.send(false).expect("receiving side should be alive"); + assert_eq!(peer, peer_a); + assert_eq!(rep.value, COST_REPORT_BAD.cost_or_benefit()); } ); } - let head_c = Hash::from_low_u64_be(127); - let head_c_num: u32 = 1; - - let next_overseer_message = - update_view(&mut virtual_overseer, &test_state, vec![(head_c, head_c_num)], 1) - .await - .expect("should've sent request to backing"); - - // Unblock first request. - assert_matches!( - next_overseer_message, - AllMessages::CandidateBacking( - CandidateBackingMessage::CanSecond(request, tx), - ) => { - assert_eq!(request.candidate_hash, candidates[0]); - assert_eq!(request.candidate_para_id, test_state.chain_ids[0]); - assert_eq!(request.parent_head_data_hash, parent_head_data_hash); - tx.send(true).expect("receiving side should be alive"); - } - ); - - assert_fetch_collation_request( - &mut virtual_overseer, - head_b, - test_state.chain_ids[0], - Some(candidates[0]), - ) - .await; - - assert_matches!( - overseer_recv(&mut virtual_overseer).await, - AllMessages::CandidateBacking( - CandidateBackingMessage::CanSecond(request, tx), - ) => { - assert_eq!(request.candidate_hash, candidates[1]); - assert_eq!(request.candidate_para_id, test_state.chain_ids[0]); - assert_eq!(request.parent_head_data_hash, parent_head_data_hash); - tx.send(false).expect("receiving side should be alive"); - } - ); - - // Collation request was discarded. test_helpers::Yield::new().await; assert_matches!(virtual_overseer.recv().now_or_never(), None); - advertise_collation( - &mut virtual_overseer, - peer_ids[2], - head_c, - Some((candidates[2], parent_head_data_hash)), - ) - .await; - - assert_matches!( - overseer_recv(&mut virtual_overseer).await, - AllMessages::CandidateBacking( - CandidateBackingMessage::CanSecond(request, tx), - ) => { - assert_eq!(request.candidate_hash, candidates[2]); - tx.send(false).expect("receiving side should be alive"); - } - ); - - let head_d = Hash::from_low_u64_be(126); - let head_d_num: u32 = 2; - - let next_overseer_message = - update_view(&mut virtual_overseer, &test_state, vec![(head_d, head_d_num)], 1) - .await - .expect("should've sent request to backing"); - - // Reject 2, accept 3. - assert_matches!( - next_overseer_message, - AllMessages::CandidateBacking( - CandidateBackingMessage::CanSecond(request, tx), - ) => { - assert_eq!(request.candidate_hash, candidates[1]); - tx.send(false).expect("receiving side should be alive"); - } - ); - assert_matches!( - overseer_recv(&mut virtual_overseer).await, - AllMessages::CandidateBacking( - CandidateBackingMessage::CanSecond(request, tx), - ) => { - assert_eq!(request.candidate_hash, candidates[2]); - tx.send(true).expect("receiving side should be alive"); - } - ); - assert_fetch_collation_request( - &mut virtual_overseer, - head_c, - test_state.chain_ids[0], - Some(candidates[2]), - ) - .await; - virtual_overseer }); } diff --git a/polkadot/node/network/dispute-distribution/Cargo.toml b/polkadot/node/network/dispute-distribution/Cargo.toml index ff9c302c73146d501114728c4a483e4465d199a9..dff285590d97cd4f47a00a6141b5c8a07315e35e 100644 --- a/polkadot/node/network/dispute-distribution/Cargo.toml +++ b/polkadot/node/network/dispute-distribution/Cargo.toml @@ -14,7 +14,7 @@ futures = "0.3.30" futures-timer = "3.0.2" gum = { package = "tracing-gum", path = "../../gum" } derive_more = "0.99.17" -parity-scale-codec = { version = "3.6.1", features = ["std"] } +parity-scale-codec = { version = "3.6.12", features = ["std"] } polkadot-primitives = { path = "../../../primitives" } polkadot-erasure-coding = { path = "../../../erasure-coding" } polkadot-node-subsystem = { path = "../../subsystem" } @@ -25,7 +25,7 @@ sc-network = { path = "../../../../substrate/client/network" } sp-application-crypto = { path = "../../../../substrate/primitives/application-crypto" } sp-keystore = { path = "../../../../substrate/primitives/keystore" } thiserror = { workspace = true } -fatality = "0.0.6" +fatality = "0.1.1" schnellru = "0.2.1" indexmap = "2.0.0" diff --git a/polkadot/node/network/dispute-distribution/src/sender/send_task.rs b/polkadot/node/network/dispute-distribution/src/sender/send_task.rs index 18c66066d162ec16880b9391aa2e59e1f6b0ea1a..54ccd10789d0aec283748286bc4f69b6a9ae379a 100644 --- a/polkadot/node/network/dispute-distribution/src/sender/send_task.rs +++ b/polkadot/node/network/dispute-distribution/src/sender/send_task.rs @@ -16,7 +16,7 @@ use std::collections::{HashMap, HashSet}; -use futures::{future::RemoteHandle, Future, FutureExt}; +use futures::{Future, FutureExt}; use polkadot_node_network_protocol::{ request_response::{ @@ -64,7 +64,7 @@ pub struct SendTask { /// Status of a particular vote/statement delivery to a particular validator. enum DeliveryStatus { /// Request is still in flight. - Pending(RemoteHandle<()>), + Pending, /// Succeeded - no need to send request to this peer anymore. Succeeded, } @@ -297,9 +297,8 @@ async fn send_requests( metrics.time_dispute_request(), ); - let (remote, remote_handle) = fut.remote_handle(); - ctx.spawn("dispute-sender", remote.boxed()).map_err(FatalError::SpawnTask)?; - statuses.insert(receiver, DeliveryStatus::Pending(remote_handle)); + ctx.spawn("dispute-sender", fut.boxed()).map_err(FatalError::SpawnTask)?; + statuses.insert(receiver, DeliveryStatus::Pending); } let msg = NetworkBridgeTxMessage::SendRequests(reqs, IfDisconnected::ImmediateError); diff --git a/polkadot/node/network/protocol/Cargo.toml b/polkadot/node/network/protocol/Cargo.toml index 0408e673791114793da1b231baa7448f185b0db6..c5015b8c64504b2712c9713463ab78af2f265948 100644 --- a/polkadot/node/network/protocol/Cargo.toml +++ b/polkadot/node/network/protocol/Cargo.toml @@ -16,7 +16,7 @@ hex = "0.4.3" polkadot-primitives = { path = "../../../primitives" } polkadot-node-primitives = { path = "../../primitives" } polkadot-node-jaeger = { path = "../../jaeger" } -parity-scale-codec = { version = "3.6.1", default-features = false, features = ["derive"] } +parity-scale-codec = { version = "3.6.12", default-features = false, features = ["derive"] } sc-network = { path = "../../../../substrate/client/network" } sc-network-types = { path = "../../../../substrate/client/network/types" } sc-authority-discovery = { path = "../../../../substrate/client/authority-discovery" } @@ -24,7 +24,7 @@ sp-runtime = { path = "../../../../substrate/primitives/runtime" } strum = { version = "0.26.2", features = ["derive"] } futures = "0.3.30" thiserror = { workspace = true } -fatality = "0.0.6" +fatality = "0.1.1" rand = "0.8" derive_more = "0.99" gum = { package = "tracing-gum", path = "../../gum" } diff --git a/polkadot/node/network/statement-distribution/Cargo.toml b/polkadot/node/network/statement-distribution/Cargo.toml index d8ae031cbf36dabf2899e61574958ffdbde62921..1fe761bd0e3bb4e52d505aae234c750e28ffd1e6 100644 --- a/polkadot/node/network/statement-distribution/Cargo.toml +++ b/polkadot/node/network/statement-distribution/Cargo.toml @@ -22,9 +22,9 @@ polkadot-node-subsystem-util = { path = "../../subsystem-util" } 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"] } +parity-scale-codec = { version = "3.6.12", default-features = false, features = ["derive"] } thiserror = { workspace = true } -fatality = "0.0.6" +fatality = "0.1.1" bitvec = "1" [dev-dependencies] diff --git a/polkadot/node/network/statement-distribution/src/legacy_v1/tests.rs b/polkadot/node/network/statement-distribution/src/legacy_v1/tests.rs index 0dea5ad0996e787553bfb597d455460208cc5e21..d4c5f95034ae8061b81f8019c86fcd44b0530cf5 100644 --- a/polkadot/node/network/statement-distribution/src/legacy_v1/tests.rs +++ b/polkadot/node/network/statement-distribution/src/legacy_v1/tests.rs @@ -55,7 +55,7 @@ use sp_application_crypto::{sr25519::Pair, AppCrypto, Pair as TraitPair}; use sp_authority_discovery::AuthorityPair; use sp_keyring::Sr25519Keyring; use sp_keystore::{Keystore, KeystorePtr}; -use std::{iter::FromIterator as _, sync::Arc, time::Duration}; +use std::{sync::Arc, time::Duration}; use util::reputation::add_reputation; // Some deterministic genesis hash for protocol names diff --git a/polkadot/node/network/statement-distribution/src/lib.rs b/polkadot/node/network/statement-distribution/src/lib.rs index 7e91d2849120283c3fcefc4193a6e3d8bff809a1..4ca199c3378bfc80eeee9c5f2985b1ad570e5736 100644 --- a/polkadot/node/network/statement-distribution/src/lib.rs +++ b/polkadot/node/network/statement-distribution/src/lib.rs @@ -207,6 +207,7 @@ impl StatementDistributionSubsystem { v2::respond_task( self.req_receiver.take().expect("Mandatory argument to new. qed"), res_sender.clone(), + self.metrics.clone(), ) .boxed(), ) diff --git a/polkadot/node/network/statement-distribution/src/metrics.rs b/polkadot/node/network/statement-distribution/src/metrics.rs index b9a51dc89d61afd9d2805f294b208f92572dd754..1bc994174263905d3058154ead29eaaa16bd2ad4 100644 --- a/polkadot/node/network/statement-distribution/src/metrics.rs +++ b/polkadot/node/network/statement-distribution/src/metrics.rs @@ -24,14 +24,19 @@ const HISTOGRAM_LATENCY_BUCKETS: &[f64] = &[ #[derive(Clone)] struct MetricsInner { + // V1 statements_distributed: prometheus::Counter, sent_requests: prometheus::Counter, received_responses: prometheus::CounterVec, - active_leaves_update: prometheus::Histogram, - share: prometheus::Histogram, network_bridge_update: prometheus::HistogramVec, statements_unexpected: prometheus::CounterVec, created_message_size: prometheus::Gauge, + // V1+ + active_leaves_update: prometheus::Histogram, + share: prometheus::Histogram, + // V2+ + peer_rate_limit_request_drop: prometheus::Counter, + max_parallel_requests_reached: prometheus::Counter, } /// Statement Distribution metrics. @@ -114,6 +119,23 @@ impl Metrics { metrics.created_message_size.set(size as u64); } } + + /// Update sent dropped requests counter when request dropped because + /// of peer rate limit + pub fn on_request_dropped_peer_rate_limit(&self) { + if let Some(metrics) = &self.0 { + metrics.peer_rate_limit_request_drop.inc(); + } + } + + /// Update max parallel requests reached counter + /// This counter is updated when the maximum number of parallel requests is reached + /// and we are waiting for one of the requests to finish + pub fn on_max_parallel_requests_reached(&self) { + if let Some(metrics) = &self.0 { + metrics.max_parallel_requests_reached.inc(); + } + } } impl metrics::Metrics for Metrics { @@ -193,6 +215,20 @@ impl metrics::Metrics for Metrics { ))?, registry, )?, + peer_rate_limit_request_drop: prometheus::register( + prometheus::Counter::new( + "polkadot_parachain_statement_distribution_peer_rate_limit_request_drop_total", + "Number of statement distribution requests dropped because of the peer rate limiting.", + )?, + registry, + )?, + max_parallel_requests_reached: prometheus::register( + prometheus::Counter::new( + "polkadot_parachain_statement_distribution_max_parallel_requests_reached_total", + "Number of times the maximum number of parallel requests was reached.", + )?, + registry, + )?, }; Ok(Metrics(Some(metrics))) } diff --git a/polkadot/node/network/statement-distribution/src/v2/candidates.rs b/polkadot/node/network/statement-distribution/src/v2/candidates.rs index ad56ad4a2365b94e6ced0e43ce0747d99fb6a80d..a4f2455c28401f536d449268591e2f9746a9db81 100644 --- a/polkadot/node/network/statement-distribution/src/v2/candidates.rs +++ b/polkadot/node/network/statement-distribution/src/v2/candidates.rs @@ -243,12 +243,12 @@ impl Candidates { /// Whether statements from a candidate are importable. /// /// This is only true when the candidate is known, confirmed, - /// and is importable in a fragment tree. + /// and is importable in a fragment chain. pub fn is_importable(&self, candidate_hash: &CandidateHash) -> bool { self.get_confirmed(candidate_hash).map_or(false, |c| c.is_importable(None)) } - /// Note that a candidate is importable in a fragment tree indicated by the given + /// Note that a candidate is importable in a fragment chain indicated by the given /// leaf hash. pub fn note_importable_under(&mut self, candidate: &HypotheticalCandidate, leaf_hash: Hash) { match candidate { diff --git a/polkadot/node/network/statement-distribution/src/v2/grid.rs b/polkadot/node/network/statement-distribution/src/v2/grid.rs index 24d846c840e00c49446a0525b3768353f56ae524..b6e4163090c4d5fe00a22c61b50d99b74e69c8bd 100644 --- a/polkadot/node/network/statement-distribution/src/v2/grid.rs +++ b/polkadot/node/network/statement-distribution/src/v2/grid.rs @@ -46,10 +46,8 @@ //! - Request/response for the candidate + votes. //! - Ignore if they are inconsistent with the manifest. //! - A malicious backing group is capable of producing an unbounded number of backed candidates. -//! - We request the candidate only if the candidate has a hypothetical depth in any of our -//! fragment trees, and: -//! - the seconding validators have not seconded any other candidates at that depth in any of -//! those fragment trees +//! - We request the candidate only if the candidate is a hypothetical member in any of our +//! fragment chains, and: //! - All members of the group attempt to circulate all statements (in compact form) from the rest //! of the group on candidates that have already been backed. //! - They do this via the grid topology. diff --git a/polkadot/node/network/statement-distribution/src/v2/mod.rs b/polkadot/node/network/statement-distribution/src/v2/mod.rs index 68caa5f0e70099d1cdb192cde4307edaa56660f0..961ec45bdada037885fb5ea43858e4e1522fac2c 100644 --- a/polkadot/node/network/statement-distribution/src/v2/mod.rs +++ b/polkadot/node/network/statement-distribution/src/v2/mod.rs @@ -37,7 +37,7 @@ use polkadot_node_primitives::{ use polkadot_node_subsystem::{ messages::{ network_bridge_event::NewGossipTopology, CandidateBackingMessage, HypotheticalCandidate, - HypotheticalFrontierRequest, NetworkBridgeEvent, NetworkBridgeTxMessage, + HypotheticalMembershipRequest, NetworkBridgeEvent, NetworkBridgeTxMessage, ProspectiveParachainsMessage, }, overseer, ActivatedLeaf, @@ -59,6 +59,8 @@ use sp_keystore::KeystorePtr; use fatality::Nested; use futures::{ channel::{mpsc, oneshot}, + future::FutureExt, + select, stream::FuturesUnordered, SinkExt, StreamExt, }; @@ -73,6 +75,7 @@ use std::{ use crate::{ error::{JfyiError, JfyiErrorResult}, + metrics::Metrics, LOG_TARGET, }; use candidates::{BadAdvertisement, Candidates, PostConfirmation}; @@ -750,7 +753,7 @@ pub(crate) async fn handle_active_leaves_update( } } - new_leaf_fragment_tree_updates(ctx, state, activated.hash).await; + new_leaf_fragment_chain_updates(ctx, state, activated.hash).await; Ok(()) } @@ -826,7 +829,16 @@ pub(crate) fn handle_deactivate_leaves(state: &mut State, leaves: &[Hash]) { // clean up sessions based on everything remaining. let sessions: HashSet<_> = state.per_relay_parent.values().map(|r| r.session).collect(); state.per_session.retain(|s, _| sessions.contains(s)); - state.unused_topologies.retain(|s, _| sessions.contains(s)); + + let last_session_index = state.unused_topologies.keys().max().copied(); + // Do not clean-up the last saved toplogy unless we moved to the next session + // This is needed because handle_deactive_leaves, gets also called when + // prospective_parachains APIs are not present, so we would actually remove + // the topology without using it because `per_relay_parent` is empty until + // prospective_parachains gets enabled + state + .unused_topologies + .retain(|s, _| sessions.contains(s) || last_session_index == Some(*s)); } #[overseer::contextbounds(StatementDistribution, prefix=self::overseer)] @@ -2204,7 +2216,7 @@ async fn determine_groups_per_para( } #[overseer::contextbounds(StatementDistribution, prefix=self::overseer)] -async fn fragment_tree_update_inner( +async fn fragment_chain_update_inner( ctx: &mut Context, state: &mut State, active_leaf_hash: Option, @@ -2218,31 +2230,34 @@ async fn fragment_tree_update_inner( }; // 2. find out which are in the frontier - let frontier = { + gum::debug!( + target: LOG_TARGET, + "Calling getHypotheticalMembership from statement distribution" + ); + let candidate_memberships = { let (tx, rx) = oneshot::channel(); - ctx.send_message(ProspectiveParachainsMessage::GetHypotheticalFrontier( - HypotheticalFrontierRequest { + ctx.send_message(ProspectiveParachainsMessage::GetHypotheticalMembership( + HypotheticalMembershipRequest { candidates: hypotheticals, - fragment_tree_relay_parent: active_leaf_hash, - backed_in_path_only: false, + fragment_chain_relay_parent: active_leaf_hash, }, tx, )) .await; match rx.await { - Ok(frontier) => frontier, + Ok(candidate_memberships) => candidate_memberships, Err(oneshot::Canceled) => return, } }; // 3. note that they are importable under a given leaf hash. - for (hypo, membership) in frontier { - // skip parablocks outside of the frontier + for (hypo, membership) in candidate_memberships { + // skip parablocks which aren't potential candidates if membership.is_empty() { continue } - for (leaf_hash, _) in membership { + for leaf_hash in membership { state.candidates.note_importable_under(&hypo, leaf_hash); } @@ -2286,31 +2301,31 @@ async fn fragment_tree_update_inner( } #[overseer::contextbounds(StatementDistribution, prefix=self::overseer)] -async fn new_leaf_fragment_tree_updates( +async fn new_leaf_fragment_chain_updates( ctx: &mut Context, state: &mut State, leaf_hash: Hash, ) { - fragment_tree_update_inner(ctx, state, Some(leaf_hash), None, None).await + fragment_chain_update_inner(ctx, state, Some(leaf_hash), None, None).await } #[overseer::contextbounds(StatementDistribution, prefix=self::overseer)] -async fn prospective_backed_notification_fragment_tree_updates( +async fn prospective_backed_notification_fragment_chain_updates( ctx: &mut Context, state: &mut State, para_id: ParaId, para_head: Hash, ) { - fragment_tree_update_inner(ctx, state, None, Some((para_head, para_id)), None).await + fragment_chain_update_inner(ctx, state, None, Some((para_head, para_id)), None).await } #[overseer::contextbounds(StatementDistribution, prefix=self::overseer)] -async fn new_confirmed_candidate_fragment_tree_updates( +async fn new_confirmed_candidate_fragment_chain_updates( ctx: &mut Context, state: &mut State, candidate: HypotheticalCandidate, ) { - fragment_tree_update_inner(ctx, state, None, None, Some(vec![candidate])).await + fragment_chain_update_inner(ctx, state, None, None, Some(vec![candidate])).await } struct ManifestImportSuccess<'a> { @@ -2853,7 +2868,7 @@ pub(crate) async fn handle_backed_candidate_message( .await; // Search for children of the backed candidate to request. - prospective_backed_notification_fragment_tree_updates( + prospective_backed_notification_fragment_chain_updates( ctx, state, confirmed.para_id(), @@ -2944,7 +2959,8 @@ async fn apply_post_confirmation( post_confirmation.hypothetical.relay_parent(), ) .await; - new_confirmed_candidate_fragment_tree_updates(ctx, state, post_confirmation.hypothetical).await; + new_confirmed_candidate_fragment_chain_updates(ctx, state, post_confirmation.hypothetical) + .await; } /// Dispatch pending requests for candidate data & statements. @@ -3173,8 +3189,8 @@ pub(crate) async fn handle_response( let confirmed = state.candidates.get_confirmed(&candidate_hash).expect("just confirmed; qed"); - // Although the candidate is confirmed, it isn't yet on the - // hypothetical frontier of the fragment tree. Later, when it is, + // Although the candidate is confirmed, it isn't yet a + // hypothetical member of the fragment chain. Later, when it is, // we will import statements. if !confirmed.is_importable(None) { return @@ -3414,35 +3430,61 @@ pub(crate) struct ResponderMessage { pub(crate) async fn respond_task( mut receiver: IncomingRequestReceiver, mut sender: mpsc::Sender, + metrics: Metrics, ) { let mut pending_out = FuturesUnordered::new(); + let mut active_peers = HashSet::new(); + loop { - // Ensure we are not handling too many requests in parallel. - if pending_out.len() >= MAX_PARALLEL_ATTESTED_CANDIDATE_REQUESTS as usize { - // Wait for one to finish: - pending_out.next().await; - } + select! { + // New request + request_result = receiver.recv(|| vec![COST_INVALID_REQUEST]).fuse() => { + let request = match request_result.into_nested() { + Ok(Ok(v)) => v, + Err(fatal) => { + gum::debug!(target: LOG_TARGET, error = ?fatal, "Shutting down request responder"); + return + }, + Ok(Err(jfyi)) => { + gum::debug!(target: LOG_TARGET, error = ?jfyi, "Decoding request failed"); + continue + }, + }; - let req = match receiver.recv(|| vec![COST_INVALID_REQUEST]).await.into_nested() { - Ok(Ok(v)) => v, - Err(fatal) => { - gum::debug!(target: LOG_TARGET, error = ?fatal, "Shutting down request responder"); - return + // If peer currently being served drop request + if active_peers.contains(&request.peer) { + gum::trace!(target: LOG_TARGET, "Peer already being served, dropping request"); + metrics.on_request_dropped_peer_rate_limit(); + continue + } + + // If we are over parallel limit wait for one to finish + if pending_out.len() >= MAX_PARALLEL_ATTESTED_CANDIDATE_REQUESTS as usize { + gum::trace!(target: LOG_TARGET, "Over max parallel requests, waiting for one to finish"); + metrics.on_max_parallel_requests_reached(); + let (_, peer) = pending_out.select_next_some().await; + active_peers.remove(&peer); + } + + // Start serving the request + let (pending_sent_tx, pending_sent_rx) = oneshot::channel(); + let peer = request.peer; + if let Err(err) = sender + .feed(ResponderMessage { request, sent_feedback: pending_sent_tx }) + .await + { + gum::debug!(target: LOG_TARGET, ?err, "Shutting down responder"); + return + } + let future_with_peer = pending_sent_rx.map(move |result| (result, peer)); + pending_out.push(future_with_peer); + active_peers.insert(peer); }, - Ok(Err(jfyi)) => { - gum::debug!(target: LOG_TARGET, error = ?jfyi, "Decoding request failed"); - continue + // Request served/finished + result = pending_out.select_next_some() => { + let (_, peer) = result; + active_peers.remove(&peer); }, - }; - - let (pending_sent_tx, pending_sent_rx) = oneshot::channel(); - if let Err(err) = sender - .feed(ResponderMessage { request: req, sent_feedback: pending_sent_tx }) - .await - { - gum::debug!(target: LOG_TARGET, ?err, "Shutting down responder"); - return } - pending_out.push(pending_sent_rx); } } diff --git a/polkadot/node/network/statement-distribution/src/v2/requests.rs b/polkadot/node/network/statement-distribution/src/v2/requests.rs index fe270c8a58e81fc5ebee9a42c38a1cedd1a0b516..b8ed34d26c8a5272273297203b82e9ce263a107c 100644 --- a/polkadot/node/network/statement-distribution/src/v2/requests.rs +++ b/polkadot/node/network/statement-distribution/src/v2/requests.rs @@ -288,7 +288,7 @@ impl RequestManager { /// Returns an instant at which the next request to be retried will be ready. pub fn next_retry_time(&mut self) -> Option { let mut next = None; - for (_id, request) in &self.requests { + for (_id, request) in self.requests.iter().filter(|(_id, request)| !request.in_flight) { if let Some(next_retry_time) = request.next_retry_time { if next.map_or(true, |next| next_retry_time < next) { next = Some(next_retry_time); @@ -366,6 +366,7 @@ impl RequestManager { id, &props, &peer_advertised, + &response_manager, ) { None => continue, Some(t) => t, @@ -387,14 +388,17 @@ impl RequestManager { ); let stored_id = id.clone(); - response_manager.push(Box::pin(async move { - TaggedResponse { - identifier: stored_id, - requested_peer: target, - props, - response: response_fut.await, - } - })); + response_manager.push( + Box::pin(async move { + TaggedResponse { + identifier: stored_id, + requested_peer: target, + props, + response: response_fut.await, + } + }), + target, + ); entry.in_flight = true; @@ -422,28 +426,35 @@ impl RequestManager { /// A manager for pending responses. pub struct ResponseManager { pending_responses: FuturesUnordered>, + active_peers: HashSet, } impl ResponseManager { pub fn new() -> Self { - Self { pending_responses: FuturesUnordered::new() } + Self { pending_responses: FuturesUnordered::new(), active_peers: HashSet::new() } } /// Await the next incoming response to a sent request, or immediately /// return `None` if there are no pending responses. pub async fn incoming(&mut self) -> Option { - self.pending_responses - .next() - .await - .map(|response| UnhandledResponse { response }) + self.pending_responses.next().await.map(|response| { + self.active_peers.remove(&response.requested_peer); + UnhandledResponse { response } + }) } fn len(&self) -> usize { self.pending_responses.len() } - fn push(&mut self, response: BoxFuture<'static, TaggedResponse>) { + fn push(&mut self, response: BoxFuture<'static, TaggedResponse>, target: PeerId) { self.pending_responses.push(response); + self.active_peers.insert(target); + } + + /// Returns true if we are currently sending a request to the peer. + fn is_sending_to(&self, peer: &PeerId) -> bool { + self.active_peers.contains(peer) } } @@ -471,10 +482,16 @@ fn find_request_target_with_update( candidate_identifier: &CandidateIdentifier, props: &RequestProperties, peer_advertised: impl Fn(&CandidateIdentifier, &PeerId) -> Option, + response_manager: &ResponseManager, ) -> Option { let mut prune = Vec::new(); let mut target = None; for (i, p) in known_by.iter().enumerate() { + // If we are already sending to that peer, skip for now + if response_manager.is_sending_to(p) { + continue + } + let mut filter = match peer_advertised(candidate_identifier, p) { None => { prune.push(i); @@ -1002,7 +1019,8 @@ mod tests { candidate_receipt.descriptor.persisted_validation_data_hash = persisted_validation_data.hash(); let candidate = candidate_receipt.hash(); - let requested_peer = PeerId::random(); + let requested_peer_1 = PeerId::random(); + let requested_peer_2 = PeerId::random(); let identifier1 = request_manager .get_or_insert(relay_parent, candidate, 1.into()) @@ -1010,14 +1028,14 @@ mod tests { .clone(); request_manager .get_or_insert(relay_parent, candidate, 1.into()) - .add_peer(requested_peer); + .add_peer(requested_peer_1); let identifier2 = request_manager .get_or_insert(relay_parent, candidate, 2.into()) .identifier .clone(); request_manager .get_or_insert(relay_parent, candidate, 2.into()) - .add_peer(requested_peer); + .add_peer(requested_peer_2); assert_ne!(identifier1, identifier2); assert_eq!(request_manager.requests.len(), 2); @@ -1053,7 +1071,7 @@ mod tests { let response = UnhandledResponse { response: TaggedResponse { identifier: identifier1, - requested_peer, + requested_peer: requested_peer_1, props: request_properties.clone(), response: Ok(AttestedCandidateResponse { candidate_receipt: candidate_receipt.clone(), @@ -1076,13 +1094,13 @@ mod tests { assert_eq!( output, ResponseValidationOutput { - requested_peer, + requested_peer: requested_peer_1, request_status: CandidateRequestStatus::Complete { candidate: candidate_receipt.clone(), persisted_validation_data: persisted_validation_data.clone(), statements, }, - reputation_changes: vec![(requested_peer, BENEFIT_VALID_RESPONSE)], + reputation_changes: vec![(requested_peer_1, BENEFIT_VALID_RESPONSE)], } ); } @@ -1093,7 +1111,7 @@ mod tests { let response = UnhandledResponse { response: TaggedResponse { identifier: identifier2, - requested_peer, + requested_peer: requested_peer_2, props: request_properties, response: Ok(AttestedCandidateResponse { candidate_receipt: candidate_receipt.clone(), @@ -1115,12 +1133,14 @@ mod tests { assert_eq!( output, ResponseValidationOutput { - requested_peer, + requested_peer: requested_peer_2, request_status: CandidateRequestStatus::Outdated, reputation_changes: vec![], } ); } + + assert_eq!(request_manager.requests.len(), 0); } // Test case where we had a request in-flight and the request entry was garbage-collected on @@ -1293,4 +1313,140 @@ mod tests { assert_eq!(request_manager.requests.len(), 0); assert_eq!(request_manager.by_priority.len(), 0); } + + // Test case where we queue 2 requests to be sent to the same peer and 1 request to another + // peer. Same peer requests should be served one at a time but they should not block the other + // peer request. + #[test] + fn rate_limit_requests_to_same_peer() { + let mut request_manager = RequestManager::new(); + let mut response_manager = ResponseManager::new(); + + let relay_parent = Hash::from_low_u64_le(1); + + // Create 3 candidates + let mut candidate_receipt_1 = test_helpers::dummy_committed_candidate_receipt(relay_parent); + let persisted_validation_data_1 = dummy_pvd(); + candidate_receipt_1.descriptor.persisted_validation_data_hash = + persisted_validation_data_1.hash(); + let candidate_1 = candidate_receipt_1.hash(); + + let mut candidate_receipt_2 = test_helpers::dummy_committed_candidate_receipt(relay_parent); + let persisted_validation_data_2 = dummy_pvd(); + candidate_receipt_2.descriptor.persisted_validation_data_hash = + persisted_validation_data_2.hash(); + let candidate_2 = candidate_receipt_2.hash(); + + let mut candidate_receipt_3 = test_helpers::dummy_committed_candidate_receipt(relay_parent); + let persisted_validation_data_3 = dummy_pvd(); + candidate_receipt_3.descriptor.persisted_validation_data_hash = + persisted_validation_data_3.hash(); + let candidate_3 = candidate_receipt_3.hash(); + + // Create 2 peers + let requested_peer_1 = PeerId::random(); + let requested_peer_2 = PeerId::random(); + + let group_size = 3; + let group = &[ValidatorIndex(0), ValidatorIndex(1), ValidatorIndex(2)]; + let unwanted_mask = StatementFilter::blank(group_size); + let disabled_mask: BitVec = Default::default(); + let request_properties = RequestProperties { unwanted_mask, backing_threshold: None }; + let request_props = |_identifier: &CandidateIdentifier| Some((&request_properties).clone()); + let peer_advertised = + |_identifier: &CandidateIdentifier, _peer: &_| Some(StatementFilter::full(group_size)); + + // Add request for candidate 1 from peer 1 + let identifier1 = request_manager + .get_or_insert(relay_parent, candidate_1, 1.into()) + .identifier + .clone(); + request_manager + .get_or_insert(relay_parent, candidate_1, 1.into()) + .add_peer(requested_peer_1); + + // Add request for candidate 3 from peer 2 (this one can be served in parallel) + let _identifier3 = request_manager + .get_or_insert(relay_parent, candidate_3, 1.into()) + .identifier + .clone(); + request_manager + .get_or_insert(relay_parent, candidate_3, 1.into()) + .add_peer(requested_peer_2); + + // Successfully dispatch request for candidate 1 from peer 1 and candidate 3 from peer 2 + for _ in 0..2 { + let outgoing = + request_manager.next_request(&mut response_manager, request_props, peer_advertised); + assert!(outgoing.is_some()); + } + assert_eq!(response_manager.active_peers.len(), 2); + assert!(response_manager.is_sending_to(&requested_peer_1)); + assert!(response_manager.is_sending_to(&requested_peer_2)); + assert_eq!(request_manager.requests.len(), 2); + + // Add request for candidate 2 from peer 1 + let _identifier2 = request_manager + .get_or_insert(relay_parent, candidate_2, 1.into()) + .identifier + .clone(); + request_manager + .get_or_insert(relay_parent, candidate_2, 1.into()) + .add_peer(requested_peer_1); + + // Do not dispatch the request for the second candidate from peer 1 (already serving that + // peer) + let outgoing = + request_manager.next_request(&mut response_manager, request_props, peer_advertised); + assert!(outgoing.is_none()); + assert_eq!(response_manager.active_peers.len(), 2); + assert!(response_manager.is_sending_to(&requested_peer_1)); + assert!(response_manager.is_sending_to(&requested_peer_2)); + assert_eq!(request_manager.requests.len(), 3); + + // Manually mark response received (response future resolved) + response_manager.active_peers.remove(&requested_peer_1); + response_manager.pending_responses = FuturesUnordered::new(); + + // Validate first response (candidate 1 from peer 1) + { + let statements = vec![]; + let response = UnhandledResponse { + response: TaggedResponse { + identifier: identifier1, + requested_peer: requested_peer_1, + props: request_properties.clone(), + response: Ok(AttestedCandidateResponse { + candidate_receipt: candidate_receipt_1.clone(), + persisted_validation_data: persisted_validation_data_1.clone(), + statements, + }), + }, + }; + let validator_key_lookup = |_v| None; + let allowed_para_lookup = |_para, _g_index| true; + let _output = response.validate_response( + &mut request_manager, + group, + 0, + validator_key_lookup, + allowed_para_lookup, + disabled_mask.clone(), + ); + + // First request served successfully + assert_eq!(request_manager.requests.len(), 2); + assert_eq!(response_manager.active_peers.len(), 1); + assert!(response_manager.is_sending_to(&requested_peer_2)); + } + + // Check if the request that was ignored previously will be served now + let outgoing = + request_manager.next_request(&mut response_manager, request_props, peer_advertised); + assert!(outgoing.is_some()); + assert_eq!(response_manager.active_peers.len(), 2); + assert!(response_manager.is_sending_to(&requested_peer_1)); + assert!(response_manager.is_sending_to(&requested_peer_2)); + assert_eq!(request_manager.requests.len(), 2); + } } 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 4fb033e08ce3af0724d5a8770bdb0abf942e38a5..fe51f953e244a560d7fe2e0bf414279fd0b8bf89 100644 --- a/polkadot/node/network/statement-distribution/src/v2/tests/cluster.rs +++ b/polkadot/node/network/statement-distribution/src/v2/tests/cluster.rs @@ -111,8 +111,8 @@ fn share_seconded_circulated_to_cluster() { ); // sharing a `Seconded` message confirms a candidate, which leads to new - // fragment tree updates. - answer_expected_hypothetical_depth_request(&mut overseer, vec![]).await; + // fragment chain updates. + answer_expected_hypothetical_membership_request(&mut overseer, vec![]).await; overseer }); @@ -509,7 +509,7 @@ fn seconded_statement_leads_to_request() { if p == peer_a && r == BENEFIT_VALID_RESPONSE.into() => { } ); - answer_expected_hypothetical_depth_request(&mut overseer, vec![]).await; + answer_expected_hypothetical_membership_request(&mut overseer, vec![]).await; overseer }); @@ -583,7 +583,7 @@ fn cluster_statements_shared_seconded_first() { .await; // result of new confirmed candidate. - answer_expected_hypothetical_depth_request(&mut overseer, vec![]).await; + answer_expected_hypothetical_membership_request(&mut overseer, vec![]).await; overseer .send(FromOrchestra::Communication { @@ -717,8 +717,8 @@ fn cluster_accounts_for_implicit_view() { ); // sharing a `Seconded` message confirms a candidate, which leads to new - // fragment tree updates. - answer_expected_hypothetical_depth_request(&mut overseer, vec![]).await; + // fragment chain updates. + answer_expected_hypothetical_membership_request(&mut overseer, vec![]).await; // activate new leaf, which has relay-parent in implicit view. let next_relay_parent = Hash::repeat_byte(2); @@ -855,7 +855,7 @@ fn cluster_messages_imported_after_confirmed_candidate_importable_check() { ); } - answer_expected_hypothetical_depth_request( + answer_expected_hypothetical_membership_request( &mut overseer, vec![( HypotheticalCandidate::Complete { @@ -863,7 +863,7 @@ fn cluster_messages_imported_after_confirmed_candidate_importable_check() { receipt: Arc::new(candidate.clone()), persisted_validation_data: pvd.clone(), }, - vec![(relay_parent, vec![0])], + vec![relay_parent], )], ) .await; @@ -978,7 +978,7 @@ fn cluster_messages_imported_after_new_leaf_importable_check() { ); } - answer_expected_hypothetical_depth_request(&mut overseer, vec![]).await; + answer_expected_hypothetical_membership_request(&mut overseer, vec![]).await; let next_relay_parent = Hash::repeat_byte(2); let mut next_test_leaf = state.make_dummy_leaf(next_relay_parent); @@ -996,7 +996,7 @@ fn cluster_messages_imported_after_new_leaf_importable_check() { receipt: Arc::new(candidate.clone()), persisted_validation_data: pvd.clone(), }, - vec![(relay_parent, vec![0])], + vec![relay_parent], )], ) .await; @@ -1113,7 +1113,7 @@ fn ensure_seconding_limit_is_respected() { AllMessages::NetworkBridgeTx(NetworkBridgeTxMessage::SendValidationMessage(peers, _)) if peers == vec![peer_a] ); - answer_expected_hypothetical_depth_request(&mut overseer, vec![]).await; + answer_expected_hypothetical_membership_request(&mut overseer, vec![]).await; } // Candidate 2. @@ -1139,7 +1139,7 @@ fn ensure_seconding_limit_is_respected() { AllMessages::NetworkBridgeTx(NetworkBridgeTxMessage::SendValidationMessage(peers, _)) if peers == vec![peer_a] ); - answer_expected_hypothetical_depth_request(&mut overseer, vec![]).await; + answer_expected_hypothetical_membership_request(&mut overseer, vec![]).await; } // Send first statement from peer A. diff --git a/polkadot/node/network/statement-distribution/src/v2/tests/grid.rs b/polkadot/node/network/statement-distribution/src/v2/tests/grid.rs index 9d00a92e742bb6a304004ed74eb59ea8b6c5440c..d2bf031368c14a13f5da44dd29ba28376109f9bf 100644 --- a/polkadot/node/network/statement-distribution/src/v2/tests/grid.rs +++ b/polkadot/node/network/statement-distribution/src/v2/tests/grid.rs @@ -129,7 +129,7 @@ fn backed_candidate_leads_to_advertisement() { AllMessages::NetworkBridgeTx(NetworkBridgeTxMessage::SendValidationMessage(peers, _)) if peers == vec![peer_a] ); - answer_expected_hypothetical_depth_request(&mut overseer, vec![]).await; + answer_expected_hypothetical_membership_request(&mut overseer, vec![]).await; } // Send enough statements to make candidate backable, make sure announcements are sent. @@ -224,7 +224,7 @@ fn backed_candidate_leads_to_advertisement() { } ); - answer_expected_hypothetical_depth_request(&mut overseer, vec![]).await; + answer_expected_hypothetical_membership_request(&mut overseer, vec![]).await; } overseer @@ -384,7 +384,7 @@ fn received_advertisement_before_confirmation_leads_to_request() { if p == peer_c && r == BENEFIT_VALID_RESPONSE.into() => { } ); - answer_expected_hypothetical_depth_request(&mut overseer, vec![]).await; + answer_expected_hypothetical_membership_request(&mut overseer, vec![]).await; } overseer @@ -515,7 +515,7 @@ fn received_advertisement_after_backing_leads_to_acknowledgement() { assert_peer_reported!(&mut overseer, peer_c, BENEFIT_VALID_STATEMENT); assert_peer_reported!(&mut overseer, peer_c, BENEFIT_VALID_RESPONSE); - answer_expected_hypothetical_depth_request(&mut overseer, vec![]).await; + answer_expected_hypothetical_membership_request(&mut overseer, vec![]).await; } // Receive Backed message. @@ -546,7 +546,7 @@ fn received_advertisement_after_backing_leads_to_acknowledgement() { } ); - answer_expected_hypothetical_depth_request(&mut overseer, vec![]).await; + answer_expected_hypothetical_membership_request(&mut overseer, vec![]).await; } // Receive a manifest about the same candidate from peer D. @@ -720,7 +720,7 @@ fn received_acknowledgements_for_locally_confirmed() { AllMessages::NetworkBridgeTx(NetworkBridgeTxMessage::SendValidationMessage(peers, _)) if peers == vec![peer_a] ); - answer_expected_hypothetical_depth_request(&mut overseer, vec![]).await; + answer_expected_hypothetical_membership_request(&mut overseer, vec![]).await; } // Receive an unexpected acknowledgement from peer D. @@ -785,7 +785,7 @@ fn received_acknowledgements_for_locally_confirmed() { } ); - answer_expected_hypothetical_depth_request(&mut overseer, vec![]).await; + answer_expected_hypothetical_membership_request(&mut overseer, vec![]).await; } // Receive an unexpected acknowledgement from peer D. @@ -918,7 +918,7 @@ fn received_acknowledgements_for_externally_confirmed() { assert_peer_reported!(&mut overseer, peer_c, BENEFIT_VALID_STATEMENT); assert_peer_reported!(&mut overseer, peer_c, BENEFIT_VALID_RESPONSE); - answer_expected_hypothetical_depth_request(&mut overseer, vec![]).await; + answer_expected_hypothetical_membership_request(&mut overseer, vec![]).await; } let ack = BackedCandidateAcknowledgement { @@ -1101,7 +1101,7 @@ fn received_advertisement_after_confirmation_before_backing() { if p == peer_c && r == BENEFIT_VALID_RESPONSE.into() ); - answer_expected_hypothetical_depth_request(&mut overseer, vec![]).await; + answer_expected_hypothetical_membership_request(&mut overseer, vec![]).await; } // Receive advertisement from peer D (after confirmation but before backing). @@ -1272,9 +1272,12 @@ fn additional_statements_are_shared_after_manifest_exchange() { receipt: Arc::new(candidate.clone()), persisted_validation_data: pvd.clone(), }; - let membership = vec![(relay_parent, vec![0])]; - answer_expected_hypothetical_depth_request(&mut overseer, vec![(hypothetical, membership)]) - .await; + let membership = vec![relay_parent]; + answer_expected_hypothetical_membership_request( + &mut overseer, + vec![(hypothetical, membership)], + ) + .await; // Statements are sent to the Backing subsystem. { @@ -1338,7 +1341,7 @@ fn additional_statements_are_shared_after_manifest_exchange() { } ); - answer_expected_hypothetical_depth_request(&mut overseer, vec![]).await; + answer_expected_hypothetical_membership_request(&mut overseer, vec![]).await; } // Receive a manifest about the same candidate from peer D. Contains different statements. @@ -1507,7 +1510,7 @@ fn advertisement_sent_when_peer_enters_relay_parent_view() { AllMessages::NetworkBridgeTx(NetworkBridgeTxMessage::SendValidationMessage(peers, _)) if peers == vec![peer_a] ); - answer_expected_hypothetical_depth_request(&mut overseer, vec![]).await; + answer_expected_hypothetical_membership_request(&mut overseer, vec![]).await; } // Send enough statements to make candidate backable, make sure announcements are sent. @@ -1574,7 +1577,7 @@ fn advertisement_sent_when_peer_enters_relay_parent_view() { }) .await; - answer_expected_hypothetical_depth_request(&mut overseer, vec![]).await; + answer_expected_hypothetical_membership_request(&mut overseer, vec![]).await; // Relay parent enters view of peer C. { @@ -1721,7 +1724,7 @@ fn advertisement_not_re_sent_when_peer_re_enters_view() { AllMessages::NetworkBridgeTx(NetworkBridgeTxMessage::SendValidationMessage(peers, _)) if peers == vec![peer_a] ); - answer_expected_hypothetical_depth_request(&mut overseer, vec![]).await; + answer_expected_hypothetical_membership_request(&mut overseer, vec![]).await; } // Send enough statements to make candidate backable, make sure announcements are sent. @@ -1816,7 +1819,7 @@ fn advertisement_not_re_sent_when_peer_re_enters_view() { } ); - answer_expected_hypothetical_depth_request(&mut overseer, vec![]).await; + answer_expected_hypothetical_membership_request(&mut overseer, vec![]).await; } // Peer leaves view. @@ -1982,9 +1985,12 @@ fn inner_grid_statements_imported_to_backing(groups_for_first_para: usize) { receipt: Arc::new(candidate.clone()), persisted_validation_data: pvd.clone(), }; - let membership = vec![(relay_parent, vec![0])]; - answer_expected_hypothetical_depth_request(&mut overseer, vec![(hypothetical, membership)]) - .await; + let membership = vec![relay_parent]; + answer_expected_hypothetical_membership_request( + &mut overseer, + vec![(hypothetical, membership)], + ) + .await; // Receive messages from Backing subsystem. { @@ -2616,7 +2622,7 @@ fn peer_reported_for_advertisement_conflicting_with_confirmed_candidate() { if p == peer_c && r == BENEFIT_VALID_RESPONSE.into() ); - answer_expected_hypothetical_depth_request(&mut overseer, vec![]).await; + answer_expected_hypothetical_membership_request(&mut overseer, vec![]).await; } // Receive conflicting advertisement from peer C after confirmation. @@ -2763,7 +2769,7 @@ fn inactive_local_participates_in_grid() { AllMessages::NetworkBridgeTx(NetworkBridgeTxMessage::ReportPeer(ReportPeerMessage::Single(p, r))) if p == peer_a && r == BENEFIT_VALID_RESPONSE.into() => { } ); - answer_expected_hypothetical_depth_request(&mut overseer, vec![]).await; + answer_expected_hypothetical_membership_request(&mut overseer, vec![]).await; overseer }); diff --git a/polkadot/node/network/statement-distribution/src/v2/tests/mod.rs b/polkadot/node/network/statement-distribution/src/v2/tests/mod.rs index 8dda7219cd1251ccd7869408c51e80ca01513c2b..d32e2323ba346b3001677b7951d4257e6a18752e 100644 --- a/polkadot/node/network/statement-distribution/src/v2/tests/mod.rs +++ b/polkadot/node/network/statement-distribution/src/v2/tests/mod.rs @@ -26,8 +26,8 @@ use polkadot_node_network_protocol::{ }; use polkadot_node_primitives::Statement; use polkadot_node_subsystem::messages::{ - network_bridge_event::NewGossipTopology, AllMessages, ChainApiMessage, FragmentTreeMembership, - HypotheticalCandidate, NetworkBridgeEvent, ProspectiveParachainsMessage, ReportPeerMessage, + network_bridge_event::NewGossipTopology, AllMessages, ChainApiMessage, HypotheticalCandidate, + HypotheticalMembership, NetworkBridgeEvent, ProspectiveParachainsMessage, ReportPeerMessage, RuntimeApiMessage, RuntimeApiRequest, }; use polkadot_node_subsystem_test_helpers as test_helpers; @@ -509,6 +509,12 @@ async fn setup_test_and_connect_peers( // Send gossip topology and activate leaf. if send_topology_before_leaf { send_new_topology(overseer, state.make_dummy_topology()).await; + // Send cleaning up of a leaf to make sure it does not clear the save topology as well. + overseer + .send(FromOrchestra::Signal(OverseerSignal::ActiveLeaves( + ActiveLeavesUpdate::stop_work(Hash::random()), + ))) + .await; activate_leaf(overseer, &test_leaf, &state, true, vec![]).await; } else { activate_leaf(overseer, &test_leaf, &state, true, vec![]).await; @@ -533,7 +539,7 @@ async fn activate_leaf( leaf: &TestLeaf, test_state: &TestState, is_new_session: bool, - hypothetical_frontier: Vec<(HypotheticalCandidate, FragmentTreeMembership)>, + hypothetical_memberships: Vec<(HypotheticalCandidate, HypotheticalMembership)>, ) { let activated = new_leaf(leaf.hash, leaf.number); @@ -548,7 +554,7 @@ async fn activate_leaf( leaf, test_state, is_new_session, - hypothetical_frontier, + hypothetical_memberships, ) .await; } @@ -558,7 +564,7 @@ async fn handle_leaf_activation( leaf: &TestLeaf, test_state: &TestState, is_new_session: bool, - hypothetical_frontier: Vec<(HypotheticalCandidate, FragmentTreeMembership)>, + hypothetical_memberships: Vec<(HypotheticalCandidate, HypotheticalMembership)>, ) { let TestLeaf { number, @@ -668,18 +674,17 @@ async fn handle_leaf_activation( tx.send(Ok((validator_groups, group_rotation_info))).unwrap(); }, AllMessages::ProspectiveParachains( - ProspectiveParachainsMessage::GetHypotheticalFrontier(req, tx), + ProspectiveParachainsMessage::GetHypotheticalMembership(req, tx), ) => { - assert_eq!(req.fragment_tree_relay_parent, Some(*hash)); - assert!(!req.backed_in_path_only); - for (i, (candidate, _)) in hypothetical_frontier.iter().enumerate() { + assert_eq!(req.fragment_chain_relay_parent, Some(*hash)); + for (i, (candidate, _)) in hypothetical_memberships.iter().enumerate() { assert!( req.candidates.iter().any(|c| &c == &candidate), "did not receive request for hypothetical candidate {}", i, ); } - tx.send(hypothetical_frontier).unwrap(); + tx.send(hypothetical_memberships).unwrap(); // this is the last expected runtime api call break }, @@ -721,17 +726,16 @@ async fn handle_sent_request( ); } -async fn answer_expected_hypothetical_depth_request( +async fn answer_expected_hypothetical_membership_request( virtual_overseer: &mut VirtualOverseer, - responses: Vec<(HypotheticalCandidate, FragmentTreeMembership)>, + responses: Vec<(HypotheticalCandidate, HypotheticalMembership)>, ) { assert_matches!( virtual_overseer.recv().await, AllMessages::ProspectiveParachains( - ProspectiveParachainsMessage::GetHypotheticalFrontier(req, tx) + ProspectiveParachainsMessage::GetHypotheticalMembership(req, tx) ) => { - assert_eq!(req.fragment_tree_relay_parent, None); - assert!(!req.backed_in_path_only); + assert_eq!(req.fragment_chain_relay_parent, None); for (i, (candidate, _)) in responses.iter().enumerate() { assert!( req.candidates.iter().any(|c| &c == &candidate), diff --git a/polkadot/node/network/statement-distribution/src/v2/tests/requests.rs b/polkadot/node/network/statement-distribution/src/v2/tests/requests.rs index dc2c8f55290b43e5dce172730d3c5027dddc4b03..38d7a10b86527c153f4a369beb8bbe86da05d582 100644 --- a/polkadot/node/network/statement-distribution/src/v2/tests/requests.rs +++ b/polkadot/node/network/statement-distribution/src/v2/tests/requests.rs @@ -169,7 +169,7 @@ fn cluster_peer_allowed_to_send_incomplete_statements() { ); } - answer_expected_hypothetical_depth_request(&mut overseer, vec![]).await; + answer_expected_hypothetical_membership_request(&mut overseer, vec![]).await; overseer }); @@ -339,7 +339,7 @@ fn peer_reported_for_providing_statements_meant_to_be_masked_out() { if p == peer_c && r == BENEFIT_VALID_RESPONSE.into() ); - answer_expected_hypothetical_depth_request(&mut overseer, vec![]).await; + answer_expected_hypothetical_membership_request(&mut overseer, vec![]).await; } // Peer C advertises candidate 2. @@ -411,7 +411,7 @@ fn peer_reported_for_providing_statements_meant_to_be_masked_out() { if p == peer_c && r == BENEFIT_VALID_RESPONSE.into() ); - answer_expected_hypothetical_depth_request(&mut overseer, vec![]).await; + answer_expected_hypothetical_membership_request(&mut overseer, vec![]).await; } // Peer C sends an announcement for candidate 3. Should hit seconding limit for validator 1. @@ -634,7 +634,7 @@ fn peer_reported_for_not_enough_statements() { if p == peer_c && r == BENEFIT_VALID_RESPONSE.into() ); - answer_expected_hypothetical_depth_request(&mut overseer, vec![]).await; + answer_expected_hypothetical_membership_request(&mut overseer, vec![]).await; } overseer @@ -789,7 +789,7 @@ fn peer_reported_for_duplicate_statements() { ); } - answer_expected_hypothetical_depth_request(&mut overseer, vec![]).await; + answer_expected_hypothetical_membership_request(&mut overseer, vec![]).await; overseer }); @@ -919,7 +919,7 @@ fn peer_reported_for_providing_statements_with_invalid_signatures() { if p == peer_a && r == BENEFIT_VALID_RESPONSE.into() => { } ); - answer_expected_hypothetical_depth_request(&mut overseer, vec![]).await; + answer_expected_hypothetical_membership_request(&mut overseer, vec![]).await; } overseer @@ -1049,7 +1049,7 @@ fn peer_reported_for_providing_statements_with_wrong_validator_id() { if p == peer_a && r == BENEFIT_VALID_RESPONSE.into() => { } ); - answer_expected_hypothetical_depth_request(&mut overseer, vec![]).await; + answer_expected_hypothetical_membership_request(&mut overseer, vec![]).await; } overseer @@ -1215,7 +1215,7 @@ fn disabled_validators_added_to_unwanted_mask() { assert_eq!(statement, seconded_b); } ); - answer_expected_hypothetical_depth_request(&mut overseer, vec![]).await; + answer_expected_hypothetical_membership_request(&mut overseer, vec![]).await; } overseer @@ -1372,7 +1372,7 @@ fn when_validator_disabled_after_sending_the_request() { assert_eq!(statement, seconded_b); } ); - answer_expected_hypothetical_depth_request(&mut overseer, vec![]).await; + answer_expected_hypothetical_membership_request(&mut overseer, vec![]).await; } overseer @@ -1475,7 +1475,7 @@ fn no_response_for_grid_request_not_meeting_quorum() { AllMessages::NetworkBridgeTx(NetworkBridgeTxMessage::SendValidationMessage(peers, _)) if peers == vec![peer_a] ); - answer_expected_hypothetical_depth_request(&mut overseer, vec![]).await; + answer_expected_hypothetical_membership_request(&mut overseer, vec![]).await; } // Send enough statements to make candidate backable, make sure announcements are sent. @@ -1572,7 +1572,7 @@ fn no_response_for_grid_request_not_meeting_quorum() { } ); - answer_expected_hypothetical_depth_request(&mut overseer, vec![]).await; + answer_expected_hypothetical_membership_request(&mut overseer, vec![]).await; } let mask = StatementFilter { @@ -1720,7 +1720,7 @@ fn disabling_works_from_the_latest_state_not_relay_parent() { if p == peer_disabled && r == BENEFIT_VALID_RESPONSE.into() => { } ); - answer_expected_hypothetical_depth_request(&mut overseer, vec![]).await; + answer_expected_hypothetical_membership_request(&mut overseer, vec![]).await; } activate_leaf(&mut overseer, &leaf_2, &state, false, vec![]).await; @@ -1862,7 +1862,7 @@ fn local_node_sanity_checks_incoming_requests() { } ); - answer_expected_hypothetical_depth_request(&mut overseer, vec![]).await; + answer_expected_hypothetical_membership_request(&mut overseer, vec![]).await; } // Should drop requests from unknown peers. @@ -1891,7 +1891,7 @@ fn local_node_sanity_checks_incoming_requests() { let mask = StatementFilter::blank(state.config.group_size + 1); let response = state .send_request( - peer_c, + peer_a, request_v2::AttestedCandidateRequest { candidate_hash: candidate.hash(), mask }, ) .await @@ -2036,7 +2036,7 @@ fn local_node_checks_that_peer_can_request_before_responding() { } ); - answer_expected_hypothetical_depth_request(&mut overseer, vec![]).await; + answer_expected_hypothetical_membership_request(&mut overseer, vec![]).await; // Local node should respond to requests from peers in the same group // which appear to not have already seen the candidate @@ -2248,7 +2248,7 @@ fn local_node_respects_statement_mask() { AllMessages::NetworkBridgeTx(NetworkBridgeTxMessage::SendValidationMessage(peers, _)) if peers == vec![peer_a] ); - answer_expected_hypothetical_depth_request(&mut overseer, vec![]).await; + answer_expected_hypothetical_membership_request(&mut overseer, vec![]).await; } // Send enough statements to make candidate backable, make sure announcements are sent. @@ -2347,7 +2347,7 @@ fn local_node_respects_statement_mask() { } ); - answer_expected_hypothetical_depth_request(&mut overseer, vec![]).await; + answer_expected_hypothetical_membership_request(&mut overseer, vec![]).await; } // `1` indicates statements NOT to request. @@ -2600,13 +2600,37 @@ fn should_delay_before_retrying_dropped_requests() { if p == peer_c && r == BENEFIT_VALID_RESPONSE.into() ); - answer_expected_hypothetical_depth_request(&mut overseer, vec![]).await; + answer_expected_hypothetical_membership_request(&mut overseer, vec![]).await; } // Sleep for the given amount of time. This should reset the delay for the first candidate. futures_timer::Delay::new(REQUEST_RETRY_DELAY).await; - // We re-try the first request. + // We re-try the first request the second time drop it again. + assert_matches!( + overseer.recv().await, + AllMessages::NetworkBridgeTx(NetworkBridgeTxMessage::SendRequests(mut requests, IfDisconnected::ImmediateError)) => { + assert_eq!(requests.len(), 1); + assert_matches!( + requests.pop().unwrap(), + Requests::AttestedCandidateV2(outgoing) => { + assert_eq!(outgoing.peer, Recipient::Peer(peer_c)); + assert_eq!(outgoing.payload.candidate_hash, candidate_hash_1); + assert_eq!(outgoing.payload.mask, mask); + } + ); + } + ); + + assert_matches!( + overseer_recv_with_timeout(&mut overseer, Duration::from_millis(100)).await, + None + ); + + // Sleep for the given amount of time. This should reset the delay for the first candidate. + futures_timer::Delay::new(REQUEST_RETRY_DELAY).await; + + // We re-try the first request, for the third time, so let's answer to it. { let statements = vec![ state @@ -2667,7 +2691,7 @@ fn should_delay_before_retrying_dropped_requests() { if p == peer_c && r == BENEFIT_VALID_RESPONSE.into() ); - answer_expected_hypothetical_depth_request(&mut overseer, vec![]).await; + answer_expected_hypothetical_membership_request(&mut overseer, vec![]).await; } overseer diff --git a/polkadot/node/primitives/Cargo.toml b/polkadot/node/primitives/Cargo.toml index a4bbd824e6712e001f1df1cd9d66f835d02822fb..526d4e480bb05d745aad137f94b611f4cf91c838 100644 --- a/polkadot/node/primitives/Cargo.toml +++ b/polkadot/node/primitives/Cargo.toml @@ -13,7 +13,7 @@ workspace = true bounded-vec = "0.7" futures = "0.3.30" polkadot-primitives = { path = "../../primitives" } -parity-scale-codec = { version = "3.6.1", default-features = false, features = ["derive"] } +parity-scale-codec = { version = "3.6.12", default-features = false, features = ["derive"] } sp-core = { path = "../../../substrate/primitives/core" } sp-application-crypto = { path = "../../../substrate/primitives/application-crypto" } sp-consensus-babe = { path = "../../../substrate/primitives/consensus/babe" } diff --git a/polkadot/node/primitives/src/lib.rs b/polkadot/node/primitives/src/lib.rs index 375aacd583267ef7e86f7888a9e3e17599e7414d..0f97250a934e0865d799fc1ea3923bbceff57a99 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.10.0"; +pub const NODE_VERSION: &'static str = "1.11.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 9688ab556473131d6e90075de9b6f69ba4f244e5..b3f1c22d0e705bfddc1a5fb42e9da1d5cb244746 100644 --- a/polkadot/node/service/Cargo.toml +++ b/polkadot/node/service/Cargo.toml @@ -90,7 +90,7 @@ 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" } +codec = { package = "parity-scale-codec", version = "3.6.12" } parking_lot = "0.12.1" bitvec = { version = "1.0.1", optional = true } @@ -206,6 +206,7 @@ runtime-benchmarks = [ "service/runtime-benchmarks", "sp-runtime/runtime-benchmarks", "westend-runtime?/runtime-benchmarks", + "xcm-fee-payment-runtime-api/runtime-benchmarks", ] try-runtime = [ "frame-support/try-runtime", diff --git a/polkadot/node/service/chain-specs/kusama.json b/polkadot/node/service/chain-specs/kusama.json index 490b39ee696930bafc9af4c139339a9974dffff9..899b302155f79c2e889ca8300f9cf277059bd3d4 100644 --- a/polkadot/node/service/chain-specs/kusama.json +++ b/polkadot/node/service/chain-specs/kusama.json @@ -18,11 +18,11 @@ "/dns/kusama.bootnode.amforc.com/tcp/30334/wss/p2p/12D3KooWLx6nsj6Fpd8biP1VDyuCUjazvRiGWyBam8PsqRJkbUb9", "/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", - "/dns/boot-kusama.metaspan.io/tcp/23015/ws/p2p/12D3KooWE1tq9ZL9AAxMiUBBqy1ENmh5pwfWabnoBPMo8gFPXhn6", - "/dns/boot-kusama.metaspan.io/tcp/23016/wss/p2p/12D3KooWE1tq9ZL9AAxMiUBBqy1ENmh5pwfWabnoBPMo8gFPXhn6", + "/dns/boot.gatotech.network/tcp/33200/p2p/12D3KooWRNZXf99BfzQDE1C8YhuBbuy7Sj18UEf7FNpD8egbURYD", + "/dns/boot.gatotech.network/tcp/35200/wss/p2p/12D3KooWRNZXf99BfzQDE1C8YhuBbuy7Sj18UEf7FNpD8egbURYD", + "/dns/boot.metaspan.io/tcp/23012/p2p/12D3KooWE1tq9ZL9AAxMiUBBqy1ENmh5pwfWabnoBPMo8gFPXhn6", + "/dns/boot.metaspan.io/tcp/23015/ws/p2p/12D3KooWE1tq9ZL9AAxMiUBBqy1ENmh5pwfWabnoBPMo8gFPXhn6", + "/dns/boot.metaspan.io/tcp/23016/wss/p2p/12D3KooWE1tq9ZL9AAxMiUBBqy1ENmh5pwfWabnoBPMo8gFPXhn6", "/dns/kusama-bootnode.turboflakes.io/tcp/30305/p2p/12D3KooWR6cMhCYRhbJdqYZfzWZT6bcck3unpRLk8GBQGmHBgPwu", "/dns/kusama-bootnode.turboflakes.io/tcp/30405/wss/p2p/12D3KooWR6cMhCYRhbJdqYZfzWZT6bcck3unpRLk8GBQGmHBgPwu", "/dns/kusama-boot-ng.dwellir.com/tcp/443/wss/p2p/12D3KooWLswepVYVdCNduvWRTyNTaDMXEBcmvJdZ9Bhw3u2Jhad2", @@ -36,7 +36,8 @@ "/dns/ksm14.rotko.net/tcp/33224/p2p/12D3KooWAa5THTw8HPfnhEei23HdL8P9McBXdozG2oTtMMksjZkK", "/dns/ibp-boot-kusama.luckyfriday.io/tcp/30333/p2p/12D3KooW9vu1GWHBuxyhm7rZgD3fhGZpNajPXFexadvhujWMgwfT", "/dns/boot-kusama.luckyfriday.io/tcp/443/wss/p2p/12D3KooWS1Lu6DmK8YHSvkErpxpcXmk14vG6y4KVEFEkd9g62PP8", - "/dns/ibp-boot-kusama.luckyfriday.io/tcp/30334/wss/p2p/12D3KooW9vu1GWHBuxyhm7rZgD3fhGZpNajPXFexadvhujWMgwfT" + "/dns/ibp-boot-kusama.luckyfriday.io/tcp/30334/wss/p2p/12D3KooW9vu1GWHBuxyhm7rZgD3fhGZpNajPXFexadvhujWMgwfT", + "/dns4/kusama-0.boot.onfinality.io/tcp/27682/ws/p2p/12D3KooWFrwFo7ry3dEuFwhehGSSN96a5Xdzxot7SWfXeSbhELAe" ], "telemetryEndpoints": [ [ diff --git a/polkadot/node/service/chain-specs/paseo.json b/polkadot/node/service/chain-specs/paseo.json index 19eefd328994ed67c269fafc06acefaf28c751bf..5a67ddcd4c4361f4f1fc4e87ac6ffdf649e06feb 100644 --- a/polkadot/node/service/chain-specs/paseo.json +++ b/polkadot/node/service/chain-specs/paseo.json @@ -17,6 +17,8 @@ "/dns/boot.gatotech.network/tcp/35400/wss/p2p/12D3KooWEvz5Ygv3MhCUNTVQbUTVhzhvf4KKcNoe5M5YbVLPBeeW", "/dns/paseo-bootnode.turboflakes.io/tcp/30630/p2p/12D3KooWMjCN2CrnN71hAdehn6M2iYKeGdGbZ1A3SKhf4hxrgG9e", "/dns/paseo-bootnode.turboflakes.io/tcp/30730/wss/p2p/12D3KooWMjCN2CrnN71hAdehn6M2iYKeGdGbZ1A3SKhf4hxrgG9e", + "/dns/pso16.rotko.net/tcp/33246/p2p/12D3KooWRH8eBMhw8c7bucy6pJfy94q4dKpLkF3pmeGohHmemdRu", + "/dns/pso16.rotko.net/tcp/35246/wss/p2p/12D3KooWRH8eBMhw8c7bucy6pJfy94q4dKpLkF3pmeGohHmemdRu", "/dns/paseo-boot-ng.dwellir.com/tcp/443/wss/p2p/12D3KooWBLLFKDGBxCwq3QmU3YwWKXUx953WwprRshJQicYu4Cfr", "/dns/paseo-boot-ng.dwellir.com/tcp/30354/p2p/12D3KooWBLLFKDGBxCwq3QmU3YwWKXUx953WwprRshJQicYu4Cfr" ], diff --git a/polkadot/node/service/chain-specs/polkadot.json b/polkadot/node/service/chain-specs/polkadot.json index 5f8d88102d7edd9d9d640a21b43a3c37982430d5..04def54f794cbc6381c3b2aadaa3e2d02763b6f2 100644 --- a/polkadot/node/service/chain-specs/polkadot.json +++ b/polkadot/node/service/chain-specs/polkadot.json @@ -19,11 +19,11 @@ "/dns/polkadot.bootnode.amforc.com/tcp/30334/wss/p2p/12D3KooWAsuCEVCzUVUrtib8W82Yne3jgVGhQZN3hizko5FTnDg3", "/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", - "/dns/boot-polkadot.metaspan.io/tcp/13015/ws/p2p/12D3KooWRjHFApinuqSBjoaDjQHvxwubQSpEVy5hrgC9Smvh92WF", - "/dns/boot-polkadot.metaspan.io/tcp/13016/wss/p2p/12D3KooWRjHFApinuqSBjoaDjQHvxwubQSpEVy5hrgC9Smvh92WF", + "/dns/boot.gatotech.network/tcp/33100/p2p/12D3KooWK4E16jKk9nRhvC4RfrDVgcZzExg8Q3Q2G7ABUUitks1w", + "/dns/boot.gatotech.network/tcp/35100/wss/p2p/12D3KooWK4E16jKk9nRhvC4RfrDVgcZzExg8Q3Q2G7ABUUitks1w", + "/dns/boot.metaspan.io/tcp/13012/p2p/12D3KooWRjHFApinuqSBjoaDjQHvxwubQSpEVy5hrgC9Smvh92WF", + "/dns/boot.metaspan.io/tcp/13015/ws/p2p/12D3KooWRjHFApinuqSBjoaDjQHvxwubQSpEVy5hrgC9Smvh92WF", + "/dns/boot.metaspan.io/tcp/13016/wss/p2p/12D3KooWRjHFApinuqSBjoaDjQHvxwubQSpEVy5hrgC9Smvh92WF", "/dns/polkadot-bootnode.turboflakes.io/tcp/30300/p2p/12D3KooWHJBMZgt7ymAdTRtadPcGXpJw79vBGe8z53r9JMkZW7Ha", "/dns/polkadot-bootnode.turboflakes.io/tcp/30400/wss/p2p/12D3KooWHJBMZgt7ymAdTRtadPcGXpJw79vBGe8z53r9JMkZW7Ha", "/dns/polkadot-boot-ng.dwellir.com/tcp/443/wss/p2p/12D3KooWFFqjBKoSdQniRpw1Y8W6kkV7takWv1DU2ZMkaA81PYVq", @@ -37,7 +37,8 @@ "/dns/dot14.rotko.net/tcp/33214/p2p/12D3KooWPyEvPEXghnMC67Gff6PuZiSvfx3fmziKiPZcGStZ5xff", "/dns/ibp-boot-polkadot.luckyfriday.io/tcp/30333/p2p/12D3KooWEjk6QXrZJ26fLpaajisJGHiz6WiQsR8k7mkM9GmWKnRZ", "/dns/ibp-boot-polkadot.luckyfriday.io/tcp/30334/wss/p2p/12D3KooWEjk6QXrZJ26fLpaajisJGHiz6WiQsR8k7mkM9GmWKnRZ", - "/dns/boot-polkadot.luckyfriday.io/tcp/443/wss/p2p/12D3KooWAdyiVAaeGdtBt6vn5zVetwA4z4qfm9Fi2QCSykN1wTBJ" + "/dns/boot-polkadot.luckyfriday.io/tcp/443/wss/p2p/12D3KooWAdyiVAaeGdtBt6vn5zVetwA4z4qfm9Fi2QCSykN1wTBJ", + "/dns4/polkadot-0.boot.onfinality.io/tcp/24446/ws/p2p/12D3KooWT1PWaNdAwYrSr89dvStnoGdH3t4LNRbcVNN4JCtsotkR" ], "telemetryEndpoints": [ [ diff --git a/polkadot/node/service/chain-specs/westend.json b/polkadot/node/service/chain-specs/westend.json index 775f3e72ac75578a0f0166cba96531244af760c9..16bc7ff07b0fdd4805b7ffb3a4099c5b0c728363 100644 --- a/polkadot/node/service/chain-specs/westend.json +++ b/polkadot/node/service/chain-specs/westend.json @@ -16,11 +16,11 @@ "/dns/westend.bootnode.amforc.com/tcp/30334/wss/p2p/12D3KooWJ5y9ZgVepBQNW4aabrxgmnrApdVnscqgKWiUu4BNJbC8", "/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", - "/dns/boot-westend.metaspan.io/tcp/33015/ws/p2p/12D3KooWNTau7iG4G9cUJSwwt2QJP1W88pUf2SgqsHjRU2RL8pfa", - "/dns/boot-westend.metaspan.io/tcp/33016/wss/p2p/12D3KooWNTau7iG4G9cUJSwwt2QJP1W88pUf2SgqsHjRU2RL8pfa", + "/dns/boot.gatotech.network/tcp/33300/p2p/12D3KooWQGR1vUhoy6mvQorFp3bZFn6NNezhQZ6NWnVV7tpFgoPd", + "/dns/boot.gatotech.network/tcp/35300/wss/p2p/12D3KooWQGR1vUhoy6mvQorFp3bZFn6NNezhQZ6NWnVV7tpFgoPd", + "/dns/boot.metaspan.io/tcp/33012/p2p/12D3KooWNTau7iG4G9cUJSwwt2QJP1W88pUf2SgqsHjRU2RL8pfa", + "/dns/boot.metaspan.io/tcp/33015/ws/p2p/12D3KooWNTau7iG4G9cUJSwwt2QJP1W88pUf2SgqsHjRU2RL8pfa", + "/dns/boot.metaspan.io/tcp/33016/wss/p2p/12D3KooWNTau7iG4G9cUJSwwt2QJP1W88pUf2SgqsHjRU2RL8pfa", "/dns/westend-bootnode.turboflakes.io/tcp/30310/p2p/12D3KooWJvPDCZmReU46ghpCMJCPVUvUCav4WQdKtXQhZgJdH6tZ", "/dns/westend-bootnode.turboflakes.io/tcp/30410/wss/p2p/12D3KooWJvPDCZmReU46ghpCMJCPVUvUCav4WQdKtXQhZgJdH6tZ", "/dns/westend-boot-ng.dwellir.com/tcp/443/wss/p2p/12D3KooWJifoDhCL3swAKt7MWhFb7wLRFD9oG33AL3nAathmU24x", diff --git a/polkadot/node/service/src/fake_runtime_api.rs b/polkadot/node/service/src/fake_runtime_api.rs index c6cfb7a27d042bdf9e1b23cd41f88b8483a414a5..03c4836020d98cdd15719619856db0be38dae66b 100644 --- a/polkadot/node/service/src/fake_runtime_api.rs +++ b/polkadot/node/service/src/fake_runtime_api.rs @@ -242,7 +242,7 @@ sp_api::impl_runtime_apis! { } fn submit_report_equivocation_unsigned_extrinsic( - _: beefy_primitives::EquivocationProof< + _: beefy_primitives::DoubleVotingProof< BlockNumber, BeefyId, BeefySignature, @@ -272,11 +272,11 @@ sp_api::impl_runtime_apis! { fn generate_proof( _: Vec, _: Option, - ) -> Result<(Vec, sp_mmr_primitives::Proof), sp_mmr_primitives::Error> { + ) -> Result<(Vec, sp_mmr_primitives::LeafProof), sp_mmr_primitives::Error> { unimplemented!() } - fn verify_proof(_: Vec, _: sp_mmr_primitives::Proof) + fn verify_proof(_: Vec, _: sp_mmr_primitives::LeafProof) -> Result<(), sp_mmr_primitives::Error> { unimplemented!() @@ -285,7 +285,7 @@ sp_api::impl_runtime_apis! { fn verify_proof_stateless( _: Hash, _: Vec, - _: sp_mmr_primitives::Proof + _: sp_mmr_primitives::LeafProof ) -> Result<(), sp_mmr_primitives::Error> { unimplemented!() } @@ -398,20 +398,30 @@ sp_api::impl_runtime_apis! { } } - impl xcm_fee_payment_runtime_api::XcmPaymentApi for Runtime { - fn query_acceptable_payment_assets(_: xcm::Version) -> Result, xcm_fee_payment_runtime_api::Error> { + impl xcm_fee_payment_runtime_api::fees::XcmPaymentApi for Runtime { + fn query_acceptable_payment_assets(_: xcm::Version) -> Result, xcm_fee_payment_runtime_api::fees::Error> { unimplemented!() } - fn query_weight_to_asset_fee(_: Weight, _: VersionedAssetId) -> Result { + fn query_weight_to_asset_fee(_: Weight, _: VersionedAssetId) -> Result { unimplemented!() } - fn query_xcm_weight(_: VersionedXcm<()>) -> Result { + fn query_xcm_weight(_: VersionedXcm<()>) -> Result { unimplemented!() } - fn query_delivery_fees(_: VersionedLocation, _: VersionedXcm<()>) -> Result { + fn query_delivery_fees(_: VersionedLocation, _: VersionedXcm<()>) -> Result { + unimplemented!() + } + } + + impl xcm_fee_payment_runtime_api::dry_run::XcmDryRunApi for Runtime { + fn dry_run_extrinsic(_: ::Extrinsic) -> Result, xcm_fee_payment_runtime_api::dry_run::Error> { + unimplemented!() + } + + fn dry_run_xcm(_: VersionedLocation, _: VersionedXcm<()>) -> Result, xcm_fee_payment_runtime_api::dry_run::Error> { unimplemented!() } } diff --git a/polkadot/node/service/src/lib.rs b/polkadot/node/service/src/lib.rs index 22231c84b1d9c377c24bf689e7c5a88d40dba62b..665533e9bc70a9173a5a9f6ff106657de07f859f 100644 --- a/polkadot/node/service/src/lib.rs +++ b/polkadot/node/service/src/lib.rs @@ -643,6 +643,13 @@ pub struct NewFullParams { pub workers_path: Option, /// Optional custom names for the prepare and execute workers. pub workers_names: Option<(String, String)>, + /// An optional number of the maximum number of pvf execute workers. + pub execute_workers_max_num: Option, + /// An optional maximum number of pvf workers that can be spawned in the pvf prepare pool for + /// tasks with the priority below critical. + pub prepare_workers_soft_max_num: Option, + /// An optional absolute number of pvf workers that can be spawned in the pvf prepare pool. + pub prepare_workers_hard_max_num: Option, pub overseer_gen: OverseerGenerator, pub overseer_message_channel_capacity_override: Option, #[allow(dead_code)] @@ -738,6 +745,9 @@ pub fn new_full< overseer_message_channel_capacity_override, malus_finality_delay: _malus_finality_delay, hwbench, + execute_workers_max_num, + prepare_workers_soft_max_num, + prepare_workers_hard_max_num, }: NewFullParams, ) -> Result { use polkadot_node_network_protocol::request_response::IncomingRequest; @@ -943,6 +953,16 @@ pub fn new_full< secure_validator_mode, prep_worker_path, exec_worker_path, + pvf_execute_workers_max_num: execute_workers_max_num.unwrap_or_else( + || match config.chain_spec.identify_chain() { + // The intention is to use this logic for gradual increasing from 2 to 4 + // of this configuration chain by chain until it reaches production chain. + Chain::Polkadot | Chain::Kusama => 2, + Chain::Rococo | Chain::Westend | Chain::Unknown => 4, + }, + ), + pvf_prepare_workers_soft_max_num: prepare_workers_soft_max_num.unwrap_or(1), + pvf_prepare_workers_hard_max_num: prepare_workers_hard_max_num.unwrap_or(2), }) } else { None diff --git a/polkadot/node/subsystem-bench/Cargo.toml b/polkadot/node/subsystem-bench/Cargo.toml index e534ac18e4b36bdb40737d4ad7052a008c0497e7..37c6681b273430ab4f3f5699e014491a50fbf88a 100644 --- a/polkadot/node/subsystem-bench/Cargo.toml +++ b/polkadot/node/subsystem-bench/Cargo.toml @@ -55,7 +55,7 @@ rand_distr = "0.4.3" bitvec = "1.0.1" kvdb-memorydb = "0.13.0" -parity-scale-codec = { version = "3.6.1", features = ["derive", "std"] } +parity-scale-codec = { version = "3.6.12", features = ["derive", "std"] } tokio = { version = "1.24.2", features = ["parking_lot", "rt-multi-thread"] } clap-num = "1.0.2" polkadot-node-subsystem-test-helpers = { path = "../subsystem-test-helpers" } @@ -66,7 +66,7 @@ sc-network-types = { path = "../../../substrate/client/network/types" } sc-service = { path = "../../../substrate/client/service" } sp-consensus = { path = "../../../substrate/primitives/consensus/common" } polkadot-node-metrics = { path = "../metrics" } -itertools = "0.11.0" +itertools = "0.11" 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 } diff --git a/polkadot/node/subsystem-bench/src/lib/approval/message_generator.rs b/polkadot/node/subsystem-bench/src/lib/approval/message_generator.rs index 219b2cb515d7da5df52df9902c0da28e09838763..e4a6c207970febc06fc364237e8f277728ec905e 100644 --- a/polkadot/node/subsystem-bench/src/lib/approval/message_generator.rs +++ b/polkadot/node/subsystem-bench/src/lib/approval/message_generator.rs @@ -91,7 +91,7 @@ pub struct PeerMessagesGenerator { impl PeerMessagesGenerator { /// 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. + /// the assignments/approvals and peer view changes at the beginning of each block. pub fn generate_messages(mut self, spawn_task_handle: &SpawnTaskHandle) { spawn_task_handle.spawn("generate-messages", "generate-messages", async move { for block_info in &self.blocks { diff --git a/polkadot/node/subsystem-bench/src/lib/approval/mod.rs b/polkadot/node/subsystem-bench/src/lib/approval/mod.rs index 6ab5b86baede30117489b892490dd14b415650e7..6ac0776d2d35a496be7737987988a68fd854d956 100644 --- a/polkadot/node/subsystem-bench/src/lib/approval/mod.rs +++ b/polkadot/node/subsystem-bench/src/lib/approval/mod.rs @@ -98,7 +98,7 @@ pub(crate) const TEST_CONFIG: ApprovalVotingConfig = ApprovalVotingConfig { const DATA_COL: u32 = 0; /// Start generating messages for a slot into the future, so that the -/// generation nevers falls behind the current slot. +/// generation never falls behind the current slot. const BUFFER_FOR_GENERATION_MILLIS: u64 = 30_000; /// Parameters specific to the approvals benchmark diff --git a/polkadot/node/subsystem-bench/src/lib/usage.rs b/polkadot/node/subsystem-bench/src/lib/usage.rs index 59296746ec3d4154274ce68d9ee910bb61d0f9f8..bfaac3265a2e3741aaa2fa4811785bd90e8ea016 100644 --- a/polkadot/node/subsystem-bench/src/lib/usage.rs +++ b/polkadot/node/subsystem-bench/src/lib/usage.rs @@ -161,6 +161,13 @@ impl ResourceUsage { 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; + let per_block_sd = + standard_deviation(&values.iter().map(|v| v.per_block).collect::>()); + println!( + "[{}] standart_deviation {:.2}%", + resource_name, + per_block_sd / per_block * 100.0 + ); average.push(Self { resource_name, total, per_block }); } average @@ -179,3 +186,11 @@ pub struct ChartItem { pub unit: String, pub value: f64, } + +fn standard_deviation(values: &[f64]) -> f64 { + let n = values.len() as f64; + let mean = values.iter().sum::() / n; + let variance = values.iter().map(|v| (v - mean).powi(2)).sum::() / (n - 1.0); + + variance.sqrt() +} diff --git a/polkadot/node/subsystem-types/src/messages.rs b/polkadot/node/subsystem-types/src/messages.rs index e75d80395c4ba0371b58ce1383db2a1f364eaad8..2a54b3aed301e7dcdcdaf87fe49775b43954a102 100644 --- a/polkadot/node/subsystem-types/src/messages.rs +++ b/polkadot/node/subsystem-types/src/messages.rs @@ -62,7 +62,7 @@ pub mod network_bridge_event; pub use network_bridge_event::NetworkBridgeEvent; /// A request to the candidate backing subsystem to check whether -/// there exists vacant membership in some fragment tree. +/// we can second this candidate. #[derive(Debug, Copy, Clone)] pub struct CanSecondRequest { /// Para id of the candidate. @@ -90,10 +90,12 @@ pub enum CandidateBackingMessage { oneshot::Sender>>, ), /// Request the subsystem to check whether it's allowed to second given candidate. - /// The rule is to only fetch collations that are either built on top of the root - /// of some fragment tree or have a parent node which represents backed candidate. + /// The rule is to only fetch collations that can either be directly chained to any + /// FragmentChain in the view or there is at least one FragmentChain where this candidate is a + /// potentially unconnected candidate (we predict that it may become connected to a + /// FragmentChain in the future). /// - /// Always responses with `false` if async backing is disabled for candidate's relay + /// Always responds with `false` if async backing is disabled for candidate's relay /// parent. CanSecond(CanSecondRequest, oneshot::Sender), /// Note that the Candidate Backing subsystem should second the given candidate in the context @@ -244,13 +246,6 @@ pub enum CollatorProtocolMessage { /// /// The hash is the relay parent. Seconded(Hash, SignedFullStatement), - /// The candidate received enough validity votes from the backing group. - Backed { - /// Candidate's para id. - para_id: ParaId, - /// Hash of the para head generated by candidate. - para_head: Hash, - }, } impl Default for CollatorProtocolMessage { @@ -1023,9 +1018,9 @@ pub enum GossipSupportMessage { NetworkBridgeUpdate(NetworkBridgeEvent), } -/// Request introduction of a candidate into the prospective parachains subsystem. +/// Request introduction of a seconded candidate into the prospective parachains subsystem. #[derive(Debug, PartialEq, Eq, Clone)] -pub struct IntroduceCandidateRequest { +pub struct IntroduceSecondedCandidateRequest { /// The para-id of the candidate. pub candidate_para: ParaId, /// The candidate receipt itself. @@ -1034,7 +1029,7 @@ pub struct IntroduceCandidateRequest { pub persisted_validation_data: PersistedValidationData, } -/// A hypothetical candidate to be evaluated for frontier membership +/// A hypothetical candidate to be evaluated for potential/actual membership /// in the prospective parachains subsystem. /// /// Hypothetical candidates are either complete or incomplete. @@ -1103,21 +1098,27 @@ impl HypotheticalCandidate { candidate_relay_parent, } } + + /// Get the output head data hash, if the candidate is complete. + pub fn output_head_data_hash(&self) -> Option { + match *self { + HypotheticalCandidate::Complete { ref receipt, .. } => + Some(receipt.descriptor.para_head), + HypotheticalCandidate::Incomplete { .. } => None, + } + } } /// Request specifying which candidates are either already included -/// or might be included in the hypothetical frontier of fragment trees -/// under a given active leaf. +/// or might become included in fragment chain under a given active leaf (or any active leaf if +/// `fragment_chain_relay_parent` is `None`). #[derive(Debug, PartialEq, Eq, Clone)] -pub struct HypotheticalFrontierRequest { +pub struct HypotheticalMembershipRequest { /// Candidates, in arbitrary order, which should be checked for - /// possible membership in fragment trees. + /// hypothetical/actual membership in fragment chains. pub candidates: Vec, - /// Either a specific fragment tree to check, otherwise all. - pub fragment_tree_relay_parent: Option, - /// Only return membership if all candidates in the path from the - /// root are backed. - pub backed_in_path_only: bool, + /// Either a specific fragment chain to check, otherwise all. + pub fragment_chain_relay_parent: Option, } /// A request for the persisted validation data stored in the prospective @@ -1156,9 +1157,9 @@ impl ParentHeadData { } } -/// Indicates the relay-parents whose fragment tree a candidate -/// is present in and the depths of that tree the candidate is present in. -pub type FragmentTreeMembership = Vec<(Hash, Vec)>; +/// Indicates the relay-parents whose fragment chain a candidate +/// is present in or can be added in (right now or in the future). +pub type HypotheticalMembership = Vec; /// A collection of ancestor candidates of a parachain. pub type Ancestors = HashSet; @@ -1166,15 +1167,11 @@ pub type Ancestors = HashSet; /// Messages sent to the Prospective Parachains subsystem. #[derive(Debug)] pub enum ProspectiveParachainsMessage { - /// Inform the Prospective Parachains Subsystem of a new candidate. + /// Inform the Prospective Parachains Subsystem of a new seconded candidate. /// - /// The response sender accepts the candidate membership, which is the existing - /// membership of the candidate if it was already known. - IntroduceCandidate(IntroduceCandidateRequest, oneshot::Sender), - /// Inform the Prospective Parachains Subsystem that a previously introduced candidate - /// has been seconded. This requires that the candidate was successfully introduced in - /// the past. - CandidateSeconded(ParaId, CandidateHash), + /// The response sender returns false if the candidate was rejected by prospective parachains, + /// true otherwise (if it was accepted or already present) + IntroduceSecondedCandidate(IntroduceSecondedCandidateRequest, oneshot::Sender), /// Inform the Prospective Parachains Subsystem that a previously introduced candidate /// has been backed. This requires that the candidate was successfully introduced in /// the past. @@ -1193,23 +1190,29 @@ pub enum ProspectiveParachainsMessage { Ancestors, oneshot::Sender>, ), - /// Get the hypothetical frontier membership of candidates with the given properties - /// under the specified active leaves' fragment trees. + /// Get the hypothetical or actual membership of candidates with the given properties + /// under the specified active leave's fragment chain. + /// + /// For each candidate, we return a vector of leaves where the candidate is present or could be + /// added. "Could be added" either means that the candidate can be added to the chain right now + /// or could be added in the future (we may not have its ancestors yet). + /// Note that even if we think it could be added in the future, we may find out that it was + /// invalid, as time passes. + /// If an active leaf is not in the vector, it means that there's no + /// chance this candidate will become valid under that leaf in the future. /// - /// For any candidate which is already known, this returns the depths the candidate - /// occupies. - GetHypotheticalFrontier( - HypotheticalFrontierRequest, - oneshot::Sender>, + /// If `fragment_chain_relay_parent` in the request is `Some()`, the return vector can only + /// contain this relay parent (or none). + GetHypotheticalMembership( + HypotheticalMembershipRequest, + oneshot::Sender>, ), - /// Get the membership of the candidate in all fragment trees. - GetTreeMembership(ParaId, CandidateHash, oneshot::Sender), - /// Get the minimum accepted relay-parent number for each para in the fragment tree + /// Get the minimum accepted relay-parent number for each para in the fragment chain /// for the given relay-chain block hash. /// /// That is, if the block hash is known and is an active leaf, this returns the /// minimum relay-parent block number in the same branch of the relay chain which - /// is accepted in the fragment tree for each para-id. + /// is accepted in the fragment chain for each para-id. /// /// If the block hash is not an active leaf, this will return an empty vector. /// @@ -1219,8 +1222,10 @@ pub enum ProspectiveParachainsMessage { /// Para-IDs are returned in no particular order. GetMinimumRelayParents(Hash, oneshot::Sender>), /// Get the validation data of some prospective candidate. The candidate doesn't need - /// to be part of any fragment tree, but this only succeeds if the parent head-data and - /// relay-parent are part of some fragment tree. + /// to be part of any fragment chain, but this only succeeds if the parent head-data and + /// relay-parent are part of the `CandidateStorage` (meaning that it's a candidate which is + /// part of some fragment chain or which prospective-parachains predicted will become part of + /// some fragment chain). GetProspectiveValidationData( ProspectiveValidationDataRequest, oneshot::Sender>, diff --git a/polkadot/node/subsystem-types/src/messages/network_bridge_event.rs b/polkadot/node/subsystem-types/src/messages/network_bridge_event.rs index fa2c7687b38a52ed1a02cdd1373ab5fd41552470..29798c785b9c97816017d8f3d4bbaf5cdc3585fe 100644 --- a/polkadot/node/subsystem-types/src/messages/network_bridge_event.rs +++ b/polkadot/node/subsystem-types/src/messages/network_bridge_event.rs @@ -14,7 +14,7 @@ // You should have received a copy of the GNU General Public License // along with Polkadot. If not, see . -use std::{collections::HashSet, convert::TryFrom}; +use std::collections::HashSet; pub use sc_network::ReputationChange; pub use sc_network_types::PeerId; diff --git a/polkadot/node/subsystem-util/Cargo.toml b/polkadot/node/subsystem-util/Cargo.toml index 79a6a75e4cdfb5cf644dc8f963e51d0ef49c1fcd..219ea4d3f57d0e513c04c4f567f6681555889ca6 100644 --- a/polkadot/node/subsystem-util/Cargo.toml +++ b/polkadot/node/subsystem-util/Cargo.toml @@ -13,13 +13,13 @@ workspace = true async-trait = "0.1.79" futures = "0.3.30" futures-channel = "0.3.23" -itertools = "0.10" -parity-scale-codec = { version = "3.6.1", default-features = false, features = ["derive"] } +itertools = "0.11" +parity-scale-codec = { version = "3.6.12", default-features = false, features = ["derive"] } parking_lot = "0.12.1" pin-project = "1.0.9" rand = "0.8.5" thiserror = { workspace = true } -fatality = "0.0.6" +fatality = "0.1.1" gum = { package = "tracing-gum", path = "../gum" } derive_more = "0.99.17" schnellru = "0.2.1" diff --git a/polkadot/node/subsystem-util/src/inclusion_emulator/mod.rs b/polkadot/node/subsystem-util/src/inclusion_emulator/mod.rs index d38d838fedefac643253528ab99d0035eeae55da..b5aef325c8b437ec43c2872f130651de65c28a52 100644 --- a/polkadot/node/subsystem-util/src/inclusion_emulator/mod.rs +++ b/polkadot/node/subsystem-util/src/inclusion_emulator/mod.rs @@ -39,8 +39,8 @@ /// /// # Usage /// -/// It's expected that the users of this module will be building up trees of -/// [`Fragment`]s and consistently pruning and adding to the tree. +/// It's expected that the users of this module will be building up chains of +/// [`Fragment`]s and consistently pruning and adding to the chains. /// /// ## Operating Constraints /// @@ -54,60 +54,65 @@ /// make an intelligent prediction about what might be accepted in the future based on /// prior fragments that also exist off-chain. /// -/// ## Fragment Trees +/// ## Fragment Chains +/// +/// For simplicity and practicality, we expect that collators of the same parachain are +/// cooperating and don't create parachain forks or cycles on the same relay chain active leaf. +/// Therefore, higher-level code should maintain one fragment chain for each active leaf (not a +/// fragment tree). If parachains do create forks, their performance in regards to async +/// backing and elastic scaling will suffer, because different validators will have different +/// predictions of the future. /// /// As the relay-chain grows, some predictions come true and others come false. /// And new predictions get made. These three changes correspond distinctly to the -/// 3 primary operations on fragment trees. -/// -/// A fragment tree is a mental model for thinking about a forking series of predictions -/// about a single parachain. There may be one or more fragment trees per parachain. -/// -/// In expectation, most parachains will have a plausibly-unique authorship method which means -/// that they should really be much closer to fragment-chains, maybe with an occasional fork. +/// 3 primary operations on fragment chains. /// -/// Avoiding fragment-tree blowup is beyond the scope of this module. +/// Avoiding fragment-chain blowup is beyond the scope of this module. Higher-level must ensure +/// proper spam protection. /// -/// ### Pruning Fragment Trees +/// ### Pruning Fragment Chains /// /// When the relay-chain advances, we want to compare the new constraints of that relay-parent -/// to the roots of the fragment trees we have. There are 3 cases: +/// to the root of the fragment chain we have. There are 3 cases: /// /// 1. The root fragment is still valid under the new constraints. In this case, we do nothing. -/// This is the "prediction still uncertain" case. +/// This is the "prediction still uncertain" case. (Corresponds to some candidates still +/// being pending availability). /// -/// 2. The root fragment is invalid under the new constraints because it has been subsumed by -/// the relay-chain. In this case, we can discard the root and split & re-root the fragment -/// tree under its descendants and compare to the new constraints again. This is the -/// "prediction came true" case. +/// 2. The root fragment (potentially along with a number of descendants) is invalid under the +/// new constraints because it has been included by the relay-chain. In this case, we can +/// discard the included chain and split & re-root the chain under its descendants and +/// compare to the new constraints again. This is the "prediction came true" case. /// -/// 3. The root fragment is invalid under the new constraints because a competing parachain -/// block has been included or it would never be accepted for some other reason. In this -/// case we can discard the entire fragment tree. This is the "prediction came false" case. +/// 3. The root fragment becomes invalid under the new constraints for any reason (if for +/// example the parachain produced a fork and the block producer picked a different +/// candidate to back). In this case we can discard the entire fragment chain. This is the +/// "prediction came false" case. /// /// This is all a bit of a simplification because it assumes that the relay-chain advances -/// without forks and is finalized instantly. In practice, the set of fragment-trees needs to +/// without forks and is finalized instantly. In practice, the set of fragment-chains needs to /// be observable from the perspective of a few different possible forks of the relay-chain and /// not pruned too eagerly. /// /// Note that the fragments themselves don't need to change and the only thing we care about /// is whether the predictions they represent are still valid. /// -/// ### Extending Fragment Trees +/// ### Extending Fragment Chains /// /// As predictions fade into the past, new ones should be stacked on top. /// /// Every new relay-chain block is an opportunity to make a new prediction about the future. -/// Higher-level logic should select the leaves of the fragment-trees to build upon or whether -/// to create a new fragment-tree. +/// Higher-level logic should decide whether to build upon an existing chain or whether +/// to create a new fragment-chain. /// /// ### Code Upgrades /// /// Code upgrades are the main place where this emulation fails. The on-chain PVF upgrade /// scheduling logic is very path-dependent and intricate so we just assume that code upgrades -/// can't be initiated and applied within a single fragment-tree. Fragment-trees aren't deep, -/// in practice and code upgrades are fairly rare. So what's likely to happen around code -/// upgrades is that the entire fragment-tree has to get discarded at some point. +/// can't be initiated and applied within a single fragment-chain. Fragment-chains aren't deep, +/// in practice (bounded by a linear function of the the number of cores assigned to a +/// parachain) and code upgrades are fairly rare. So what's likely to happen around code +/// upgrades is that the entire fragment-chain has to get discarded at some point. /// /// That means a few blocks of execution time lost, which is not a big deal for code upgrades /// in practice at most once every few weeks. @@ -116,10 +121,7 @@ use polkadot_primitives::{ CollatorId, CollatorSignature, Hash, HeadData, Id as ParaId, PersistedValidationData, UpgradeRestriction, ValidationCodeHash, }; -use std::{ - borrow::{Borrow, Cow}, - collections::HashMap, -}; +use std::{collections::HashMap, sync::Arc}; /// Constraints on inbound HRMP channels. #[derive(Debug, Clone, PartialEq)] @@ -524,9 +526,9 @@ impl ConstraintModifications { /// here. But the erasure-root is not. This means that prospective candidates /// are not correlated to any session in particular. #[derive(Debug, Clone, PartialEq)] -pub struct ProspectiveCandidate<'a> { +pub struct ProspectiveCandidate { /// The commitments to the output of the execution. - pub commitments: Cow<'a, CandidateCommitments>, + pub commitments: CandidateCommitments, /// The collator that created the candidate. pub collator: CollatorId, /// The signature of the collator on the payload. @@ -539,32 +541,6 @@ pub struct ProspectiveCandidate<'a> { pub validation_code_hash: ValidationCodeHash, } -impl<'a> ProspectiveCandidate<'a> { - fn into_owned(self) -> ProspectiveCandidate<'static> { - ProspectiveCandidate { commitments: Cow::Owned(self.commitments.into_owned()), ..self } - } - - /// Partially clone the prospective candidate, but borrow the - /// parts which are potentially heavy. - pub fn partial_clone(&self) -> ProspectiveCandidate { - ProspectiveCandidate { - commitments: Cow::Borrowed(self.commitments.borrow()), - collator: self.collator.clone(), - collator_signature: self.collator_signature.clone(), - persisted_validation_data: self.persisted_validation_data.clone(), - pov_hash: self.pov_hash, - validation_code_hash: self.validation_code_hash, - } - } -} - -#[cfg(test)] -impl ProspectiveCandidate<'static> { - fn commitments_mut(&mut self) -> &mut CandidateCommitments { - self.commitments.to_mut() - } -} - /// Kinds of errors with the validity of a fragment. #[derive(Debug, Clone, PartialEq)] pub enum FragmentValidityError { @@ -618,19 +594,19 @@ pub enum FragmentValidityError { /// This is a type which guarantees that the candidate is valid under the /// operating constraints. #[derive(Debug, Clone, PartialEq)] -pub struct Fragment<'a> { +pub struct Fragment { /// The new relay-parent. relay_parent: RelayChainBlockInfo, /// The constraints this fragment is operating under. operating_constraints: Constraints, /// The core information about the prospective candidate. - candidate: ProspectiveCandidate<'a>, + candidate: Arc, /// Modifications to the constraints based on the outputs of /// the candidate. modifications: ConstraintModifications, } -impl<'a> Fragment<'a> { +impl Fragment { /// Create a new fragment. /// /// This fails if the fragment isn't in line with the operating @@ -642,10 +618,29 @@ impl<'a> Fragment<'a> { pub fn new( relay_parent: RelayChainBlockInfo, operating_constraints: Constraints, - candidate: ProspectiveCandidate<'a>, + candidate: Arc, ) -> Result { + let modifications = Self::check_against_constraints( + &relay_parent, + &operating_constraints, + &candidate.commitments, + &candidate.validation_code_hash, + &candidate.persisted_validation_data, + )?; + + Ok(Fragment { relay_parent, operating_constraints, candidate, modifications }) + } + + /// Check the candidate against the operating constrains and return the constraint modifications + /// made by this candidate. + pub fn check_against_constraints( + relay_parent: &RelayChainBlockInfo, + operating_constraints: &Constraints, + commitments: &CandidateCommitments, + validation_code_hash: &ValidationCodeHash, + persisted_validation_data: &PersistedValidationData, + ) -> Result { let modifications = { - let commitments = &candidate.commitments; ConstraintModifications { required_parent: Some(commitments.head_data.clone()), hrmp_watermark: Some({ @@ -689,11 +684,13 @@ impl<'a> Fragment<'a> { validate_against_constraints( &operating_constraints, &relay_parent, - &candidate, + commitments, + persisted_validation_data, + validation_code_hash, &modifications, )?; - Ok(Fragment { relay_parent, operating_constraints, candidate, modifications }) + Ok(modifications) } /// Access the relay parent information. @@ -707,7 +704,7 @@ impl<'a> Fragment<'a> { } /// Access the underlying prospective candidate. - pub fn candidate(&self) -> &ProspectiveCandidate<'a> { + pub fn candidate(&self) -> &ProspectiveCandidate { &self.candidate } @@ -715,31 +712,14 @@ impl<'a> Fragment<'a> { pub fn constraint_modifications(&self) -> &ConstraintModifications { &self.modifications } - - /// Convert the fragment into an owned variant. - pub fn into_owned(self) -> Fragment<'static> { - Fragment { candidate: self.candidate.into_owned(), ..self } - } - - /// Validate this fragment against some set of constraints - /// instead of the operating constraints. - pub fn validate_against_constraints( - &self, - constraints: &Constraints, - ) -> Result<(), FragmentValidityError> { - validate_against_constraints( - constraints, - &self.relay_parent, - &self.candidate, - &self.modifications, - ) - } } fn validate_against_constraints( constraints: &Constraints, relay_parent: &RelayChainBlockInfo, - candidate: &ProspectiveCandidate, + commitments: &CandidateCommitments, + persisted_validation_data: &PersistedValidationData, + validation_code_hash: &ValidationCodeHash, modifications: &ConstraintModifications, ) -> Result<(), FragmentValidityError> { let expected_pvd = PersistedValidationData { @@ -749,17 +729,17 @@ fn validate_against_constraints( max_pov_size: constraints.max_pov_size as u32, }; - if expected_pvd != candidate.persisted_validation_data { + if expected_pvd != *persisted_validation_data { return Err(FragmentValidityError::PersistedValidationDataMismatch( expected_pvd, - candidate.persisted_validation_data.clone(), + persisted_validation_data.clone(), )) } - if constraints.validation_code_hash != candidate.validation_code_hash { + if constraints.validation_code_hash != *validation_code_hash { return Err(FragmentValidityError::ValidationCodeMismatch( constraints.validation_code_hash, - candidate.validation_code_hash, + *validation_code_hash, )) } @@ -770,7 +750,7 @@ fn validate_against_constraints( )) } - if candidate.commitments.new_validation_code.is_some() { + if commitments.new_validation_code.is_some() { match constraints.upgrade_restriction { None => {}, Some(UpgradeRestriction::Present) => @@ -778,11 +758,8 @@ fn validate_against_constraints( } } - let announced_code_size = candidate - .commitments - .new_validation_code - .as_ref() - .map_or(0, |code| code.0.len()); + let announced_code_size = + commitments.new_validation_code.as_ref().map_or(0, |code| code.0.len()); if announced_code_size > constraints.max_code_size { return Err(FragmentValidityError::CodeSizeTooLarge( @@ -801,17 +778,17 @@ fn validate_against_constraints( } } - if candidate.commitments.horizontal_messages.len() > constraints.max_hrmp_num_per_candidate { + if commitments.horizontal_messages.len() > constraints.max_hrmp_num_per_candidate { return Err(FragmentValidityError::HrmpMessagesPerCandidateOverflow { messages_allowed: constraints.max_hrmp_num_per_candidate, - messages_submitted: candidate.commitments.horizontal_messages.len(), + messages_submitted: commitments.horizontal_messages.len(), }) } - if candidate.commitments.upward_messages.len() > constraints.max_ump_num_per_candidate { + if commitments.upward_messages.len() > constraints.max_ump_num_per_candidate { return Err(FragmentValidityError::UmpMessagesPerCandidateOverflow { messages_allowed: constraints.max_ump_num_per_candidate, - messages_submitted: candidate.commitments.upward_messages.len(), + messages_submitted: commitments.upward_messages.len(), }) } @@ -1184,21 +1161,21 @@ mod tests { fn make_candidate( constraints: &Constraints, relay_parent: &RelayChainBlockInfo, - ) -> ProspectiveCandidate<'static> { + ) -> ProspectiveCandidate { let collator_pair = CollatorPair::generate().0; let collator = collator_pair.public(); let sig = collator_pair.sign(b"blabla".as_slice()); ProspectiveCandidate { - commitments: Cow::Owned(CandidateCommitments { + commitments: CandidateCommitments { upward_messages: Default::default(), horizontal_messages: Default::default(), new_validation_code: None, head_data: HeadData::from(vec![1, 2, 3, 4, 5]), processed_downward_messages: 0, hrmp_watermark: relay_parent.number, - }), + }, collator, collator_signature: sig, persisted_validation_data: PersistedValidationData { @@ -1229,7 +1206,7 @@ mod tests { candidate.validation_code_hash = got_code; assert_eq!( - Fragment::new(relay_parent, constraints, candidate), + Fragment::new(relay_parent, constraints, Arc::new(candidate.clone())), Err(FragmentValidityError::ValidationCodeMismatch(expected_code, got_code,)), ) } @@ -1261,7 +1238,7 @@ mod tests { let got_pvd = candidate.persisted_validation_data.clone(); assert_eq!( - Fragment::new(relay_parent_b, constraints, candidate), + Fragment::new(relay_parent_b, constraints, Arc::new(candidate.clone())), Err(FragmentValidityError::PersistedValidationDataMismatch(expected_pvd, got_pvd,)), ); } @@ -1278,10 +1255,10 @@ mod tests { let mut candidate = make_candidate(&constraints, &relay_parent); let max_code_size = constraints.max_code_size; - candidate.commitments_mut().new_validation_code = Some(vec![0; max_code_size + 1].into()); + candidate.commitments.new_validation_code = Some(vec![0; max_code_size + 1].into()); assert_eq!( - Fragment::new(relay_parent, constraints, candidate), + Fragment::new(relay_parent, constraints, Arc::new(candidate.clone())), Err(FragmentValidityError::CodeSizeTooLarge(max_code_size, max_code_size + 1,)), ); } @@ -1298,7 +1275,7 @@ mod tests { let candidate = make_candidate(&constraints, &relay_parent); assert_eq!( - Fragment::new(relay_parent, constraints, candidate), + Fragment::new(relay_parent, constraints, Arc::new(candidate.clone())), Err(FragmentValidityError::RelayParentTooOld(5, 3,)), ); } @@ -1317,7 +1294,7 @@ mod tests { let max_hrmp = constraints.max_hrmp_num_per_candidate; candidate - .commitments_mut() + .commitments .horizontal_messages .try_extend((0..max_hrmp + 1).map(|i| OutboundHrmpMessage { recipient: ParaId::from(i as u32), @@ -1326,7 +1303,7 @@ mod tests { .unwrap(); assert_eq!( - Fragment::new(relay_parent, constraints, candidate), + Fragment::new(relay_parent, constraints, Arc::new(candidate.clone())), Err(FragmentValidityError::HrmpMessagesPerCandidateOverflow { messages_allowed: max_hrmp, messages_submitted: max_hrmp + 1, @@ -1346,22 +1323,36 @@ mod tests { let mut candidate = make_candidate(&constraints, &relay_parent); // Empty dmp queue is ok. - assert!(Fragment::new(relay_parent.clone(), constraints.clone(), candidate.clone()).is_ok()); + assert!(Fragment::new( + relay_parent.clone(), + constraints.clone(), + Arc::new(candidate.clone()) + ) + .is_ok()); // Unprocessed message that was sent later is ok. constraints.dmp_remaining_messages = vec![relay_parent.number + 1]; - assert!(Fragment::new(relay_parent.clone(), constraints.clone(), candidate.clone()).is_ok()); + assert!(Fragment::new( + relay_parent.clone(), + constraints.clone(), + Arc::new(candidate.clone()) + ) + .is_ok()); for block_number in 0..=relay_parent.number { constraints.dmp_remaining_messages = vec![block_number]; assert_eq!( - Fragment::new(relay_parent.clone(), constraints.clone(), candidate.clone()), + Fragment::new( + relay_parent.clone(), + constraints.clone(), + Arc::new(candidate.clone()) + ), Err(FragmentValidityError::DmpAdvancementRule), ); } - candidate.commitments.to_mut().processed_downward_messages = 1; - assert!(Fragment::new(relay_parent, constraints, candidate).is_ok()); + candidate.commitments.processed_downward_messages = 1; + assert!(Fragment::new(relay_parent, constraints, Arc::new(candidate.clone())).is_ok()); } #[test] @@ -1379,13 +1370,12 @@ mod tests { candidate .commitments - .to_mut() .upward_messages .try_extend((0..max_ump + 1).map(|i| vec![i as u8])) .unwrap(); assert_eq!( - Fragment::new(relay_parent, constraints, candidate), + Fragment::new(relay_parent, constraints, Arc::new(candidate.clone())), Err(FragmentValidityError::UmpMessagesPerCandidateOverflow { messages_allowed: max_ump, messages_submitted: max_ump + 1, @@ -1405,10 +1395,10 @@ mod tests { let mut candidate = make_candidate(&constraints, &relay_parent); constraints.upgrade_restriction = Some(UpgradeRestriction::Present); - candidate.commitments_mut().new_validation_code = Some(ValidationCode(vec![1, 2, 3])); + candidate.commitments.new_validation_code = Some(ValidationCode(vec![1, 2, 3])); assert_eq!( - Fragment::new(relay_parent, constraints, candidate), + Fragment::new(relay_parent, constraints, Arc::new(candidate.clone())), Err(FragmentValidityError::CodeUpgradeRestricted), ); } @@ -1424,23 +1414,23 @@ mod tests { let constraints = make_constraints(); let mut candidate = make_candidate(&constraints, &relay_parent); - candidate.commitments_mut().horizontal_messages = HorizontalMessages::truncate_from(vec![ + candidate.commitments.horizontal_messages = HorizontalMessages::truncate_from(vec![ OutboundHrmpMessage { recipient: ParaId::from(0 as u32), data: vec![1, 2, 3] }, OutboundHrmpMessage { recipient: ParaId::from(0 as u32), data: vec![4, 5, 6] }, ]); assert_eq!( - Fragment::new(relay_parent.clone(), constraints.clone(), candidate.clone()), + Fragment::new(relay_parent.clone(), constraints.clone(), Arc::new(candidate.clone())), Err(FragmentValidityError::HrmpMessagesDescendingOrDuplicate(1)), ); - candidate.commitments_mut().horizontal_messages = HorizontalMessages::truncate_from(vec![ + candidate.commitments.horizontal_messages = HorizontalMessages::truncate_from(vec![ OutboundHrmpMessage { recipient: ParaId::from(1 as u32), data: vec![1, 2, 3] }, OutboundHrmpMessage { recipient: ParaId::from(0 as u32), data: vec![4, 5, 6] }, ]); assert_eq!( - Fragment::new(relay_parent, constraints, candidate), + Fragment::new(relay_parent, constraints, Arc::new(candidate.clone())), Err(FragmentValidityError::HrmpMessagesDescendingOrDuplicate(1)), ); } diff --git a/polkadot/node/test/client/Cargo.toml b/polkadot/node/test/client/Cargo.toml index 7db00404eb8eca049a6194d19e5e92e66325628c..55d4d81d1c21bbb5007962ac71c8d38fe898d49b 100644 --- a/polkadot/node/test/client/Cargo.toml +++ b/polkadot/node/test/client/Cargo.toml @@ -10,7 +10,7 @@ license.workspace = true workspace = true [dependencies] -parity-scale-codec = { version = "3.6.1", default-features = false, features = ["derive"] } +parity-scale-codec = { version = "3.6.12", default-features = false, features = ["derive"] } # Polkadot dependencies polkadot-test-runtime = { path = "../../../runtime/test-runtime" } diff --git a/polkadot/node/test/service/src/lib.rs b/polkadot/node/test/service/src/lib.rs index d313c19333483095291b09c79103d681961dbff6..35156a3a9372b54cf438fe086d3642b8fd55992d 100644 --- a/polkadot/node/test/service/src/lib.rs +++ b/polkadot/node/test/service/src/lib.rs @@ -97,6 +97,9 @@ pub fn new_full( overseer_message_channel_capacity_override: None, malus_finality_delay: None, hwbench: None, + execute_workers_max_num: None, + prepare_workers_hard_max_num: None, + prepare_workers_soft_max_num: None, }, ), sc_network::config::NetworkBackendType::Litep2p => @@ -116,6 +119,9 @@ pub fn new_full( overseer_message_channel_capacity_override: None, malus_finality_delay: None, hwbench: None, + execute_workers_max_num: None, + prepare_workers_hard_max_num: None, + prepare_workers_soft_max_num: None, }, ), } @@ -210,6 +216,8 @@ pub fn node_config( rpc_message_buffer_capacity: Default::default(), rpc_batch_config: RpcBatchRequestConfig::Unlimited, rpc_rate_limit: None, + rpc_rate_limit_whitelisted_ips: Default::default(), + rpc_rate_limit_trust_proxy_headers: Default::default(), prometheus_config: None, telemetry_endpoints: None, default_heap_pages: None, diff --git a/polkadot/node/zombienet-backchannel/Cargo.toml b/polkadot/node/zombienet-backchannel/Cargo.toml index fa99490a997434eedee977121f13d8dcc1a9b5a1..a0233bb46e5128b1b036a6fa7dd0181e587f1e9a 100644 --- a/polkadot/node/zombienet-backchannel/Cargo.toml +++ b/polkadot/node/zombienet-backchannel/Cargo.toml @@ -14,10 +14,10 @@ workspace = true [dependencies] tokio = { version = "1.24.2", default-features = false, features = ["macros", "net", "rt-multi-thread", "sync"] } url = "2.3.1" -tokio-tungstenite = "0.17" +tokio-tungstenite = "0.20.1" futures-util = "0.3.30" lazy_static = "1.4.0" -parity-scale-codec = { version = "3.6.1", features = ["derive"] } +parity-scale-codec = { version = "3.6.12", features = ["derive"] } reqwest = { version = "0.11", features = ["rustls-tls"], default-features = false } thiserror = { workspace = true } gum = { package = "tracing-gum", path = "../gum" } diff --git a/polkadot/parachain/Cargo.toml b/polkadot/parachain/Cargo.toml index 15eea2addc893ced551edaf2557ff703a455a879..1344baac64b65246945b3bd09569cf21990fde5e 100644 --- a/polkadot/parachain/Cargo.toml +++ b/polkadot/parachain/Cargo.toml @@ -13,7 +13,7 @@ workspace = true # note: special care is taken to avoid inclusion of `sp-io` externals when compiling # this crate for WASM. This is critical to avoid forcing all parachain WASM into implementing # various unnecessary Substrate-specific endpoints. -parity-scale-codec = { version = "3.6.1", default-features = false, features = ["derive"] } +parity-scale-codec = { version = "3.6.12", default-features = false, features = ["derive"] } scale-info = { version = "2.11.1", default-features = false, features = ["derive", "serde"] } sp-std = { path = "../../substrate/primitives/std", default-features = false } sp-runtime = { path = "../../substrate/primitives/runtime", default-features = false, features = ["serde"] } diff --git a/polkadot/parachain/src/primitives.rs b/polkadot/parachain/src/primitives.rs index 5a1efdf898217a18972cab8c9ea49a41e5a2280f..2764384363727a8b7b350b02441903204eae717f 100644 --- a/polkadot/parachain/src/primitives.rs +++ b/polkadot/parachain/src/primitives.rs @@ -333,7 +333,19 @@ impl DmpMessageHandler for () { } /// The aggregate XCMP message format. -#[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Encode, Decode, TypeInfo, RuntimeDebug)] +#[derive( + Copy, + Clone, + Eq, + PartialEq, + Ord, + PartialOrd, + Encode, + Decode, + TypeInfo, + RuntimeDebug, + MaxEncodedLen, +)] pub enum XcmpMessageFormat { /// Encoded `VersionedXcm` messages, all concatenated. ConcatenatedVersionedXcm, diff --git a/polkadot/parachain/test-parachains/Cargo.toml b/polkadot/parachain/test-parachains/Cargo.toml index 6acdedf67ff2e4be34da2caa70c572a41f861eca..22f3d2942e0c2076cae4e9e37a6d960b42969860 100644 --- a/polkadot/parachain/test-parachains/Cargo.toml +++ b/polkadot/parachain/test-parachains/Cargo.toml @@ -12,7 +12,7 @@ workspace = true [dependencies] tiny-keccak = { version = "2.0.2", features = ["keccak"] } -parity-scale-codec = { version = "3.6.1", default-features = false, features = ["derive"] } +parity-scale-codec = { version = "3.6.12", default-features = false, features = ["derive"] } adder = { package = "test-parachain-adder", path = "adder" } halt = { package = "test-parachain-halt", path = "halt" } diff --git a/polkadot/parachain/test-parachains/adder/Cargo.toml b/polkadot/parachain/test-parachains/adder/Cargo.toml index eec19ef788aad510d7ea9ef6d2ab61d7c6aeb8f9..273fa93a50f412ffc282aeeafb07c0e173fd5e72 100644 --- a/polkadot/parachain/test-parachains/adder/Cargo.toml +++ b/polkadot/parachain/test-parachains/adder/Cargo.toml @@ -13,7 +13,7 @@ workspace = true [dependencies] parachain = { package = "polkadot-parachain-primitives", path = "../..", default-features = false, features = ["wasm-api"] } -parity-scale-codec = { version = "3.6.1", default-features = false, features = ["derive"] } +parity-scale-codec = { version = "3.6.12", default-features = false, features = ["derive"] } sp-std = { path = "../../../../substrate/primitives/std", default-features = false } tiny-keccak = { version = "2.0.2", features = ["keccak"] } dlmalloc = { version = "0.2.4", features = ["global"] } diff --git a/polkadot/parachain/test-parachains/adder/collator/Cargo.toml b/polkadot/parachain/test-parachains/adder/collator/Cargo.toml index 5a2b5405741446f52e5f1212de2665ab04d350d2..dbc8507d599bb5e7899a8ee99450e95e4c480618 100644 --- a/polkadot/parachain/test-parachains/adder/collator/Cargo.toml +++ b/polkadot/parachain/test-parachains/adder/collator/Cargo.toml @@ -15,7 +15,7 @@ name = "adder-collator" path = "src/main.rs" [dependencies] -parity-scale-codec = { version = "3.6.1", default-features = false, features = ["derive"] } +parity-scale-codec = { version = "3.6.12", default-features = false, features = ["derive"] } clap = { version = "4.5.3", features = ["derive"] } futures = "0.3.30" futures-timer = "3.0.2" diff --git a/polkadot/parachain/test-parachains/adder/collator/src/main.rs b/polkadot/parachain/test-parachains/adder/collator/src/main.rs index fec90fc41cdb160f1a90a8ceab7a15da81e96bb2..e8588274df27aad40820d0a73e70ec5d24a89fb6 100644 --- a/polkadot/parachain/test-parachains/adder/collator/src/main.rs +++ b/polkadot/parachain/test-parachains/adder/collator/src/main.rs @@ -95,6 +95,9 @@ fn main() -> Result<()> { overseer_message_channel_capacity_override: None, malus_finality_delay: None, hwbench: None, + execute_workers_max_num: None, + prepare_workers_hard_max_num: None, + prepare_workers_soft_max_num: None, }, ) .map_err(|e| e.to_string())?; diff --git a/polkadot/parachain/test-parachains/undying/Cargo.toml b/polkadot/parachain/test-parachains/undying/Cargo.toml index 82ceebcf4eee99f36140908580b41c13b04ea87e..f2067a2c3b9bdc3c7e585fbb03fc79ee435f7d1d 100644 --- a/polkadot/parachain/test-parachains/undying/Cargo.toml +++ b/polkadot/parachain/test-parachains/undying/Cargo.toml @@ -13,7 +13,7 @@ workspace = true [dependencies] parachain = { package = "polkadot-parachain-primitives", path = "../..", default-features = false, features = ["wasm-api"] } -parity-scale-codec = { version = "3.6.1", default-features = false, features = ["derive"] } +parity-scale-codec = { version = "3.6.12", default-features = false, features = ["derive"] } sp-std = { path = "../../../../substrate/primitives/std", default-features = false } tiny-keccak = { version = "2.0.2", features = ["keccak"] } dlmalloc = { version = "0.2.4", features = ["global"] } diff --git a/polkadot/parachain/test-parachains/undying/collator/Cargo.toml b/polkadot/parachain/test-parachains/undying/collator/Cargo.toml index cacf7304f90a29d39848b80a58159afbbb6cb3e5..28efdbbf242f7879615928bb228a4975b54c2d0c 100644 --- a/polkadot/parachain/test-parachains/undying/collator/Cargo.toml +++ b/polkadot/parachain/test-parachains/undying/collator/Cargo.toml @@ -15,7 +15,7 @@ name = "undying-collator" path = "src/main.rs" [dependencies] -parity-scale-codec = { version = "3.6.1", default-features = false, features = ["derive"] } +parity-scale-codec = { version = "3.6.12", default-features = false, features = ["derive"] } clap = { version = "4.5.3", features = ["derive"] } futures = "0.3.30" futures-timer = "3.0.2" diff --git a/polkadot/parachain/test-parachains/undying/collator/src/main.rs b/polkadot/parachain/test-parachains/undying/collator/src/main.rs index 45f21e7b859631ec8763304c18f01cf6f3d04d10..7198a831a4771b1a70de4180149ce81ffe6f5412 100644 --- a/polkadot/parachain/test-parachains/undying/collator/src/main.rs +++ b/polkadot/parachain/test-parachains/undying/collator/src/main.rs @@ -97,6 +97,9 @@ fn main() -> Result<()> { overseer_message_channel_capacity_override: None, malus_finality_delay: None, hwbench: None, + execute_workers_max_num: None, + prepare_workers_hard_max_num: None, + prepare_workers_soft_max_num: None, }, ) .map_err(|e| e.to_string())?; diff --git a/polkadot/primitives/Cargo.toml b/polkadot/primitives/Cargo.toml index 004fa62acf34595c548e0e36da1d05f0a52abb53..603d08b8fee524f803b32c751cdd818249687132 100644 --- a/polkadot/primitives/Cargo.toml +++ b/polkadot/primitives/Cargo.toml @@ -12,7 +12,7 @@ workspace = true [dependencies] bitvec = { version = "1.0.0", default-features = false, features = ["alloc", "serde"] } hex-literal = "0.4.1" -parity-scale-codec = { version = "3.6.1", default-features = false, features = ["bit-vec", "derive"] } +parity-scale-codec = { version = "3.6.12", default-features = false, features = ["bit-vec", "derive"] } scale-info = { version = "2.11.1", default-features = false, features = ["bit-vec", "derive", "serde"] } log = { workspace = true, default-features = false } serde = { features = ["alloc", "derive"], workspace = true } @@ -26,7 +26,7 @@ sp-arithmetic = { path = "../../substrate/primitives/arithmetic", default-featur sp-authority-discovery = { path = "../../substrate/primitives/authority-discovery", default-features = false, features = ["serde"] } sp-consensus-slots = { path = "../../substrate/primitives/consensus/slots", default-features = false, features = ["serde"] } sp-io = { path = "../../substrate/primitives/io", default-features = false } -sp-keystore = { path = "../../substrate/primitives/keystore", optional = true } +sp-keystore = { path = "../../substrate/primitives/keystore", optional = true, default-features = false } sp-staking = { path = "../../substrate/primitives/staking", default-features = false, features = ["serde"] } sp-std = { package = "sp-std", path = "../../substrate/primitives/std", default-features = false } @@ -53,6 +53,7 @@ std = [ "sp-consensus-slots/std", "sp-io/std", "sp-keystore", + "sp-keystore?/std", "sp-staking/std", "sp-std/std", ] diff --git a/polkadot/primitives/src/lib.rs b/polkadot/primitives/src/lib.rs index d4eeb3cc3d2951089213b924777cbcd9a979c1c9..01f393086a668f43d2e18abc10b4491f54aae2cf 100644 --- a/polkadot/primitives/src/lib.rs +++ b/polkadot/primitives/src/lib.rs @@ -44,7 +44,7 @@ pub use v7::{ CandidateReceipt, CheckedDisputeStatementSet, CheckedMultiDisputeStatementSet, CollatorId, CollatorSignature, CommittedCandidateReceipt, CompactStatement, ConsensusLog, CoreIndex, CoreState, DisputeState, DisputeStatement, DisputeStatementSet, DownwardMessage, EncodeAs, - ExecutorParam, ExecutorParamError, ExecutorParams, ExecutorParamsHash, + ExecutorParam, ExecutorParamError, ExecutorParams, ExecutorParamsHash, ExecutorParamsPrepHash, ExplicitDisputeStatement, GroupIndex, GroupRotationInfo, Hash, HashT, HeadData, Header, HorizontalMessages, HrmpChannelId, Id, InboundDownwardMessage, InboundHrmpMessage, IndexedVec, InherentData, InvalidDisputeStatementKind, Moment, MultiDisputeStatementSet, NodeFeatures, diff --git a/polkadot/primitives/src/v7/executor_params.rs b/polkadot/primitives/src/v7/executor_params.rs index 1e19f3b23fec9b9889d5976380f52ab6b66072b4..918a7f17a7e3ba466bd8e06cb635cfbf2f9df839 100644 --- a/polkadot/primitives/src/v7/executor_params.rs +++ b/polkadot/primitives/src/v7/executor_params.rs @@ -152,13 +152,42 @@ impl sp_std::fmt::LowerHex for ExecutorParamsHash { } } +/// Unit type wrapper around [`type@Hash`] that represents a hash of preparation-related +/// executor parameters. +/// +/// This type is produced by [`ExecutorParams::prep_hash`]. +#[derive(Clone, Copy, Encode, Decode, Hash, Eq, PartialEq, PartialOrd, Ord, TypeInfo)] +pub struct ExecutorParamsPrepHash(Hash); + +impl sp_std::fmt::Display for ExecutorParamsPrepHash { + fn fmt(&self, f: &mut sp_std::fmt::Formatter<'_>) -> sp_std::fmt::Result { + self.0.fmt(f) + } +} + +impl sp_std::fmt::Debug for ExecutorParamsPrepHash { + fn fmt(&self, f: &mut sp_std::fmt::Formatter<'_>) -> sp_std::fmt::Result { + write!(f, "{:?}", self.0) + } +} + +impl sp_std::fmt::LowerHex for ExecutorParamsPrepHash { + fn fmt(&self, f: &mut sp_std::fmt::Formatter<'_>) -> sp_std::fmt::Result { + sp_std::fmt::LowerHex::fmt(&self.0, f) + } +} + /// # Deterministically serialized execution environment semantics /// Represents an arbitrary semantics of an arbitrary execution environment, so should be kept as /// abstract as possible. +// // ADR: For mandatory entries, mandatoriness should be enforced in code rather than separating them // 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. +// +// !!! Any new parameter that does not affect the prepared artifact must be added to the exclusion +// !!! list in `prep_hash()` to avoid unneccessary artifact rebuilds. #[derive( Clone, Debug, Default, Encode, Decode, PartialEq, Eq, TypeInfo, Serialize, Deserialize, )] @@ -175,6 +204,28 @@ impl ExecutorParams { ExecutorParamsHash(BlakeTwo256::hash(&self.encode())) } + /// Returns hash of preparation-related executor parameters + pub fn prep_hash(&self) -> ExecutorParamsPrepHash { + use ExecutorParam::*; + + let mut enc = b"prep".to_vec(); + + self.0 + .iter() + .flat_map(|param| match param { + MaxMemoryPages(..) => None, + StackLogicalMax(..) => Some(param), + StackNativeMax(..) => None, + PrecheckingMaxMemory(..) => None, + PvfPrepTimeout(..) => Some(param), + PvfExecTimeout(..) => None, + WasmExtBulkMemory => Some(param), + }) + .for_each(|p| enc.extend(p.encode())); + + ExecutorParamsPrepHash(BlakeTwo256::hash(&enc)) + } + /// Returns a PVF preparation timeout, if any pub fn pvf_prep_timeout(&self, kind: PvfPrepKind) -> Option { for param in &self.0 { @@ -336,3 +387,51 @@ impl From<&[ExecutorParam]> for ExecutorParams { ExecutorParams(arr.to_vec()) } } + +// This test ensures the hash generated by `prep_hash()` changes if any preparation-related +// executor parameter changes. If you're adding a new executor parameter, you must add it into +// this test, and if changing that parameter may not affect the artifact produced on the +// preparation step, it must be added to the list of exlusions in `pre_hash()` as well. +// See also `prep_hash()` comments. +#[test] +fn ensure_prep_hash_changes() { + use ExecutorParam::*; + let ep = ExecutorParams::from( + &[ + MaxMemoryPages(0), + StackLogicalMax(0), + StackNativeMax(0), + PrecheckingMaxMemory(0), + PvfPrepTimeout(PvfPrepKind::Precheck, 0), + PvfPrepTimeout(PvfPrepKind::Prepare, 0), + PvfExecTimeout(PvfExecKind::Backing, 0), + PvfExecTimeout(PvfExecKind::Approval, 0), + WasmExtBulkMemory, + ][..], + ); + + for p in ep.iter() { + let (ep1, ep2) = match p { + MaxMemoryPages(_) => continue, + StackLogicalMax(_) => ( + ExecutorParams::from(&[StackLogicalMax(1)][..]), + ExecutorParams::from(&[StackLogicalMax(2)][..]), + ), + StackNativeMax(_) => continue, + PrecheckingMaxMemory(_) => continue, + PvfPrepTimeout(PvfPrepKind::Precheck, _) => ( + ExecutorParams::from(&[PvfPrepTimeout(PvfPrepKind::Precheck, 1)][..]), + ExecutorParams::from(&[PvfPrepTimeout(PvfPrepKind::Precheck, 2)][..]), + ), + PvfPrepTimeout(PvfPrepKind::Prepare, _) => ( + ExecutorParams::from(&[PvfPrepTimeout(PvfPrepKind::Prepare, 1)][..]), + ExecutorParams::from(&[PvfPrepTimeout(PvfPrepKind::Prepare, 2)][..]), + ), + PvfExecTimeout(_, _) => continue, + WasmExtBulkMemory => + (ExecutorParams::default(), ExecutorParams::from(&[WasmExtBulkMemory][..])), + }; + + assert_ne!(ep1.prep_hash(), ep2.prep_hash()); + } +} diff --git a/polkadot/primitives/src/v7/mod.rs b/polkadot/primitives/src/v7/mod.rs index 5647bfe68d5667c17f23a684ba97d8ce271fcb26..8a059408496c0f87e2d1394beb84263f48c4fbda 100644 --- a/polkadot/primitives/src/v7/mod.rs +++ b/polkadot/primitives/src/v7/mod.rs @@ -62,7 +62,9 @@ pub mod executor_params; pub mod slashing; pub use async_backing::AsyncBackingParams; -pub use executor_params::{ExecutorParam, ExecutorParamError, ExecutorParams, ExecutorParamsHash}; +pub use executor_params::{ + ExecutorParam, ExecutorParamError, ExecutorParams, ExecutorParamsHash, ExecutorParamsPrepHash, +}; mod metrics; pub use metrics::{ diff --git a/polkadot/roadmap/implementers-guide/src/SUMMARY.md b/polkadot/roadmap/implementers-guide/src/SUMMARY.md index bb19390c7af4d422dfe62252a7153392c8ef534d..41485e5df8ec1f75bc04a54c5c21ef87a5ef4bb6 100644 --- a/polkadot/roadmap/implementers-guide/src/SUMMARY.md +++ b/polkadot/roadmap/implementers-guide/src/SUMMARY.md @@ -8,6 +8,7 @@ - [Disputes Process](protocol-disputes.md) - [Dispute Flow](disputes-flow.md) - [Chain Selection and Finalization](protocol-chain-selection.md) + - [Validator Disabling](protocol-validator-disabling.md) - [Architecture Overview](architecture.md) - [Messaging Overview](messaging.md) - [PVF Pre-checking](pvf-prechecking.md) diff --git a/polkadot/roadmap/implementers-guide/src/node/backing/prospective-parachains.md b/polkadot/roadmap/implementers-guide/src/node/backing/prospective-parachains.md index 8f00ff084941cc260dea6a9e76c0ff30d3770caf..701f6c87caff0341c36e4b2799d2444c015c411c 100644 --- a/polkadot/roadmap/implementers-guide/src/node/backing/prospective-parachains.md +++ b/polkadot/roadmap/implementers-guide/src/node/backing/prospective-parachains.md @@ -98,15 +98,11 @@ prospective validation data. This is unlikely to change. hashes. - Sent by the Provisioner when requesting backable candidates, when selecting candidates for a given relay-parent. -- `ProspectiveParachainsMessage::GetHypotheticalFrontier` +- `ProspectiveParachainsMessage::GetHypotheticalMembership` - Gets the hypothetical frontier membership of candidates with the given properties under the specified active leaves' fragment trees. - Sent by the Backing Subsystem when sanity-checking whether a candidate can be seconded based on its hypothetical frontiers. -- `ProspectiveParachainsMessage::GetTreeMembership` - - Gets the membership of the candidate in all fragment trees. - - Sent by the Backing Subsystem when it needs to update the candidates - seconded at various depths under new active leaves. - `ProspectiveParachainsMessage::GetMinimumRelayParents` - Gets the minimum accepted relay-parent number for each para in the fragment tree for the given relay-chain block hash. diff --git a/polkadot/roadmap/implementers-guide/src/node/backing/statement-distribution.md b/polkadot/roadmap/implementers-guide/src/node/backing/statement-distribution.md index e6e597c531787f46ced0a6f9e38e05817f2323d7..e5eb9bd7642c1108c45e73134a00ee22b2f6475c 100644 --- a/polkadot/roadmap/implementers-guide/src/node/backing/statement-distribution.md +++ b/polkadot/roadmap/implementers-guide/src/node/backing/statement-distribution.md @@ -194,7 +194,7 @@ request). This doesn't fully avoid race conditions, but tries to minimize them. - Reports a peer (either good or bad). - `CandidateBackingMessage::Statement` - Note a validator's statement about a particular candidate. -- `ProspectiveParachainsMessage::GetHypotheticalFrontier` +- `ProspectiveParachainsMessage::GetHypotheticalMembership` - Gets the hypothetical frontier membership of candidates under active leaves' fragment trees. - `NetworkBridgeTxMessage::SendRequests` - Sends requests, initiating the request/response protocol. diff --git a/polkadot/roadmap/implementers-guide/src/protocol-disputes.md b/polkadot/roadmap/implementers-guide/src/protocol-disputes.md index 2a4082cc07f92aa99425e9e708ec2e90117c02c5..922cc3c3e2b56836d804f9decd8c2be44e7a7fd4 100644 --- a/polkadot/roadmap/implementers-guide/src/protocol-disputes.md +++ b/polkadot/roadmap/implementers-guide/src/protocol-disputes.md @@ -8,9 +8,9 @@ All parachain blocks that end up in the finalized relay chain should be valid. T only backed, but not included. We have two primary components for ensuring that nothing invalid ends up in the finalized relay chain: - * Approval Checking, as described [here](./protocol-approval.md) and implemented according to the [Approval - Voting](node/approval/approval-voting.md) subsystem. This protocol can be shown to prevent invalid parachain blocks - from making their way into the finalized relay chain as long as the amount of attempts are limited. + * Approval Checking, as described [here](./protocol-approval.md) and implemented accordingly in the [Approval +Voting](node/approval/approval-voting.md) subsystem. This protocol can be shown to prevent invalid parachain blocks +from making their way into the finalized relay chain as long as the amount of attempts are limited. * Disputes, this protocol, which ensures that each attempt to include something bad is caught, and the offending validators are punished. Disputes differ from backing and approval process (and can not be part of those) in that a dispute is independent of a particular fork, while both backing and approval operate on particular forks. This diff --git a/polkadot/roadmap/implementers-guide/src/protocol-validator-disabling.md b/polkadot/roadmap/implementers-guide/src/protocol-validator-disabling.md new file mode 100644 index 0000000000000000000000000000000000000000..9fd44c00fa0a1c9ba7f5bb0d5abd54bdc55b8e4e --- /dev/null +++ b/polkadot/roadmap/implementers-guide/src/protocol-validator-disabling.md @@ -0,0 +1,437 @@ +# Validator Disabling + +## Background + +As established in the [approval process](protocol-approval.md) dealing with bad parablocks is a three step process: + +1. Detection +1. Escalation +1. Consequences + +The main system responsible for dispensing **consequences** for malicious actors is the [dispute +system](protocol-disputes.md) which eventually dispenses slash events. The slashes itself can be dispensed quickly (a +matter of blocks) but for an extra layer of auditing all slashes are deferred for 27 days (in Polkadot/Kusama) which +gives time for Governance to investigate and potentially alter the punishment. Dispute concluding by itself does not +immediately remove the validator from the active validator set. + +> **Note:** \ +> There was an additional mechanism of automatically chilling the validator which removed their intent to participate in +> the next election, but the removed validator could simply re-register his intent to validate. + +There is a need to have a more immediate way to deal with malicious validators. This is where the validator disabling +comes in. It is focused on dispensing **low latency** consequences for malicious actors. It is important to note that +the validator disabling is not a replacement for the dispute or slashing systems. It is a complementary system that is +focused on lighter but immediate consequences usually in the form of restricted validator privileges. + +The primary goals are: +- Eliminate or minimize cases where attackers can get free attempts at attacking the network +- Eliminate or minimize the risks of honest nodes being pushed out of consensus when getting unjustly slashed (defense + in depth) + +The above two goals are generally at odds so a careful balance has to be struck between them. We will achieve them by +sacrificing some **liveness** in favor of **soundness** when the network is under stress. Maintaining some liveness but +absolute soundness is paramount. + +> **Note:** \ +> Liveness = Valid candidates can go through (at a decent pace) \ +> Security = Invalid candidates cannot go through (or are statistically very improbable) + +Side goals are: +- Reduce the damages to honest nodes that had a fault which might cause repeated slashes +- Reduce liveness impact of individual malicious attackers + +## System Overview + +High level assumptions and goals of the validator disabling system that will be further discussed in the following +sections: + +1. If validator gets slashed (even 0%) we mark them as disabled in the runtime and on the node side. +1. We only disable up to byzantine threshold of the validators. +1. If there are more offenders than byzantine threshold disable only the highest offenders. (Some might get re-enabled.) +1. Disablement lasts for 1 era. +1. Disabled validators remain in the active validator set but have some limited permissions. +1. Disabled validators can get re-elected. +1. Disabled validators can participate in approval checking. +1. Disabled validators can participate in GRANDPA/BEEFY, but equivocations cause disablement. +1. Disabled validators cannot author blocks. +1. Disabled validators cannot back candidates. +1. Disabled validators cannot initiate disputes, but their votes are still counted if a dispute occurs. +1. Disabled validators making dispute statements no-show in approval checking. + +


+ +# Risks + +## Risks of NOT having validator disabling + +Assume that if an offense is committed a slash is deposited but the perpetrator can still act normally. He will be +slashed 100% with a long delay (slash deferral duration which is 27 days). This is akin to the current design. + +A simple argument for disabling is that if someone is already slashed 100% and they have nothing to lose they could +cause harm to the network and should be silenced. + +What harm could they cause? + +**1. Liveness attacks:** + +- 1.1. Break sharding (with mass no-shows or mass disputes): It forces everyone to do all the work which affects + liveness but doesn't kill it completely. The chain can progress at a slow rate. + +- 1.2. Mass invalid candidate backing: Spawns a lot of worthless work that needs to be done but it is bounded by backing + numbers. Honest backers will still back valid candidates and that cannot be stopped. Honest block authors will + eventually select valid candidates and even if disputed they will win and progress the chain. + +**2. Soundness attacks:** + +- 2.1. The best and possibly only way to affect soundness is by getting lucky in the approval process. If by chance all + approval voters would be malicious, the attackers could get a single invalid candidate through. Their chances would be + relatively low but in general this risk has to be taken seriously as it significantly reduces the safety buffer around + approval checking. + +> **Note:** With 30 approvals needed chance that a malicious candidate going through is around 4\*10^-15. Assuming +> attackers can back invalid candidates on 50 cores for 48 hours straight and only those candidates get included it +> still gives a 7\*10^-9 chance of success which is still relatively small considering the cost (all malicious stake +> slashed). + +Attacks 1.2 and 2.1 should generally be pretty futile as a solo attacker while 1.1 could be possible with mass disputes +even from a single attacker. Nevertheless whatever the attack vector within the old system the attackers would get +*eventually* get slashed and pushed out of the active validator set but they had plenty of time to wreck havoc. + +## Risks of having validator disabling + +Assume we fully push out validator when they commit offenses. + +The primary risk behind having any sort of disabling is that it is a double-edged sword that in case of any dispute bugs +or sources of PVF non-determinism could disable honest nodes or be abused by attackers to specifically silence honest +nodes. + +Validators being pushed out of the validator set are an issue because that can greatly skew the numbers game in approval +checking (% for 30-ish malicious in a row). + +There are also censorship or liveness issues if backing is suddenly dominated by malicious nodes but in general even if +some honest blocks get backed liveness should be preserved. + +> **Note:** It is worth noting that is is fundamentally a defense in depth strategy because if we assume disputes are +> perfect it should not be a real concern. In reality disputes and determinism are difficult to get right, and +> non-determinism and happen so defense in depth is crucial when handling those subsystems. + +


+ +# Risks Mitigation + +## Addressing the risks of having validator disabling + +One safety measure is bounding the disabled number to 1/3 ([**Point 2.**](#system-overview)) or to be exact the +byzantine threshold. If for any reason more than 1/3 of validators are getting disabled it means that some part of the +protocol failed or there is more than 1/3 malicious nodes which breaks the assumptions. + +Even in such a dire situation where more than 1/3 got disabled the most likely scenario is a non-determinism bug or +sacrifice attack bug. Those attacks generally cause minor slashes to multiple honest nodes. In such a case the situation +could be salvaged by prioritizing highest offenders for disabling ([**Point 3.**](#system-overview)). + +> **Note:** \ +> System can be launched with re-enabling and will still provide some security improvements. Re-enabling will be +> launched in an upgrade after the initial deployment. + +Fully pushing out offending validator out of the validator set it too risky in case of a dispute bug, non-determinism or +sacrifice attacks. Main issue lies in skewing the numbers in approval checking so instead of fully blocking disabled +nodes a different approach can be taken - one were only some functionalities are disabled ([**Point +5.**](#system-overview)). Once of those functionalities can be approval voting which as pointed above is so crucial that +even in a disabled state nodes should be able to participate in it ([**Point 7.**](#system-overview)). + +> **Note:** \ +> Approval Checking statement are implicitly valid. Sending a statement for an invalid candidate is a part of the +> dispute logic which we did not yet discuss. For now we only allow nodes to state that a candidate is valid or remain +> silent. But this solves the main risk of disabling. + +Because we capped the number of disabled nodes to 1/3 there will always be at least 1/3 honest nodes to participate in +backing so liveness should be preserved. That means that backing **COULD** be safely disabled for disabled nodes +([**Point 10.**](#system-overview)). + + +## Addressing the risks of NOT having validator disabling + +To determine if backing **SHOULD** be disabled the attack vector of 1.2 (Mass invalid candidate backing) and 2.1 +(Getting lucky in approval voting) need to be considered. In both of those cases having extra backed malicious +candidates gives attackers extra chances to get lucky in approval checking. The solution is to not allow for backing in +disablement. ([**Point 10.**](#system-overview)) + +The attack vector 1.1 (Break sharding) requires a bit more nuance. If we assume that the attacker is a single entity and +that he can get a lot of disputes through he could potentially incredibly easily break sharding. This generally points +into the direction of disallowing that during disablement ([**Point 11.**](#system-overview)). + +This might seem like an issue because it takes away the escalation privileges of disabled approval checkers but this is +NOT true. By issuing a dispute statement those nodes remain silent in approval checking because they skip their approval +statement and thus will count as a no-show. This will create a mini escalation for that particular candidate. This means +that disabled nodes maintain just enough escalation that they can protect soundness (same argument as soundness +protection during a DoS attack on approval checking) but they lose their extreme escalation privilege which are only +given to flawlessly performing nodes ([**Point 12.**](#system-overview)). + +As a defense in depth measure dispute statements from disabled validators count toward confirming disputes (byzantine +threshold needed to confirm). If a dispute is confirmed everyone participates in it. This protects us from situations +where due to a bug more than byzantine threshold of validators would be disabled. + +> **Note:** \ +> The way this behavior is achieved easily in implementation is that honest nodes note down dispute statements from +> disabled validators just like they would for normal nodes, but they do not release their own dispute statements unless +> the dispute is confirmed already. This simply stops the escalation process of disputes. + +

+ +# Disabling Duration + +## Context + +A crucial point to understand is that as of the time of writing all slashing events as alluded to in the begging are +delayed for 27 days before being executed. This is primarily because it gives governance enough time to investigate and +potentially intervene. For that duration when the slash is pending the stake is locked and cannot be moved. Time to +unbond you stake is 28 days which ensures that the stake will eventually be slashed before being withdrawn. + +## Design + +A few options for the duration of disablement were considered: +- 1 epoch (4h in Polkadot) +- 1 era (24h in Polkadot) +- 2-26 eras +- 27 eras + +1 epoch is a short period and between a few epochs the validator will most likely be exactly the same. It is also very +difficult to fix any local node issues for honest validator in such a short time so the chance for a repeated offense is +high. + +1 era gives a bit more time to fix any minor issues. Additionally, it guarantees a validator set change at so many of +the currently disabled validator might no longer be present anyway. It also gives the time for the validator to chill +themselves if they have identified a cause and want to spend more time fixing it. ([**Point 4.**](#system-overview)) + +Higher values could be considered and the main arguments for those are based around the fact that it reduces the number +of repeated attacks that will be allowed before the slash execution. Generally 1 attack per era for 27 eras resulting in +27 attacks at most should not compromise our safety assumptions. Although this direction could be further explored and +might be parametrized for governance to decide. + +


+ +# Economic consequences of Disablement + +Disablement is generally a form of punishment and that will be reflected in the rewards at the end of an era. A disabled +validator will not receive any rewards for backing or block authoring. which will reduce its profits. + +That means that the opportunity cost of being disabled is a punishment by itself and thus it can be used for some cases +where a minor punishment is needed. Current implementation was using 0% slashes to mark nodes for chilling and similar +approach of 0% slashes can be used to mark validators for disablement. ([**Point 1.**](#system-overview)) 0% slashes +could for instance be used to punish approval checkers voting invalid on valid candidates. + +Anything higher than 0% will of course also lead to a disablement. + +> **Notes:** \ +> Alternative designs incorporating disabling proportional to offenses were explored but they were deemed too complex +> and not worth the effort. Main issue with those is that proportional disabling would cause back and forth between +> disabled and enabled which complicated tracking the state of disabled validators and messes with optimistic node +> optimizations. Main benefits were that minor slashes will be barely disabled which has nice properties against +> sacrifice attacks. + +


+ +# Redundancy + +Some systems can be greatly simplified or outright removed thanks to the above changes. This leads to reduced complexity +around the systems that were hard to reason about and were sources of potential bugs or new attack vectors. + +## Automatic Chilling + +Chilling is process of a validator dropping theirs intent to validate. This removes them from the upcoming NPoS +elections and effectively pushes them out of the validator set as quickly as of the next era (or 2 era in case of late +offenses). All nominators of that validator were also getting unsubscribed from that validator. Validator could +re-register their intent to validate at any time. The intent behind this logic was to protect honest stakes from +repeated slashes caused by unnoticed bugs. It would give time for validators to fix their issue before continuing as a +validator. + +Chilling had a myriad of problems. It assumes that validators and nominators remain very active and monitor everything. +If a validator got slashed he was getting automatically chilled and his nominators were getting unsubscribed. This was +an issue because of minor non-malicious slashes due to node operator mistakes or small bugs. Validators got those bugs +fixed quickly and were reimbursed but nominator had to manually re-subscribe to the validator, which they often +postponed for very lengthy amounts of time most likely due to simply not checking their stake. **This forced +unsubscribing of nominators was later disabled.** + +Automatic chilling was achieving its goals in ideal scenarios (no attackers, no lazy nominators) but it opened new +vulnerabilities for attackers. The biggest issue was that chilling in case of honest node slashes could lead to honest +validators being quickly pushed out of the next validator set within the next era. This retains the validator set size +but gives an edge to attackers as they can more easily win slots in the NPoS election. + +Disabling allows for punishment that limits the damages malicious actors can cause without having to resort to kicking +them out of the validator set. This protects us from the edge case of honest validators getting quickly pushed out of +the set by slashes. ([**Point 6.**](#system-overview)) + +> **Notes:** \ +> As long as honest slashes absolutely cannot occur automatic chilling is a sensible and desirable. This means it could +> be re-enabled once PolkaVM introduces deterministic gas metering. Then best of both worlds could be achieved. + +## Forcing New Era + +Previous implementation of disabling had some limited mechanisms allowing for validators disablement and if too many +were disabled forcing a new era (new election). Frame staking pallet offered the ability to force a new era but it was +also deemed unsafe as it could be abused and compromised the security of the network for instance by weakening the +randomness used throughout the protocol. + +


+ +# Other types of slashing + +Above slashes were specifically referring to slashing events coming from disputes against candidates, but in Polkadot +other types of offenses exist for example GRANDPA equivocations or block authoring offenses. Question is if the above +defined design can handle those offenses. + +## GRANDPA/BEEFY Offenses + +The main offences for GRANDPA/BEEFY are equivocations. It is not a very serious offense and some nodes committing do not +endanger the system and performance is barely affected. If more than byzantine threshold of nodes equivocate it is a +catastrophic failure potentially resulting in 2 finalized blocks on the same height in the case of GRANDPA. + +Honest nodes generally should not commit those offenses so the goal of protecting them does not apply here. + +> **Note:** \ +> A validator running multiple nodes with the same identity might equivocate. Doing that is highly not advised but it +> has happened before. + +It's not a game of chance so giving attackers extra chances does not compromise soundness. Also it requires a +supermajority of honest nodes to successfully finalize blocks so any disabling of honest nodes from GRANDPA might +compromise liveness. + +Best approach is to allow disabled nodes to participate in GRANDPA/BEEFY as normal and as mentioned before +GRANDPA/BABE/BEEFY equivocations should not happen to honest nodes so we can safely disable the offenders. Additionally +the slashes for singular equivocations will be very low so those offenders would easily get re-enabled in the case of +more serious offenders showing up. ([**Point 8.**](#system-overview)) + +## Block Authoring Offenses (BABE Equivocations) + +Even if all honest nodes are disabled in Block Authoring (BA) liveness is generally preserved. At least 50% of blocks +produced should still be honest. Soundness wise disabled nodes can create a decent amount of wasted work by creating bad +blocks but they only get to do it in bounded amounts. + +Disabling in BA is not a requirement as both liveness and soundness are preserved but it is the current default behavior +as well as it offers a bit less wasted work. + +Offenses in BA just like in backing can be caused by faulty PVFs or bugs. They might happen to honest nodes and +disabling here while not a requirement can also ensure that this node does not repeat the offense as it might not be +trusted with it's PVF anymore. + +Both points above don't present significant risks when disabling so the default behavior is to disable in BA and because +of offenses in BA. ([**Point 9.**](#system-overview)) This filters out honest faulty nodes as well as protects from some +attackers. + +


+ +# Extra Design Considerations + +## Disabling vs Accumulating Slashes + +Instant disabling generally allows us to remove the need for accumulating slashes. It is a more immediate punishment and +it is a more lenient punishment for honest nodes. + +The current architecture of using max slashing can be used and it works around the problems of delaying the slash for a +long period. + +An alternative design with immediate slashing and acclimating slashing could relevant to other systems but it goes +against the governance auditing mechanisms so it's not be suitable for Polkadot. + +## Disabling vs Getting Pushed Out of NPoS Elections + +Validator disabling and getting forced ouf of NPoS elections (1 era) due to slashes are actually very similar processes +in terms of outcomes but there are some differences: + +- **latency** (next few blocks for validator disabling and 27 days for getting pushed out organically) +- **pool restriction** (validator disabling could effectively lower the number of active validators during an era if we + fully disable) +- **granularity** (validator disabling could remove only a portion of validator privileges instead of all) + +Granularity is particularly crucial in the final design as only a few select functions are disabled while others remain. + +## Enabling Approval Voter Slashes + +The original Polkadot 1.0 design describes that all validators on the loosing side of the dispute are slashed. In the +current system only the backers are slashed and any approval voters on the wrong side will not be slashed. This creates +some undesirable incentives: + +- Lazy approval checkers (approvals yay`ing everything) +- Spammy approval checkers (approval voters nay`ing everything) + +Initially those slashes were disabled to reduce the complexity and to minimize the risk surface in case the system +malfunctioned. This is especially risky in case any nondeterministic bugs are present in the system. Once validator +re-enabling is launched approval voter slashes can be re-instated. Numbers need to be further explored but slashes +between 0-2% are reasonable. 0% would still disable which with the opportunity cost consideration should be enough. + + > **Note:** \ +> Spammy approval checkers are in fact not a big issue as a side effect of the offchain-disabling introduced by the +> Defense Against Past-Era Dispute Spam (**Node**) [#2225](https://github.com/paritytech/polkadot-sdk/issues/2225). It +> makes it so all validators loosing a dispute are locally disabled and ignored for dispute initiation so it effectively +> silences spammers. They can still no-show but the damage is minimized. + + +## Interaction with all types of misbehaviors + +With re-enabling in place and potentially approval voter slashes enabled the overall misbehaviour-punishment system can +be as highlighted in the table below: + +|Misbehaviour |Slash % |Onchain Disabling |Offchain Disabling |Chilling |Reputation Costs | +|------------ |------- |----------------- |------------------ |-------- |----------------- | +|Backing Invalid |100% |Yes (High Prio) |Yes (High Prio) |No |No | +|ForInvalid Vote |2% |Yes (Mid Prio) |Yes (Mid Prio) |No |No | +|AgainstValid Vote |0% |Yes (Low Prio) |Yes (Low Prio) |No |No | +|GRANDPA / BABE / BEEFY Equivocations |0.01-100% |Yes (Varying Prio) |No |No |No | +|Seconded + Valid Equivocation |- |No |No |No |No | +|Double Seconded Equivocation |- |No |No |No |Yes | + + +*Ignoring AURA offences. + +**There are some other misbehaviour types handled in rep only (DoS prevention etc) but they are not relevant to this strategy. + +*** BEEFY will soon introduce new slash types so this strategy table will need to be revised but no major changes are expected. + +


+ +# Implementation + +Implementation of the above design covers a few additional areas that allow for node-side optimizations. + +## Core Features + +1. Disabled Validators Tracking (**Runtime**) [#2950](https://github.com/paritytech/polkadot-sdk/issues/2950) + - Expose a ``disabled_validators`` map through a Runtime API +1. Enforce Backing Disabling (**Runtime**) [#1592](https://github.com/paritytech/polkadot-sdk/issues/1592) + - Filter out votes from ``disabled_validators`` in ``BackedCandidates`` in ``process_inherent_data`` +1. Substrate Byzantine Threshold (BZT) as Limit for Disabling + [#1963](https://github.com/paritytech/polkadot-sdk/issues/1963) + - Can be parametrized but default to BZT + - Disable only up to 1/3 of validators +1. Respect Disabling in Backing Statement Distribution (**Node**) + [#1591](https://github.com/paritytech/polkadot-sdk/issues/1951) + - This is an optimization as in the end it would get filtered in the runtime anyway + - Filter out backing statements coming from ``disabled_validators`` +1. Respect Disablement in Backing (**Node**) [#2951](https://github.com/paritytech/polkadot-sdk/issues/2951) + - This is an optimization as in the end it would get filtered in the runtime anyway + - Don't start backing new candidates when disabled + - Don't react to backing requests when disabled +1. Stop Automatic Chilling of Offenders [#1962](https://github.com/paritytech/polkadot-sdk/issues/1962) + - Chilling still persists as a state but is no longer automatically applied on offenses +1. Respect Disabling in Dispute Participation (**Node**) [#2225](https://github.com/paritytech/polkadot-sdk/issues/2225) + - Receive dispute statements from ``disabled_validators`` but do not release own statements + - Ensure dispute confirmation when BZT statements from disabled +1. Remove Liveness Slashes [#1964](https://github.com/paritytech/polkadot-sdk/issues/1964) + - Remove liveness slashes from the system + - The are other incentives to be online and they could be abused to attack the system +1. Defense Against Past-Era Dispute Spam (**Node**) [#2225](https://github.com/paritytech/polkadot-sdk/issues/2225) + - This is needed because runtime cannot disable validators which it no longer knows about + - Add a node-side parallel store of ``disabled_validators`` + - Add new disabled validators to node-side store when they loose a dispute in any leaf in scope + - Runtime ``disabled_validators`` always have priority over node-side ``disabled_validators`` + - Respect the BZT threshold + > **Note:** \ + > An alternative design here was considered where instead of tracking new incoming leaves a relay parent is used. + > This would guarantee determinism as different nodes can see different leaves, but this approach was leaving too + > wide of a window because of Async-Backing. Relay Parent could have been significantly in the past and it would + > give a lot of time for past session disputes to be spammed. +1. Do not block finality for "disabled" disputes [#3358](https://github.com/paritytech/polkadot-sdk/pull/3358) + - Emergency fix to not block finality for disputes initiated only by disabled validators +1. Re-enable small offender when approaching BZT (**Runtime**) #TODO + - When BZT limit is reached and there are more offenders to be disabled re-enable the smallest offenders to disable + the biggest ones diff --git a/polkadot/runtime/common/Cargo.toml b/polkadot/runtime/common/Cargo.toml index 4219a7e7b0dcb57c50a5e709d0695dfa723b582a..3a64148817682096d409e9ea1c4e38a39b44d7b7 100644 --- a/polkadot/runtime/common/Cargo.toml +++ b/polkadot/runtime/common/Cargo.toml @@ -12,7 +12,7 @@ workspace = true [dependencies] 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"] } +parity-scale-codec = { version = "3.6.12", default-features = false, features = ["derive"] } log = { workspace = true } rustc-hex = { version = "2.1.0", default-features = false } scale-info = { version = "2.11.1", default-features = false, features = ["derive"] } diff --git a/polkadot/runtime/common/slot_range_helper/Cargo.toml b/polkadot/runtime/common/slot_range_helper/Cargo.toml index cacafd8ed3b746d35b5b064ca3d6662b313f8b86..314e101ad221e9e842eb609a0ca6d80d8c8c52ad 100644 --- a/polkadot/runtime/common/slot_range_helper/Cargo.toml +++ b/polkadot/runtime/common/slot_range_helper/Cargo.toml @@ -12,7 +12,7 @@ workspace = true [dependencies] paste = "1.0" enumn = "0.1.12" -parity-scale-codec = { version = "3.6.1", default-features = false, features = ["derive"] } +parity-scale-codec = { version = "3.6.12", default-features = false, features = ["derive"] } sp-std = { package = "sp-std", path = "../../../../substrate/primitives/std", default-features = false } sp-runtime = { path = "../../../../substrate/primitives/runtime", default-features = false } diff --git a/polkadot/runtime/common/src/crowdloan/mod.rs b/polkadot/runtime/common/src/crowdloan/mod.rs index 12078871a1957215fd209402894fc0434fba6ba5..477530467fa105d93b41569d851b5699aadc09b0 100644 --- a/polkadot/runtime/common/src/crowdloan/mod.rs +++ b/polkadot/runtime/common/src/crowdloan/mod.rs @@ -866,7 +866,7 @@ mod tests { use sp_core::H256; use std::{cell::RefCell, collections::BTreeMap, sync::Arc}; // 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 requried. + // or public keys. `u64` is used as the `AccountId` and no `Signature`s are required. use crate::{ crowdloan, mock::TestRegistrar, diff --git a/polkadot/runtime/common/src/impls.rs b/polkadot/runtime/common/src/impls.rs index cc1243790c2e58b23c169de918f28d75397420ba..85531e9c04fc47f83fb007802e30e87799c2150c 100644 --- a/polkadot/runtime/common/src/impls.rs +++ b/polkadot/runtime/common/src/impls.rs @@ -19,7 +19,7 @@ use frame_support::traits::{ fungible::{Balanced, Credit}, tokens::imbalance::ResolveTo, - Imbalance, OnUnbalanced, + Contains, ContainsPair, Imbalance, OnUnbalanced, }; use pallet_treasury::TreasuryAccountId; use parity_scale_codec::{Decode, Encode, MaxEncodedLen}; @@ -156,6 +156,26 @@ impl TryConvert<&VersionedLocation, xcm::latest::Location> for VersionedLocation } } +/// Adapter for [`Contains`] trait to match [`VersionedLocatableAsset`] type converted to the latest +/// version of itself where it's location matched by `L` and it's asset id by `A` parameter types. +pub struct ContainsParts(core::marker::PhantomData); +impl Contains for ContainsParts +where + C: ContainsPair, +{ + fn contains(asset: &VersionedLocatableAsset) -> bool { + use VersionedLocatableAsset::*; + let (location, asset_id) = match asset.clone() { + V3 { location, asset_id } => match (location.try_into(), asset_id.try_into()) { + (Ok(l), Ok(a)) => (l, a), + _ => return false, + }, + V4 { location, asset_id } => (location, asset_id), + }; + C::contains(&location, &asset_id.0) + } +} + #[cfg(feature = "runtime-benchmarks")] pub mod benchmarks { use super::VersionedLocatableAsset; diff --git a/polkadot/runtime/common/src/integration_tests.rs b/polkadot/runtime/common/src/integration_tests.rs index 91b64ef7259c3c260ca39e30a8e4dc63362bf339..3e9ac1fc1b152574ea86d42c7d48f51da47ddc39 100644 --- a/polkadot/runtime/common/src/integration_tests.rs +++ b/polkadot/runtime/common/src/integration_tests.rs @@ -39,7 +39,7 @@ use primitives::{ MAX_CODE_SIZE, }; use runtime_parachains::{ - configuration, origin, paras, shared, Origin as ParaOrigin, ParaLifecycle, + configuration, dmp, origin, paras, shared, Origin as ParaOrigin, ParaLifecycle, }; use sp_core::H256; use sp_io::TestExternalities; @@ -84,6 +84,7 @@ frame_support::construct_runtime!( Paras: paras, ParasShared: shared, ParachainsOrigin: origin, + Dmp: dmp, // Para Onboarding Pallets Registrar: paras_registrar, @@ -201,6 +202,8 @@ impl shared::Config for Test { type DisabledValidators = (); } +impl dmp::Config for Test {} + impl origin::Config for Test {} parameter_types! { diff --git a/polkadot/runtime/common/src/lib.rs b/polkadot/runtime/common/src/lib.rs index 65161764ccd7bf363a85238fbf7a708421561743..60cc684149b48fe7bb4a102cbad7f96f3c7b5826 100644 --- a/polkadot/runtime/common/src/lib.rs +++ b/polkadot/runtime/common/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 . -//! Common runtime code for Polkadot and Kusama. +//! Common runtime code for the Relay Chain, e.g. Rococo, Westend, Polkadot, Kusama ... #![cfg_attr(not(feature = "std"), no_std)] diff --git a/polkadot/runtime/common/src/paras_registrar/mod.rs b/polkadot/runtime/common/src/paras_registrar/mod.rs index cc949c9d3f626407b77590b35d44177a847fedae..a49ebab3e26a8df5ecfdf7615849b75d9e3c4671 100644 --- a/polkadot/runtime/common/src/paras_registrar/mod.rs +++ b/polkadot/runtime/common/src/paras_registrar/mod.rs @@ -412,7 +412,7 @@ pub mod pallet { /// validators have reported on the validity of the code, the code will either be enacted /// or the upgrade will be rejected. If the code will be enacted, the current code of the /// parachain will be overwritten directly. This means that any PoV will be checked by this - /// new code. The parachain itself will not be informed explictely that the validation code + /// new code. The parachain itself will not be informed explicitly that the validation code /// has changed. /// /// Can be called by Root, the parachain, or the parachain manager if the parachain is diff --git a/polkadot/runtime/common/src/xcm_sender.rs b/polkadot/runtime/common/src/xcm_sender.rs index 0cbc2e603c8e776b2377f15569a2c38934753967..cbec1a8ca1036117275b5234229c2cfc06481056 100644 --- a/polkadot/runtime/common/src/xcm_sender.rs +++ b/polkadot/runtime/common/src/xcm_sender.rs @@ -18,7 +18,7 @@ use frame_support::traits::Get; use frame_system::pallet_prelude::BlockNumberFor; -use parity_scale_codec::Encode; +use parity_scale_codec::{Decode, Encode}; use primitives::Id as ParaId; use runtime_parachains::{ configuration::{self, HostConfiguration}, @@ -27,6 +27,7 @@ use runtime_parachains::{ use sp_runtime::FixedPointNumber; use sp_std::{marker::PhantomData, prelude::*}; use xcm::prelude::*; +use xcm_builder::InspectMessageQueues; use SendError::*; /// Simple value-bearing trait for determining/expressing the assets required to be paid for a @@ -119,7 +120,9 @@ where let config = configuration::ActiveConfig::::get(); let para = id.into(); let price = P::price_for_delivery(para, &xcm); - let blob = W::wrap_version(&d, xcm).map_err(|()| DestinationUnsupported)?.encode(); + let versioned_xcm = W::wrap_version(&d, xcm).map_err(|()| DestinationUnsupported)?; + versioned_xcm.validate_xcm_nesting().map_err(|()| ExceedsMaxMessageSize)?; + let blob = versioned_xcm.encode(); dmp::Pallet::::can_queue_downward_message(&config, ¶, &blob) .map_err(Into::::into)?; @@ -136,6 +139,24 @@ where } } +impl InspectMessageQueues for ChildParachainRouter { + fn get_messages() -> Vec<(VersionedLocation, Vec>)> { + dmp::DownwardMessageQueues::::iter() + .map(|(para_id, messages)| { + let decoded_messages: Vec> = messages + .iter() + .map(|downward_message| { + let message = VersionedXcm::<()>::decode(&mut &downward_message.msg[..]).unwrap(); + log::trace!(target: "xcm::DownwardMessageQueues::get_messages", "Message: {:?}, sent at: {:?}", message, downward_message.sent_at); + message + }) + .collect(); + (VersionedLocation::V4(Parachain(para_id.into()).into()), decoded_messages) + }) + .collect() + } +} + /// 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). @@ -236,9 +257,11 @@ impl EnsureForParachain for () { #[cfg(test)] mod tests { use super::*; - use frame_support::parameter_types; + use crate::integration_tests::new_test_ext; + use frame_support::{assert_ok, parameter_types}; use runtime_parachains::FeeTracker; use sp_runtime::FixedU128; + use xcm::MAX_XCM_DECODE_DEPTH; parameter_types! { pub const BaseDeliveryFee: u128 = 300_000_000; @@ -297,4 +320,40 @@ mod tests { (FeeAssetId::get(), result).into() ); } + + #[test] + fn child_parachain_router_validate_nested_xcm_works() { + let dest = Parachain(5555); + + type Router = ChildParachainRouter< + crate::integration_tests::Test, + (), + NoPriceForMessageDelivery, + >; + + // Message that is not too deeply nested: + let mut good = Xcm(vec![ClearOrigin]); + for _ in 0..MAX_XCM_DECODE_DEPTH - 1 { + good = Xcm(vec![SetAppendix(good)]); + } + + new_test_ext().execute_with(|| { + configuration::ActiveConfig::::mutate(|c| { + c.max_downward_message_size = u32::MAX; + }); + + // Check that the good message is validated: + assert_ok!(::validate( + &mut Some(dest.into()), + &mut Some(good.clone()) + )); + + // Nesting the message one more time should reject it: + let bad = Xcm(vec![SetAppendix(good)]); + assert_eq!( + Err(ExceedsMaxMessageSize), + ::validate(&mut Some(dest.into()), &mut Some(bad)) + ); + }); + } } diff --git a/polkadot/runtime/metrics/Cargo.toml b/polkadot/runtime/metrics/Cargo.toml index 481627542865e1e79e4be790c3ccf46cc5878c07..76c1d134fa18669768aff9e860bbaee35a201e67 100644 --- a/polkadot/runtime/metrics/Cargo.toml +++ b/polkadot/runtime/metrics/Cargo.toml @@ -12,7 +12,7 @@ workspace = true [dependencies] sp-std = { package = "sp-std", path = "../../../substrate/primitives/std", default-features = false } sp-tracing = { path = "../../../substrate/primitives/tracing", default-features = false } -parity-scale-codec = { version = "3.6.1", default-features = false } +parity-scale-codec = { version = "3.6.12", default-features = false } primitives = { package = "polkadot-primitives", path = "../../primitives", default-features = false } frame-benchmarking = { path = "../../../substrate/frame/benchmarking", default-features = false, optional = true } diff --git a/polkadot/runtime/parachains/Cargo.toml b/polkadot/runtime/parachains/Cargo.toml index dff8549f29f3ad38748c3c2cc5b21c328356196a..d00a19c6ddb8e43881473d7b22daa31b4cc6990c 100644 --- a/polkadot/runtime/parachains/Cargo.toml +++ b/polkadot/runtime/parachains/Cargo.toml @@ -12,7 +12,7 @@ workspace = true [dependencies] 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"] } +parity-scale-codec = { version = "3.6.12", default-features = false, features = ["derive", "max-encoded-len"] } log = { workspace = true } rustc-hex = { version = "2.1.0", default-features = false } scale-info = { version = "2.11.1", default-features = false, features = ["derive"] } @@ -28,7 +28,7 @@ sp-runtime = { path = "../../../substrate/primitives/runtime", default-features sp-session = { path = "../../../substrate/primitives/session", default-features = false } sp-staking = { path = "../../../substrate/primitives/staking", default-features = false, features = ["serde"] } sp-core = { path = "../../../substrate/primitives/core", default-features = false, features = ["serde"] } -sp-keystore = { path = "../../../substrate/primitives/keystore", optional = true } +sp-keystore = { path = "../../../substrate/primitives/keystore", optional = true, default-features = false } sp-application-crypto = { path = "../../../substrate/primitives/application-crypto", default-features = false, optional = true } sp-tracing = { path = "../../../substrate/primitives/tracing", default-features = false, optional = true } sp-arithmetic = { path = "../../../substrate/primitives/arithmetic", default-features = false } @@ -108,6 +108,7 @@ std = [ "sp-core/std", "sp-io/std", "sp-keystore", + "sp-keystore?/std", "sp-runtime/std", "sp-session/std", "sp-staking/std", diff --git a/polkadot/runtime/parachains/src/assigner_on_demand/mod.rs b/polkadot/runtime/parachains/src/assigner_on_demand/mod.rs index 598a0f10970067a67186098019e6f067798df2da..37788a67ea0c46d6c75b45039d994b8e40641e1c 100644 --- a/polkadot/runtime/parachains/src/assigner_on_demand/mod.rs +++ b/polkadot/runtime/parachains/src/assigner_on_demand/mod.rs @@ -740,7 +740,7 @@ where /// /// Subtracts from the count of the `CoreAffinityCount` if an entry is found and the core_index /// matches. When the count reaches 0, the entry is removed. - /// A non-existant entry is a no-op. + /// A non-existent entry is a no-op. /// /// Returns: The new affinity of the para on that core. `None` if there is no affinity on this /// core. diff --git a/polkadot/runtime/parachains/src/configuration.rs b/polkadot/runtime/parachains/src/configuration.rs index b5dad6c6e864ba94854e3b56198c75f894f89ce7..34923897f02b38891ca7af122f48ee91988a483e 100644 --- a/polkadot/runtime/parachains/src/configuration.rs +++ b/polkadot/runtime/parachains/src/configuration.rs @@ -30,7 +30,7 @@ use primitives::{ NodeFeatures, SessionIndex, LEGACY_MIN_BACKING_VOTES, MAX_CODE_SIZE, MAX_HEAD_DATA_SIZE, MAX_POV_SIZE, ON_DEMAND_MAX_QUEUE_MAX_SIZE, }; -use sp_runtime::{traits::Zero, Perbill}; +use sp_runtime::{traits::Zero, Perbill, Percent}; use sp_std::prelude::*; #[cfg(test)] @@ -1460,3 +1460,16 @@ impl Pallet { Ok(()) } } + +/// The implementation of `Get<(u32, u32)>` which reads `ActiveConfig` and returns `P` percent of +/// `hrmp_channel_max_message_size` / `hrmp_channel_max_capacity`. +pub struct ActiveConfigHrmpChannelSizeAndCapacityRatio(sp_std::marker::PhantomData<(T, P)>); +impl> Get<(u32, u32)> + for ActiveConfigHrmpChannelSizeAndCapacityRatio +{ + fn get() -> (u32, u32) { + let config = ActiveConfig::::get(); + let percent = P::get(); + (percent * config.hrmp_channel_max_message_size, percent * config.hrmp_channel_max_capacity) + } +} diff --git a/polkadot/runtime/parachains/src/configuration/tests.rs b/polkadot/runtime/parachains/src/configuration/tests.rs index 239b466fde3970babec24ad109a22e16be2c9066..64bbb8481fc1ba63ff8f851aa8b3d2ba5d6bd7df 100644 --- a/polkadot/runtime/parachains/src/configuration/tests.rs +++ b/polkadot/runtime/parachains/src/configuration/tests.rs @@ -17,7 +17,7 @@ use super::*; use crate::{ configuration, - mock::{new_test_ext, Configuration, ParasShared, RuntimeOrigin, Test}, + mock::{new_test_ext, Configuration, MockGenesisConfig, ParasShared, RuntimeOrigin, Test}, }; use bitvec::{bitvec, prelude::Lsb0}; use frame_support::{assert_err, assert_noop, assert_ok}; @@ -547,3 +547,51 @@ fn verify_externally_accessible() { ); }); } + +#[test] +fn active_config_hrmp_channel_size_and_capacity_ratio_works() { + frame_support::parameter_types! { + pub Ratio100: Percent = Percent::from_percent(100); + pub Ratio50: Percent = Percent::from_percent(50); + } + + let mut genesis: MockGenesisConfig = Default::default(); + genesis.configuration.config.hrmp_channel_max_message_size = 1024; + genesis.configuration.config.hrmp_channel_max_capacity = 100; + + new_test_ext(genesis).execute_with(|| { + let active_config = configuration::ActiveConfig::::get(); + assert_eq!(active_config.hrmp_channel_max_message_size, 1024); + assert_eq!(active_config.hrmp_channel_max_capacity, 100); + + assert_eq!( + ActiveConfigHrmpChannelSizeAndCapacityRatio::::get(), + (1024, 100) + ); + assert_eq!(ActiveConfigHrmpChannelSizeAndCapacityRatio::::get(), (512, 50)); + + // change ActiveConfig + assert_ok!(Configuration::set_hrmp_channel_max_message_size( + RuntimeOrigin::root(), + active_config.hrmp_channel_max_message_size * 4 + )); + assert_ok!(Configuration::set_hrmp_channel_max_capacity( + RuntimeOrigin::root(), + active_config.hrmp_channel_max_capacity * 4 + )); + on_new_session(1); + on_new_session(2); + let active_config = configuration::ActiveConfig::::get(); + assert_eq!(active_config.hrmp_channel_max_message_size, 4096); + assert_eq!(active_config.hrmp_channel_max_capacity, 400); + + assert_eq!( + ActiveConfigHrmpChannelSizeAndCapacityRatio::::get(), + (4096, 400) + ); + assert_eq!( + ActiveConfigHrmpChannelSizeAndCapacityRatio::::get(), + (2048, 200) + ); + }) +} diff --git a/polkadot/runtime/parachains/src/coretime/migration.rs b/polkadot/runtime/parachains/src/coretime/migration.rs index 72eda1ea3f3cd03a50c595a4b36b6188cca81aaa..6c8ddaa8aab30c702a4c13c25e3d1c571e6a79cf 100644 --- a/polkadot/runtime/parachains/src/coretime/migration.rs +++ b/polkadot/runtime/parachains/src/coretime/migration.rs @@ -46,7 +46,7 @@ mod v_coretime { #[cfg(feature = "try-runtime")] use sp_std::vec::Vec; use sp_std::{iter, prelude::*, result}; - use xcm::v4::{send_xcm, Instruction, Junction, Location, SendError, WeightLimit, Xcm}; + use xcm::prelude::{send_xcm, Instruction, Junction, Location, SendError, WeightLimit, Xcm}; /// Return information about a legacy lease of a parachain. pub trait GetLegacyLease { @@ -222,7 +222,7 @@ mod v_coretime { mask: CoreMask::complete(), assignment: CoreAssignment::Task(p.into()), }]); - mk_coretime_call(crate::coretime::CoretimeCalls::Reserve(schedule)) + mk_coretime_call::(crate::coretime::CoretimeCalls::Reserve(schedule)) }); let leases = lease_holding.into_iter().filter_map(|p| { @@ -243,14 +243,14 @@ mod v_coretime { let round_up = if valid_until % TIME_SLICE_PERIOD > 0 { 1 } else { 0 }; let time_slice = valid_until / TIME_SLICE_PERIOD + TIME_SLICE_PERIOD * round_up; log::trace!(target: "coretime-migration", "Sending of lease holding para {:?}, valid_until: {:?}, time_slice: {:?}", p, valid_until, time_slice); - Some(mk_coretime_call(crate::coretime::CoretimeCalls::SetLease(p.into(), time_slice))) + Some(mk_coretime_call::(crate::coretime::CoretimeCalls::SetLease(p.into(), time_slice))) }); let core_count: u16 = configuration::ActiveConfig::::get() .scheduler_params .num_cores .saturated_into(); - let set_core_count = iter::once(mk_coretime_call( + let set_core_count = iter::once(mk_coretime_call::( crate::coretime::CoretimeCalls::NotifyCoreCount(core_count), )); @@ -261,7 +261,7 @@ mod v_coretime { }]); // Reserved cores will come before lease cores, so cores will change their assignments // when coretime chain sends us their assign_core calls -> Good test. - mk_coretime_call(crate::coretime::CoretimeCalls::Reserve(schedule)) + mk_coretime_call::(crate::coretime::CoretimeCalls::Reserve(schedule)) }); let message_content = iter::once(Instruction::UnpaidExecution { diff --git a/polkadot/runtime/parachains/src/coretime/mod.rs b/polkadot/runtime/parachains/src/coretime/mod.rs index 9095cd90ae0cfea6a72fde2d4730cad28cf97d29..33cbcb98fb29992a4eac77db9eb7def4088af16f 100644 --- a/polkadot/runtime/parachains/src/coretime/mod.rs +++ b/polkadot/runtime/parachains/src/coretime/mod.rs @@ -26,7 +26,9 @@ pub use pallet::*; use pallet_broker::{CoreAssignment, CoreIndex as BrokerCoreIndex}; use primitives::{CoreIndex, Id as ParaId}; use sp_arithmetic::traits::SaturatedConversion; -use xcm::v4::{send_xcm, Instruction, Junction, Location, OriginKind, SendXcm, WeightLimit, Xcm}; +use xcm::prelude::{ + send_xcm, Instruction, Junction, Location, OriginKind, SendXcm, WeightLimit, Xcm, +}; use crate::{ assigner_coretime::{self, PartsOf57600}, @@ -104,12 +106,17 @@ pub mod pallet { type RuntimeEvent: From> + IsType<::RuntimeEvent>; /// The runtime's definition of a Currency. type Currency: Currency; - /// The ParaId of the broker system parachain. + /// The ParaId of the coretime chain. #[pallet::constant] type BrokerId: Get; /// Something that provides the weight of this pallet. type WeightInfo: WeightInfo; type SendXcm: SendXcm; + + /// Maximum weight for any XCM transact call that should be executed on the coretime chain. + /// + /// Basically should be `max_weight(set_leases, reserve, notify_core_count)`. + type MaxXcmTransactWeight: Get; } #[pallet::event] @@ -132,10 +139,16 @@ pub mod pallet { #[pallet::call] impl Pallet { + /// Request the configuration to be updated with the specified number of cores. Warning: + /// Since this only schedules a configuration update, it takes two sessions to come into + /// effect. + /// + /// - `origin`: Root or the Coretime Chain + /// - `count`: total number of cores #[pallet::weight(::WeightInfo::request_core_count())] #[pallet::call_index(1)] pub fn request_core_count(origin: OriginFor, count: u16) -> DispatchResult { - // Ignore requests not coming from the broker parachain or root. + // Ignore requests not coming from the coretime chain or root. Self::ensure_root_or_para(origin, ::BrokerId::get().into())?; configuration::Pallet::::set_coretime_cores_unchecked(u32::from(count)) @@ -148,7 +161,7 @@ pub mod pallet { // origin: OriginFor, // _when: BlockNumberFor, //) -> DispatchResult { - // // Ignore requests not coming from the broker parachain or root. + // // Ignore requests not coming from the coretime chain or root. // Self::ensure_root_or_para(origin, ::BrokerId::get().into())?; // Ok(()) //} @@ -161,7 +174,7 @@ pub mod pallet { // _who: T::AccountId, // _amount: BalanceOf, //) -> DispatchResult { - // // Ignore requests not coming from the broker parachain or root. + // // Ignore requests not coming from the coretime chain or root. // Self::ensure_root_or_para(origin, ::BrokerId::get().into())?; // Ok(()) //} @@ -170,7 +183,7 @@ pub mod pallet { /// to be used. /// /// Parameters: - /// -`origin`: The `ExternalBrokerOrigin`, assumed to be the Broker system parachain. + /// -`origin`: The `ExternalBrokerOrigin`, assumed to be the coretime chain. /// -`core`: The core that should be scheduled. /// -`begin`: The starting blockheight of the instruction. /// -`assignment`: How the blockspace should be utilised. @@ -186,7 +199,7 @@ pub mod pallet { assignment: Vec<(CoreAssignment, PartsOf57600)>, end_hint: Option>, ) -> DispatchResult { - // Ignore requests not coming from the broker parachain or root. + // Ignore requests not coming from the coretime chain or root. Self::ensure_root_or_para(origin, T::BrokerId::get().into())?; let core = u32::from(core).into(); @@ -225,7 +238,7 @@ impl Pallet { weight_limit: WeightLimit::Unlimited, check_origin: None, }, - mk_coretime_call(crate::coretime::CoretimeCalls::NotifyCoreCount(core_count)), + mk_coretime_call::(crate::coretime::CoretimeCalls::NotifyCoreCount(core_count)), ]); if let Err(err) = send_xcm::( Location::new(0, [Junction::Parachain(T::BrokerId::get())]), @@ -236,7 +249,7 @@ impl Pallet { } } - // Handle legacy swaps in coretime. Notifies broker parachain that a lease swap has occurred via + // Handle legacy swaps in coretime. Notifies coretime chain that a lease swap has occurred via // XCM message. This function is meant to be used in an implementation of `OnSwap` trait. pub fn on_legacy_lease_swap(one: ParaId, other: ParaId) { let message = Xcm(vec![ @@ -244,7 +257,7 @@ impl Pallet { weight_limit: WeightLimit::Unlimited, check_origin: None, }, - mk_coretime_call(crate::coretime::CoretimeCalls::SwapLeases(one, other)), + mk_coretime_call::(crate::coretime::CoretimeCalls::SwapLeases(one, other)), ]); if let Err(err) = send_xcm::( Location::new(0, [Junction::Parachain(T::BrokerId::get())]), @@ -261,12 +274,10 @@ impl OnNewSession> for Pallet { } } -fn mk_coretime_call(call: crate::coretime::CoretimeCalls) -> Instruction<()> { +fn mk_coretime_call(call: crate::coretime::CoretimeCalls) -> Instruction<()> { Instruction::Transact { origin_kind: OriginKind::Superuser, - // Largest call is set_lease with 1526 byte: - // Longest call is reserve() with 31_000_000 - require_weight_at_most: Weight::from_parts(170_000_000, 20_000), + require_weight_at_most: T::MaxXcmTransactWeight::get(), call: BrokerRuntimePallets::Broker(call).encode().into(), } } diff --git a/polkadot/runtime/parachains/src/disputes/slashing.rs b/polkadot/runtime/parachains/src/disputes/slashing.rs index d0c74e4bc958320fca78231129dd6e8e135e0179..a61d0c8998364c111f6e3a49fc03d5d39a5d76af 100644 --- a/polkadot/runtime/parachains/src/disputes/slashing.rs +++ b/polkadot/runtime/parachains/src/disputes/slashing.rs @@ -64,7 +64,7 @@ use sp_runtime::{ KeyTypeId, Perbill, }; use sp_session::{GetSessionNumber, GetValidatorCount}; -use sp_staking::offence::{DisableStrategy, Kind, Offence, OffenceError, ReportOffence}; +use sp_staking::offence::{Kind, Offence, OffenceError, ReportOffence}; use sp_std::{ collections::{btree_map::Entry, btree_set::BTreeSet}, prelude::*, @@ -134,15 +134,6 @@ where self.time_slot.clone() } - fn disable_strategy(&self) -> DisableStrategy { - match self.kind { - SlashingOffenceKind::ForInvalid => DisableStrategy::Always, - // in the future we might change it based on number of disputes initiated: - // - SlashingOffenceKind::AgainstValid => DisableStrategy::Never, - } - } - fn slash_fraction(&self, _offenders: u32) -> Perbill { self.slash_fraction } diff --git a/polkadot/runtime/parachains/src/dmp.rs b/polkadot/runtime/parachains/src/dmp.rs index 354b16cc3f082f2f74ad276e8139e21d4094c4cc..df2f93e194214c7bec474668f197ceaca53818ed 100644 --- a/polkadot/runtime/parachains/src/dmp.rs +++ b/polkadot/runtime/parachains/src/dmp.rs @@ -119,7 +119,7 @@ pub mod pallet { /// The downward messages addressed for a certain para. #[pallet::storage] - pub(crate) type DownwardMessageQueues = StorageMap< + pub type DownwardMessageQueues = StorageMap< _, Twox64Concat, ParaId, diff --git a/polkadot/runtime/parachains/src/hrmp.rs b/polkadot/runtime/parachains/src/hrmp.rs index 65652b38577b361353aca1920255e9788c838028..42a9c23e5aa1132c5f0ff4044b53df2407efdc1e 100644 --- a/polkadot/runtime/parachains/src/hrmp.rs +++ b/polkadot/runtime/parachains/src/hrmp.rs @@ -278,6 +278,14 @@ pub mod pallet { /// parachain. type DefaultChannelSizeAndCapacityWithSystem: Get<(u32, u32)>; + /// Means of converting an `Xcm` into a `VersionedXcm`. This pallet sends HRMP XCM + /// notifications to the channel-related parachains, while the `WrapVersion` implementation + /// attempts to wrap them into the most suitable XCM version for the destination parachain. + /// + /// NOTE: For example, `pallet_xcm` provides an accurate implementation (recommended), or + /// the default `()` implementation uses the latest XCM version for all parachains. + type VersionWrapper: xcm::WrapVersion; + /// Something that provides the weight of this pallet. type WeightInfo: WeightInfo; } @@ -1499,28 +1507,19 @@ impl Pallet { ); HrmpOpenChannelRequestsList::::append(channel_id); - let notification_bytes = { - use parity_scale_codec::Encode as _; - use xcm::opaque::{latest::prelude::*, VersionedXcm}; - - VersionedXcm::from(Xcm(vec![HrmpNewChannelOpenRequest { - sender: u32::from(origin), - max_capacity: proposed_max_capacity, - max_message_size: proposed_max_message_size, - }])) - .encode() - }; - if let Err(dmp::QueueDownwardMessageError::ExceedsMaxMessageSize) = - dmp::Pallet::::queue_downward_message(&config, recipient, notification_bytes) - { - // this should never happen unless the max downward message size is configured to a - // jokingly small number. - log::error!( - target: "runtime::hrmp", - "sending 'init_open_channel::notification_bytes' failed." - ); - debug_assert!(false); - } + Self::send_to_para( + "init_open_channel", + &config, + recipient, + Self::wrap_notification(|| { + use xcm::opaque::latest::{prelude::*, Xcm}; + Xcm(vec![HrmpNewChannelOpenRequest { + sender: origin.into(), + max_capacity: proposed_max_capacity, + max_message_size: proposed_max_message_size, + }]) + }), + ); Ok(()) } @@ -1562,23 +1561,15 @@ impl Pallet { HrmpOpenChannelRequests::::insert(&channel_id, channel_req); HrmpAcceptedChannelRequestCount::::insert(&origin, accepted_cnt + 1); - let notification_bytes = { - use parity_scale_codec::Encode as _; - use xcm::opaque::{latest::prelude::*, VersionedXcm}; - let xcm = Xcm(vec![HrmpChannelAccepted { recipient: u32::from(origin) }]); - VersionedXcm::from(xcm).encode() - }; - if let Err(dmp::QueueDownwardMessageError::ExceedsMaxMessageSize) = - dmp::Pallet::::queue_downward_message(&config, sender, notification_bytes) - { - // this should never happen unless the max downward message size is configured to an - // jokingly small number. - log::error!( - target: "runtime::hrmp", - "sending 'accept_open_channel::notification_bytes' failed." - ); - debug_assert!(false); - } + Self::send_to_para( + "accept_open_channel", + &config, + sender, + Self::wrap_notification(|| { + use xcm::opaque::latest::{prelude::*, Xcm}; + Xcm(vec![HrmpChannelAccepted { recipient: origin.into() }]) + }), + ); Ok(()) } @@ -1633,30 +1624,22 @@ impl Pallet { HrmpCloseChannelRequestsList::::append(channel_id.clone()); let config = configuration::ActiveConfig::::get(); - let notification_bytes = { - use parity_scale_codec::Encode as _; - use xcm::opaque::{latest::prelude::*, VersionedXcm}; - - VersionedXcm::from(Xcm(vec![HrmpChannelClosing { - initiator: u32::from(origin), - sender: u32::from(channel_id.sender), - recipient: u32::from(channel_id.recipient), - }])) - .encode() - }; let opposite_party = if origin == channel_id.sender { channel_id.recipient } else { channel_id.sender }; - if let Err(dmp::QueueDownwardMessageError::ExceedsMaxMessageSize) = - dmp::Pallet::::queue_downward_message(&config, opposite_party, notification_bytes) - { - // this should never happen unless the max downward message size is configured to an - // jokingly small number. - log::error!( - target: "runtime::hrmp", - "sending 'close_channel::notification_bytes' failed." - ); - debug_assert!(false); - } + + Self::send_to_para( + "close_channel", + &config, + opposite_party, + Self::wrap_notification(|| { + use xcm::opaque::latest::{prelude::*, Xcm}; + Xcm(vec![HrmpChannelClosing { + initiator: origin.into(), + sender: channel_id.sender.into(), + recipient: channel_id.recipient.into(), + }]) + }), + ); Ok(()) } @@ -1875,3 +1858,56 @@ impl Pallet { } } } + +impl Pallet { + /// Wraps HRMP XCM notifications to the most suitable XCM version for the destination para. + /// If the XCM version is unknown, the latest XCM version is used as a best effort. + fn wrap_notification( + mut notification: impl FnMut() -> xcm::opaque::latest::opaque::Xcm, + ) -> impl FnOnce(ParaId) -> primitives::DownwardMessage { + use xcm::{ + opaque::VersionedXcm, + prelude::{Junction, Location}, + WrapVersion, + }; + + // Return a closure that can prepare notifications. + move |dest| { + // Attempt to wrap the notification for the destination parachain. + T::VersionWrapper::wrap_version( + &Location::new(0, [Junction::Parachain(dest.into())]), + notification(), + ) + .unwrap_or_else(|_| { + // As a best effort, if we cannot resolve the version, fallback to using the latest + // version. + VersionedXcm::from(notification()) + }) + .encode() + } + } + + /// Sends/enqueues notification to the destination parachain. + fn send_to_para( + log_label: &str, + config: &HostConfiguration>, + dest: ParaId, + notification_bytes_for: impl FnOnce(ParaId) -> primitives::DownwardMessage, + ) { + // prepare notification + let notification_bytes = notification_bytes_for(dest); + + // try to enqueue + if let Err(dmp::QueueDownwardMessageError::ExceedsMaxMessageSize) = + dmp::Pallet::::queue_downward_message(&config, dest, notification_bytes) + { + // this should never happen unless the max downward message size is configured to a + // jokingly small number. + log::error!( + target: "runtime::hrmp", + "sending '{log_label}::notification_bytes' failed." + ); + debug_assert!(false); + } + } +} diff --git a/polkadot/runtime/parachains/src/hrmp/tests.rs b/polkadot/runtime/parachains/src/hrmp/tests.rs index 2f767ab7e1b19d311f53d194638bb23066c37d31..acfaa8f2d290510d9d11ed85872c281e8b9c7d85 100644 --- a/polkadot/runtime/parachains/src/hrmp/tests.rs +++ b/polkadot/runtime/parachains/src/hrmp/tests.rs @@ -22,13 +22,13 @@ use super::*; use crate::{ mock::{ deregister_parachain, new_test_ext, register_parachain, register_parachain_with_balance, - Hrmp, MockGenesisConfig, Paras, ParasShared, RuntimeEvent as MockEvent, RuntimeOrigin, - System, Test, + Dmp, Hrmp, MockGenesisConfig, Paras, ParasShared, RuntimeEvent as MockEvent, RuntimeOrigin, + System, Test, TestUsesOnlyStoredVersionWrapper, }, shared, }; use frame_support::{assert_noop, assert_ok, error::BadOrigin}; -use primitives::BlockNumber; +use primitives::{BlockNumber, InboundDownwardMessage}; use std::collections::BTreeMap; pub(crate) fn run_to_block(to: BlockNumber, new_session: Option>) { @@ -1004,3 +1004,140 @@ fn establish_channel_with_system_with_invalid_args() { Hrmp::assert_storage_consistency_exhaustive(); }); } + +#[test] +fn hrmp_notifications_works() { + use xcm::{ + opaque::{ + latest::{prelude::*, Xcm}, + VersionedXcm, + }, + IntoVersion, + }; + + let para_a = 2001.into(); + let para_a_origin: crate::Origin = 2001.into(); + let para_b = 2003.into(); + let para_b_origin: crate::Origin = 2003.into(); + + new_test_ext(GenesisConfigBuilder::default().build()).execute_with(|| { + // We need both A & B to be registered and alive parachains. + register_parachain(para_a); + register_parachain(para_b); + run_to_block(5, Some(vec![4, 5])); + + // set XCM versions for wrapper + + // for para_a -> `None`, means we will use latest. + TestUsesOnlyStoredVersionWrapper::set_version( + Location::new(0, [Junction::Parachain(para_a.into())]), + None, + ); + // for para_b -> `Some(latest - 1)`, means we will use latest-1 XCM version. + let previous_version = XCM_VERSION - 1; + TestUsesOnlyStoredVersionWrapper::set_version( + Location::new(0, [Junction::Parachain(para_b.into())]), + Some(previous_version), + ); + + let assert_notification_for = |sent_at, para_id, expected| { + assert_eq!( + Dmp::dmq_contents(para_id), + vec![InboundDownwardMessage { sent_at, msg: expected }] + ); + }; + + // init open channel requests + assert_ok!(Hrmp::hrmp_init_open_channel(para_a_origin.clone().into(), para_b, 2, 8)); + assert_ok!(Hrmp::hrmp_init_open_channel(para_b_origin.clone().into(), para_a, 2, 8)); + Hrmp::assert_storage_consistency_exhaustive(); + + // check dmp notications + assert_notification_for( + 5, + para_b, + VersionedXcm::from(Xcm(vec![HrmpNewChannelOpenRequest { + sender: u32::from(para_a), + max_capacity: 2, + max_message_size: 8, + }])) + .into_version(previous_version) + .expect("compatible") + .encode(), + ); + assert_notification_for( + 5, + para_a, + VersionedXcm::from(Xcm(vec![HrmpNewChannelOpenRequest { + sender: u32::from(para_b), + max_capacity: 2, + max_message_size: 8, + }])) + .encode(), + ); + let _ = Dmp::prune_dmq(para_a, 1000); + let _ = Dmp::prune_dmq(para_b, 1000); + + // accept open channel requests + assert_ok!(Hrmp::hrmp_accept_open_channel(para_a_origin.clone().into(), para_b)); + assert_ok!(Hrmp::hrmp_accept_open_channel(para_b_origin.clone().into(), para_a)); + Hrmp::assert_storage_consistency_exhaustive(); + + // check dmp notications + assert_notification_for( + 5, + para_b, + VersionedXcm::from(Xcm(vec![HrmpChannelAccepted { recipient: u32::from(para_a) }])) + .into_version(previous_version) + .expect("compatible") + .encode(), + ); + assert_notification_for( + 5, + para_a, + VersionedXcm::from(Xcm(vec![HrmpChannelAccepted { recipient: u32::from(para_b) }])) + .encode(), + ); + let _ = Dmp::prune_dmq(para_a, 1000); + let _ = Dmp::prune_dmq(para_b, 1000); + + // On Block 6: session change - creates channel. + run_to_block(6, Some(vec![6])); + assert!(channel_exists(para_a, para_b)); + + // close channel requests + assert_ok!(Hrmp::hrmp_close_channel( + para_a_origin.into(), + HrmpChannelId { sender: para_a, recipient: para_b } + )); + assert_ok!(Hrmp::hrmp_close_channel( + para_b_origin.into(), + HrmpChannelId { sender: para_b, recipient: para_a } + )); + Hrmp::assert_storage_consistency_exhaustive(); + + // check dmp notications + assert_notification_for( + 6, + para_b, + VersionedXcm::from(Xcm(vec![HrmpChannelClosing { + initiator: u32::from(para_a), + sender: u32::from(para_a), + recipient: u32::from(para_b), + }])) + .into_version(previous_version) + .expect("compatible") + .encode(), + ); + assert_notification_for( + 6, + para_a, + VersionedXcm::from(Xcm(vec![HrmpChannelClosing { + initiator: u32::from(para_b), + sender: u32::from(para_b), + recipient: u32::from(para_a), + }])) + .encode(), + ); + }); +} diff --git a/polkadot/runtime/parachains/src/inclusion/mod.rs b/polkadot/runtime/parachains/src/inclusion/mod.rs index 903d01aa5c9c9ff5ec9b2d5dd15ca2c2771fde00..31befefa32201b4bf343301c2956abcfbfb6a896 100644 --- a/polkadot/runtime/parachains/src/inclusion/mod.rs +++ b/polkadot/runtime/parachains/src/inclusion/mod.rs @@ -245,7 +245,7 @@ pub enum AggregateMessageOrigin { /// Identifies a UMP queue inside the `MessageQueue` pallet. /// /// It is written in verbose form since future variants like `Here` and `Bridged` are already -/// forseeable. +/// foreseeable. #[derive(Encode, Decode, Clone, MaxEncodedLen, Eq, PartialEq, RuntimeDebug, TypeInfo)] pub enum UmpQueueId { /// The message originated from this parachain. @@ -377,22 +377,45 @@ pub mod pallet { const LOG_TARGET: &str = "runtime::inclusion"; /// The reason that a candidate's outputs were rejected for. -#[derive(derive_more::From)] #[cfg_attr(feature = "std", derive(Debug))] -enum AcceptanceCheckErr { +enum AcceptanceCheckErr { HeadDataTooLarge, /// Code upgrades are not permitted at the current time. PrematureCodeUpgrade, /// The new runtime blob is too large. NewCodeTooLarge, /// The candidate violated this DMP acceptance criteria. - ProcessedDownwardMessages(dmp::ProcessedDownwardMessagesAcceptanceErr), + ProcessedDownwardMessages, /// The candidate violated this UMP acceptance criteria. - UpwardMessages(UmpAcceptanceCheckErr), + UpwardMessages, /// The candidate violated this HRMP watermark acceptance criteria. - HrmpWatermark(hrmp::HrmpWatermarkAcceptanceErr), + HrmpWatermark, /// The candidate violated this outbound HRMP acceptance criteria. - OutboundHrmp(hrmp::OutboundHrmpAcceptanceErr), + OutboundHrmp, +} + +impl From for AcceptanceCheckErr { + fn from(_: dmp::ProcessedDownwardMessagesAcceptanceErr) -> Self { + Self::ProcessedDownwardMessages + } +} + +impl From for AcceptanceCheckErr { + fn from(_: UmpAcceptanceCheckErr) -> Self { + Self::UpwardMessages + } +} + +impl From> for AcceptanceCheckErr { + fn from(_: hrmp::HrmpWatermarkAcceptanceErr) -> Self { + Self::HrmpWatermark + } +} + +impl From for AcceptanceCheckErr { + fn from(_: hrmp::OutboundHrmpAcceptanceErr) -> Self { + Self::OutboundHrmp + } } /// An error returned by [`Pallet::check_upward_messages`] that indicates a violation of one of @@ -1145,7 +1168,7 @@ const fn availability_threshold(n_validators: usize) -> usize { supermajority_threshold(n_validators) } -impl AcceptanceCheckErr { +impl AcceptanceCheckErr { /// Returns the same error so that it can be threaded through a needle of `DispatchError` and /// ultimately returned from a `Dispatchable`. fn strip_into_dispatch_err(self) -> Error { @@ -1154,10 +1177,10 @@ impl AcceptanceCheckErr { HeadDataTooLarge => Error::::HeadDataTooLarge, PrematureCodeUpgrade => Error::::PrematureCodeUpgrade, NewCodeTooLarge => Error::::NewCodeTooLarge, - ProcessedDownwardMessages(_) => Error::::IncorrectDownwardMessageHandling, - UpwardMessages(_) => Error::::InvalidUpwardMessages, - HrmpWatermark(_) => Error::::HrmpWatermarkMishandling, - OutboundHrmp(_) => Error::::InvalidOutboundHrmp, + ProcessedDownwardMessages => Error::::IncorrectDownwardMessageHandling, + UpwardMessages => Error::::InvalidUpwardMessages, + HrmpWatermark => Error::::HrmpWatermarkMishandling, + OutboundHrmp => Error::::InvalidOutboundHrmp, } } } @@ -1300,7 +1323,7 @@ impl CandidateCheckContext { upward_messages: &[primitives::UpwardMessage], hrmp_watermark: BlockNumberFor, horizontal_messages: &[primitives::OutboundHrmpMessage], - ) -> Result<(), AcceptanceCheckErr>> { + ) -> Result<(), AcceptanceCheckErr> { ensure!( head_data.0.len() <= self.config.max_head_data_size as _, AcceptanceCheckErr::HeadDataTooLarge, diff --git a/polkadot/runtime/parachains/src/mock.rs b/polkadot/runtime/parachains/src/mock.rs index c91f5be127cd4be06c5ca7f255804328bab7def7..a32c9d11b36e737e436d998ebddea1e5d38143b2 100644 --- a/polkadot/runtime/parachains/src/mock.rs +++ b/polkadot/runtime/parachains/src/mock.rs @@ -50,9 +50,16 @@ use sp_runtime::{ transaction_validity::TransactionPriority, BuildStorage, FixedU128, Perbill, Permill, }; -use sp_std::collections::vec_deque::VecDeque; -use std::{cell::RefCell, collections::HashMap}; -use xcm::v4::{Assets, Location, SendError, SendResult, SendXcm, Xcm, XcmHash}; +use sp_std::{ + cell::RefCell, + collections::{btree_map::BTreeMap, vec_deque::VecDeque}, +}; +use std::collections::HashMap; +use xcm::{ + prelude::XcmVersion, + v4::{Assets, Location, SendError, SendResult, SendXcm, Xcm, XcmHash}, + IntoVersion, VersionedXcm, WrapVersion, +}; type UncheckedExtrinsic = frame_system::mocking::MockUncheckedExtrinsic; type Block = frame_system::mocking::MockBlockU32; @@ -247,16 +254,41 @@ impl crate::paras::Config for Test { impl crate::dmp::Config for Test {} parameter_types! { - pub const FirstMessageFactorPercent: u64 = 100; pub const DefaultChannelSizeAndCapacityWithSystem: (u32, u32) = (4, 1); } +thread_local! { + pub static VERSION_WRAPPER: RefCell>> = RefCell::new(BTreeMap::new()); +} +/// Mock implementation of the [`WrapVersion`] trait which wraps XCM only for known/stored XCM +/// versions in the `VERSION_WRAPPER`. +pub struct TestUsesOnlyStoredVersionWrapper; +impl WrapVersion for TestUsesOnlyStoredVersionWrapper { + fn wrap_version( + dest: &Location, + xcm: impl Into>, + ) -> Result, ()> { + match VERSION_WRAPPER.with(|r| r.borrow().get(dest).map_or(None, |v| *v)) { + Some(v) => xcm.into().into_version(v), + None => return Err(()), + } + } +} +impl TestUsesOnlyStoredVersionWrapper { + pub fn set_version(location: Location, version: Option) { + VERSION_WRAPPER.with(|r| { + let _ = r.borrow_mut().entry(location).and_modify(|v| *v = version).or_insert(version); + }); + } +} + impl crate::hrmp::Config for Test { type RuntimeOrigin = RuntimeOrigin; type RuntimeEvent = RuntimeEvent; type ChannelManager = frame_system::EnsureRoot; type Currency = pallet_balances::Pallet; type DefaultChannelSizeAndCapacityWithSystem = DefaultChannelSizeAndCapacityWithSystem; + type VersionWrapper = TestUsesOnlyStoredVersionWrapper; type WeightInfo = crate::hrmp::TestWeightInfo; } @@ -387,6 +419,7 @@ impl assigner_coretime::Config for Test {} parameter_types! { pub const BrokerId: u32 = 10u32; + pub MaxXcmTransactWeight: Weight = Weight::from_parts(10_000_000, 10_000); } impl coretime::Config for Test { @@ -396,6 +429,7 @@ impl coretime::Config for Test { type BrokerId = BrokerId; type WeightInfo = crate::coretime::TestWeightInfo; type SendXcm = DummyXcmSender; + type MaxXcmTransactWeight = MaxXcmTransactWeight; } pub struct DummyXcmSender; diff --git a/polkadot/runtime/parachains/src/paras/mod.rs b/polkadot/runtime/parachains/src/paras/mod.rs index 6f67c4b8c03da1278f45532b8c9b1a1db4cf427e..36a693bcc8e29a7a2cbce1cb75a430322b88b58b 100644 --- a/polkadot/runtime/parachains/src/paras/mod.rs +++ b/polkadot/runtime/parachains/src/paras/mod.rs @@ -641,7 +641,7 @@ pub mod pallet { /// /// This is only used at genesis or by root. /// - /// TODO: Remove once coretime is the standard accross all chains. + /// TODO: Remove once coretime is the standard across all chains. type AssignCoretime: AssignCoretime; } diff --git a/polkadot/runtime/parachains/src/paras_inherent/mod.rs b/polkadot/runtime/parachains/src/paras_inherent/mod.rs index 2c6c48acc6d47d0e8176fe0b4702b9cfa6781af7..ac4cf5dc8d413397b6a740c6503f69e8d592e20d 100644 --- a/polkadot/runtime/parachains/src/paras_inherent/mod.rs +++ b/polkadot/runtime/parachains/src/paras_inherent/mod.rs @@ -1099,7 +1099,7 @@ fn limit_and_sanitize_disputes< } // Helper function for filtering candidates which don't pass the given predicate. When/if the first -// candidate which failes the predicate is found, all the other candidates that follow are dropped. +// candidate which failed the predicate is found, all the other candidates that follow are dropped. fn retain_candidates< T: inclusion::Config + paras::Config + inclusion::Config, F: FnMut(ParaId, &mut C) -> bool, diff --git a/polkadot/runtime/rococo/Cargo.toml b/polkadot/runtime/rococo/Cargo.toml index bbe19310f970ade37e25f5c1e2c983758c617412..4765de08c1a4f421a2ae9fa974236f034f09cb67 100644 --- a/polkadot/runtime/rococo/Cargo.toml +++ b/polkadot/runtime/rococo/Cargo.toml @@ -11,7 +11,7 @@ license.workspace = true workspace = true [dependencies] -parity-scale-codec = { version = "3.6.1", default-features = false, features = ["derive", "max-encoded-len"] } +parity-scale-codec = { version = "3.6.12", default-features = false, features = ["derive", "max-encoded-len"] } scale-info = { version = "2.11.1", default-features = false, features = ["derive"] } log = { workspace = true } serde = { workspace = true } @@ -268,6 +268,7 @@ runtime-benchmarks = [ "sp-staking/runtime-benchmarks", "xcm-builder/runtime-benchmarks", "xcm-executor/runtime-benchmarks", + "xcm-fee-payment-runtime-api/runtime-benchmarks", ] try-runtime = [ "frame-executive/try-runtime", diff --git a/polkadot/runtime/rococo/build.rs b/polkadot/runtime/rococo/build.rs index 0b7ee77b0d0d3b984a168f8cefe02a9e00e8f86c..403c31ff21c70f679059fa5b7e65478d309ba6a3 100644 --- a/polkadot/runtime/rococo/build.rs +++ b/polkadot/runtime/rococo/build.rs @@ -16,18 +16,11 @@ #[cfg(feature = "std")] fn main() { - substrate_wasm_builder::WasmBuilder::new() - .with_current_project() - .import_memory() - .export_heap_base() - .build(); + substrate_wasm_builder::WasmBuilder::build_using_defaults(); - substrate_wasm_builder::WasmBuilder::new() - .with_current_project() + substrate_wasm_builder::WasmBuilder::init_with_defaults() .set_file_name("fast_runtime_binary.rs") .enable_feature("fast-runtime") - .import_memory() - .export_heap_base() .build(); } diff --git a/polkadot/runtime/rococo/constants/src/lib.rs b/polkadot/runtime/rococo/constants/src/lib.rs index 9209045364c28bc585c548d6d2b30176bd52bb20..89d5deb86f1a0ff78a05255f9f5f3bdaca8333a6 100644 --- a/polkadot/runtime/rococo/constants/src/lib.rs +++ b/polkadot/runtime/rococo/constants/src/lib.rs @@ -57,7 +57,7 @@ pub mod time { // 1 in 4 blocks (on average, not counting collisions) will be primary babe blocks. // The choice of is done in accordance to the slot duration and expected target // block time, for safely resisting network delays of maximum two seconds. - // + // pub const PRIMARY_PROBABILITY: (u64, u64) = (1, 4); } diff --git a/polkadot/runtime/rococo/src/impls.rs b/polkadot/runtime/rococo/src/impls.rs index cf364b6ac7942753b6fd5f47dbf621d70c7ebcf7..ac7100d7858377dca5991e0d0308dc64577b9350 100644 --- a/polkadot/runtime/rococo/src/impls.rs +++ b/polkadot/runtime/rococo/src/impls.rs @@ -167,16 +167,11 @@ where }, ]); - let encoded_versioned_xcm = - VersionedXcm::V4(program).encode().try_into().map_err(|error| { - log::error!(target: "runtime::on_reap_identity", "XCM too large, error: {:?}", error); - pallet_xcm::Error::::XcmTooLarge - })?; // send - let _ = >::send_blob( + let _ = >::send( RawOrigin::Root.into(), Box::new(VersionedLocation::V4(destination)), - encoded_versioned_xcm, + Box::new(VersionedXcm::V4(program)), )?; Ok(()) } diff --git a/polkadot/runtime/rococo/src/lib.rs b/polkadot/runtime/rococo/src/lib.rs index 740a6240d39526cec795ba082848a480c8a7e3a3..c22d5c39b23303178e739f5a1f672ae8b762048a 100644 --- a/polkadot/runtime/rococo/src/lib.rs +++ b/polkadot/runtime/rococo/src/lib.rs @@ -25,7 +25,10 @@ use beefy_primitives::{ ecdsa_crypto::{AuthorityId as BeefyId, Signature as BeefySignature}, mmr::{BeefyDataProvider, MmrLeafVersion}, }; -use frame_support::dynamic_params::{dynamic_pallet_params, dynamic_params}; +use frame_support::{ + dynamic_params::{dynamic_pallet_params, dynamic_params}, + traits::FromContains, +}; use pallet_nis::WithMaximumOf; use parity_scale_codec::{Decode, Encode, MaxEncodedLen}; use primitives::{ @@ -40,7 +43,8 @@ use rococo_runtime_constants::system_parachain::BROKER_ID; use runtime_common::{ assigned_slots, auctions, claims, crowdloan, identity_migrator, impl_runtime_weights, impls::{ - LocatableAssetConverter, ToAuthor, VersionedLocatableAsset, VersionedLocationConverter, + ContainsParts, LocatableAssetConverter, ToAuthor, VersionedLocatableAsset, + VersionedLocationConverter, }, paras_registrar, paras_sudo_wrapper, prod_or_fast, slots, traits::{Leaser, OnSwap}, @@ -49,6 +53,7 @@ use runtime_common::{ use runtime_parachains::{ assigner_coretime as parachains_assigner_coretime, assigner_on_demand as parachains_assigner_on_demand, configuration as parachains_configuration, + configuration::ActiveConfigHrmpChannelSizeAndCapacityRatio, coretime, disputes as parachains_disputes, disputes::slashing as parachains_slashing, dmp as parachains_dmp, hrmp as parachains_hrmp, inclusion as parachains_inclusion, @@ -74,10 +79,10 @@ use frame_support::{ genesis_builder_helper::{build_state, get_preset}, parameter_types, traits::{ - fungible::HoldConsideration, Contains, EitherOf, EitherOfDiverse, EnsureOrigin, - EnsureOriginWithArg, EverythingBut, InstanceFilter, KeyOwnerProofSystem, - LinearStoragePrice, PrivilegeCmp, ProcessMessage, ProcessMessageError, StorageMapShim, - WithdrawReasons, + fungible::HoldConsideration, tokens::UnityOrOuterConversion, Contains, EitherOf, + EitherOfDiverse, EnsureOrigin, EnsureOriginWithArg, EverythingBut, InstanceFilter, + KeyOwnerProofSystem, LinearStoragePrice, PrivilegeCmp, ProcessMessage, ProcessMessageError, + StorageMapShim, WithdrawReasons, }, weights::{ConstantMultiplier, WeightMeter, WeightToFee as _}, PalletId, @@ -87,7 +92,7 @@ use pallet_grandpa::{fg_primitives, AuthorityId as GrandpaId}; use pallet_identity::legacy::IdentityInfo; use pallet_session::historical as session_historical; use pallet_transaction_payment::{FeeDetails, FungibleAdapter, RuntimeDispatchInfo}; -use sp_core::{ConstU128, OpaqueMetadata, H256}; +use sp_core::{ConstU128, ConstU8, OpaqueMetadata, H256}; use sp_runtime::{ create_runtime_str, generic, impl_opaque_keys, traits::{ @@ -129,7 +134,10 @@ use governance::{ pallet_custom_origins, AuctionAdmin, Fellows, GeneralAdmin, LeaseAdmin, Treasurer, TreasurySpender, }; -use xcm_fee_payment_runtime_api::Error as XcmPaymentApiError; +use xcm_fee_payment_runtime_api::{ + dry_run::{Error as XcmDryRunApiError, ExtrinsicDryRunEffects, XcmDryRunEffects}, + fees::Error as XcmPaymentApiError, +}; #[cfg(test)] mod tests; @@ -157,10 +165,10 @@ 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_010_000, + spec_version: 1_011_000, impl_version: 0, apis: RUNTIME_API_VERSIONS, - transaction_version: 24, + transaction_version: 25, state_version: 1, }; @@ -523,7 +531,15 @@ impl pallet_treasury::Config for Runtime { LocatableAssetConverter, VersionedLocationConverter, >; - type BalanceConverter = AssetRate; + type BalanceConverter = UnityOrOuterConversion< + ContainsParts< + FromContains< + xcm_builder::IsChildSystemParachain, + xcm_builder::IsParentsOnly>, + >, + >, + AssetRate, + >; type PayoutPeriod = PayoutSpendPeriod; #[cfg(feature = "runtime-benchmarks")] type BenchmarkHelper = runtime_common::impls::benchmarks::TreasuryArguments; @@ -1021,7 +1037,7 @@ impl pallet_message_queue::Config for Runtime { impl parachains_dmp::Config for Runtime {} parameter_types! { - pub const DefaultChannelSizeAndCapacityWithSystem: (u32, u32) = (51200, 500); + pub const HrmpChannelSizeAndCapacityWithSystemRatio: Percent = Percent::from_percent(100); } impl parachains_hrmp::Config for Runtime { @@ -1029,7 +1045,11 @@ impl parachains_hrmp::Config for Runtime { type RuntimeEvent = RuntimeEvent; type ChannelManager = EnsureRoot; type Currency = Balances; - type DefaultChannelSizeAndCapacityWithSystem = DefaultChannelSizeAndCapacityWithSystem; + type DefaultChannelSizeAndCapacityWithSystem = ActiveConfigHrmpChannelSizeAndCapacityRatio< + Runtime, + HrmpChannelSizeAndCapacityWithSystemRatio, + >; + type VersionWrapper = crate::XcmPallet; type WeightInfo = weights::runtime_parachains_hrmp::WeightInfo; } @@ -1045,6 +1065,7 @@ impl parachains_scheduler::Config for Runtime { parameter_types! { pub const BrokerId: u32 = BROKER_ID; + pub MaxXcmTransactWeight: Weight = Weight::from_parts(200_000_000, 20_000); } impl coretime::Config for Runtime { @@ -1054,6 +1075,7 @@ impl coretime::Config for Runtime { type BrokerId = BrokerId; type WeightInfo = weights::runtime_parachains_coretime::WeightInfo; type SendXcm = crate::xcm_config::XcmRouter; + type MaxXcmTransactWeight = MaxXcmTransactWeight; } parameter_types! { @@ -1745,26 +1767,34 @@ sp_api::impl_runtime_apis! { } } - impl xcm_fee_payment_runtime_api::XcmPaymentApi for Runtime { + impl xcm_fee_payment_runtime_api::fees::XcmPaymentApi for Runtime { fn query_acceptable_payment_assets(xcm_version: xcm::Version) -> Result, XcmPaymentApiError> { - if !matches!(xcm_version, 3 | 4) { - return Err(XcmPaymentApiError::UnhandledXcmVersion); - } - Ok([VersionedAssetId::V4(xcm_config::TokenLocation::get().into())] + let acceptable = vec![ + // native token + VersionedAssetId::from(AssetId(xcm_config::TokenLocation::get())) + ]; + + Ok(acceptable .into_iter() .filter_map(|asset| asset.into_version(xcm_version).ok()) .collect()) } fn query_weight_to_asset_fee(weight: Weight, asset: VersionedAssetId) -> Result { - let local_asset = VersionedAssetId::V4(xcm_config::TokenLocation::get().into()); - let asset = asset - .into_version(4) - .map_err(|_| XcmPaymentApiError::VersionedConversionFailed)?; - - if asset != local_asset { return Err(XcmPaymentApiError::AssetNotFound); } - - Ok(WeightToFee::weight_to_fee(&weight)) + match asset.try_as::() { + Ok(asset_id) if asset_id.0 == xcm_config::TokenLocation::get() => { + // for native token + Ok(WeightToFee::weight_to_fee(&weight)) + }, + Ok(asset_id) => { + log::trace!(target: "xcm::xcm_fee_payment_runtime_api", "query_weight_to_asset_fee - unhandled asset_id: {asset_id:?}!"); + Err(XcmPaymentApiError::AssetNotFound) + }, + Err(_) => { + log::trace!(target: "xcm::xcm_fee_payment_runtime_api", "query_weight_to_asset_fee - failed to convert asset: {asset:?}!"); + Err(XcmPaymentApiError::VersionedConversionFailed) + } + } } fn query_xcm_weight(message: VersionedXcm<()>) -> Result { @@ -1776,6 +1806,66 @@ sp_api::impl_runtime_apis! { } } + impl xcm_fee_payment_runtime_api::dry_run::XcmDryRunApi for Runtime { + fn dry_run_extrinsic(extrinsic: ::Extrinsic) -> Result, XcmDryRunApiError> { + use xcm_builder::InspectMessageQueues; + use xcm_executor::RecordXcm; + pallet_xcm::Pallet::::set_record_xcm(true); + let result = Executive::apply_extrinsic(extrinsic).map_err(|error| { + log::error!( + target: "xcm::XcmDryRunApi::dry_run_extrinsic", + "Applying extrinsic failed with error {:?}", + error, + ); + XcmDryRunApiError::InvalidExtrinsic + })?; + let local_xcm = pallet_xcm::Pallet::::recorded_xcm(); + let forwarded_xcms = xcm_config::XcmRouter::get_messages(); + let events: Vec = System::read_events_no_consensus().map(|record| record.event.clone()).collect(); + Ok(ExtrinsicDryRunEffects { + local_xcm: local_xcm.map(VersionedXcm::<()>::V4), + forwarded_xcms, + emitted_events: events, + execution_result: result, + }) + } + + fn dry_run_xcm(origin_location: VersionedLocation, xcm: VersionedXcm) -> Result, XcmDryRunApiError> { + use xcm_builder::InspectMessageQueues; + let origin_location: Location = origin_location.try_into().map_err(|error| { + log::error!( + target: "xcm::XcmDryRunApi::dry_run_xcm", + "Location version conversion failed with error: {:?}", + error, + ); + XcmDryRunApiError::VersionedConversionFailed + })?; + let xcm: Xcm = xcm.try_into().map_err(|error| { + log::error!( + target: "xcm::XcmDryRunApi::dry_run_xcm", + "Xcm version conversion failed with error {:?}", + error, + ); + XcmDryRunApiError::VersionedConversionFailed + })?; + let mut hash = xcm.using_encoded(sp_io::hashing::blake2_256); + let result = xcm_executor::XcmExecutor::::prepare_and_execute( + origin_location, + xcm, + &mut hash, + Weight::MAX, // Max limit available for execution. + Weight::zero(), + ); + let forwarded_xcms = xcm_config::XcmRouter::get_messages(); + let events: Vec = System::read_events_no_consensus().map(|record| record.event.clone()).collect(); + Ok(XcmDryRunEffects { + forwarded_xcms, + emitted_events: events, + execution_result: result, + }) + } + } + impl sp_api::Metadata for Runtime { fn metadata() -> OpaqueMetadata { OpaqueMetadata::new(Runtime::metadata().into()) @@ -2004,7 +2094,7 @@ sp_api::impl_runtime_apis! { } fn submit_report_equivocation_unsigned_extrinsic( - equivocation_proof: beefy_primitives::EquivocationProof< + equivocation_proof: beefy_primitives::DoubleVotingProof< BlockNumber, BeefyId, BeefySignature, @@ -2044,7 +2134,7 @@ sp_api::impl_runtime_apis! { fn generate_proof( block_numbers: Vec, best_known_block_number: Option, - ) -> Result<(Vec, mmr::Proof), mmr::Error> { + ) -> Result<(Vec, mmr::LeafProof), mmr::Error> { Mmr::generate_proof(block_numbers, best_known_block_number).map( |(leaves, proof)| { ( @@ -2058,7 +2148,7 @@ sp_api::impl_runtime_apis! { ) } - fn verify_proof(leaves: Vec, proof: mmr::Proof) + fn verify_proof(leaves: Vec, proof: mmr::LeafProof) -> Result<(), mmr::Error> { let leaves = leaves.into_iter().map(|leaf| @@ -2071,7 +2161,7 @@ sp_api::impl_runtime_apis! { fn verify_proof_stateless( root: mmr::Hash, leaves: Vec, - proof: mmr::Proof + proof: mmr::LeafProof ) -> Result<(), mmr::Error> { let nodes = leaves.into_iter().map(|leaf|mmr::DataOrHash::Data(leaf.into_opaque_leaf())).collect(); pallet_mmr::verify_leaves_proof::(root, nodes, proof) diff --git a/polkadot/runtime/rococo/src/weights/pallet_balances_balances.rs b/polkadot/runtime/rococo/src/weights/pallet_balances_balances.rs index 1b0ae1eeece41b10aff0c65181fe757cfdc4dd0e..d37bb9369c688b596b22c25da25463719c428e32 100644 --- a/polkadot/runtime/rococo/src/weights/pallet_balances_balances.rs +++ b/polkadot/runtime/rococo/src/weights/pallet_balances_balances.rs @@ -16,10 +16,10 @@ //! 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-05-08, 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-unxyhko3-project-674-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` //! WASM-EXECUTION: `Compiled`, CHAIN: `Some("rococo-dev")`, DB CACHE: 1024 // Executed Command: @@ -54,8 +54,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: 44_771_000 picoseconds. + Weight::from_parts(45_635_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 +66,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_225_000 picoseconds. + Weight::from_parts(35_622_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 +78,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_443_000 picoseconds. + Weight::from_parts(12_944_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 +90,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_189_000 picoseconds. + Weight::from_parts(17_922_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 +102,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: 45_925_000 picoseconds. + Weight::from_parts(47_021_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 +114,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: 43_775_000 picoseconds. + Weight::from_parts(44_955_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 +126,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_358_000 picoseconds. + Weight::from_parts(15_958_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 +140,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_283_000 picoseconds. + Weight::from_parts(14_888_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: 8_164 + .saturating_add(Weight::from_parts(13_730_103, 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 +153,24 @@ 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_167_000 picoseconds. + Weight::from_parts(5_505_000, 0) + .saturating_add(Weight::from_parts(0, 0)) + } + fn burn_allow_death() -> Weight { + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 27_587_000 picoseconds. + Weight::from_parts(28_493_000, 0) + .saturating_add(Weight::from_parts(0, 0)) + } + fn burn_keep_alive() -> Weight { + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 18_023_000 picoseconds. + Weight::from_parts(18_694_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..706653aeb7692188103102bbe8aba72bbd6acb30 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,10 +16,10 @@ //! 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-05-08, 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-unxyhko3-project-674-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` //! WASM-EXECUTION: `Compiled`, CHAIN: `Some("rococo-dev")`, DB CACHE: 1024 // Executed Command: @@ -56,8 +56,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_331_000 picoseconds. + Weight::from_parts(43_215_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 +70,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_674_000 picoseconds. + Weight::from_parts(33_564_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 +82,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: 9_813_000 picoseconds. + Weight::from_parts(10_111_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 +96,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_467_000 picoseconds. + Weight::from_parts(17_088_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 +110,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: 43_846_000 picoseconds. + Weight::from_parts(45_059_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 +124,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: 41_260_000 picoseconds. + Weight::from_parts(42_367_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 +138,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: 14_914_000 picoseconds. + Weight::from_parts(15_631_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 +154,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_630_000 picoseconds. + Weight::from_parts(14_924_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: 15_311 + .saturating_add(Weight::from_parts(14_920_201, 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 +167,32 @@ 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_193_000 picoseconds. + Weight::from_parts(5_403_000, 0) .saturating_add(Weight::from_parts(0, 0)) } + /// Storage: `NisCounterpartBalances::Account` (r:1 w:1) + /// Proof: `NisCounterpartBalances::Account` (`max_values`: None, `max_size`: Some(112), added: 2587, mode: `MaxEncodedLen`) + fn burn_allow_death() -> Weight { + // Proof Size summary in bytes: + // Measured: `103` + // Estimated: `3577` + // Minimum execution time: 27_002_000 picoseconds. + Weight::from_parts(27_785_000, 0) + .saturating_add(Weight::from_parts(0, 3577)) + .saturating_add(T::DbWeight::get().reads(1)) + .saturating_add(T::DbWeight::get().writes(1)) + } + /// Storage: `NisCounterpartBalances::Account` (r:1 w:1) + /// Proof: `NisCounterpartBalances::Account` (`max_values`: None, `max_size`: Some(112), added: 2587, mode: `MaxEncodedLen`) + fn burn_keep_alive() -> Weight { + // Proof Size summary in bytes: + // Measured: `103` + // Estimated: `3577` + // Minimum execution time: 17_533_000 picoseconds. + Weight::from_parts(18_338_000, 0) + .saturating_add(Weight::from_parts(0, 3577)) + .saturating_add(T::DbWeight::get().reads(1)) + .saturating_add(T::DbWeight::get().writes(1)) + } } diff --git a/polkadot/runtime/rococo/src/weights/pallet_xcm.rs b/polkadot/runtime/rococo/src/weights/pallet_xcm.rs index 42972baa1c830baa820fc5c72b35f346daaf27d0..5544ca44658cc09fa51cd75679ba90132eb16444 100644 --- a/polkadot/runtime/rococo/src/weights/pallet_xcm.rs +++ b/polkadot/runtime/rococo/src/weights/pallet_xcm.rs @@ -17,9 +17,9 @@ //! Autogenerated weights for `pallet_xcm` //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 32.0.0 -//! DATE: 2024-03-21, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! DATE: 2024-02-20, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` //! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `runner-h2rr8wx7-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: @@ -60,26 +60,8 @@ impl pallet_xcm::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `180` // Estimated: `3645` - // Minimum execution time: 24_724_000 picoseconds. - Weight::from_parts(25_615_000, 0) - .saturating_add(Weight::from_parts(0, 3645)) - .saturating_add(T::DbWeight::get().reads(4)) - .saturating_add(T::DbWeight::get().writes(2)) - } - /// 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 send_blob() -> Weight { - // Proof Size summary in bytes: - // Measured: `180` - // Estimated: `3645` - // Minimum execution time: 24_709_000 picoseconds. - Weight::from_parts(25_326_000, 0) + // Minimum execution time: 25_043_000 picoseconds. + Weight::from_parts(25_682_000, 0) .saturating_add(Weight::from_parts(0, 3645)) .saturating_add(T::DbWeight::get().reads(4)) .saturating_add(T::DbWeight::get().writes(2)) @@ -98,8 +80,8 @@ impl pallet_xcm::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `180` // Estimated: `3645` - // Minimum execution time: 106_600_000 picoseconds. - Weight::from_parts(110_781_000, 0) + // Minimum execution time: 107_570_000 picoseconds. + Weight::from_parts(109_878_000, 0) .saturating_add(Weight::from_parts(0, 3645)) .saturating_add(T::DbWeight::get().reads(5)) .saturating_add(T::DbWeight::get().writes(3)) @@ -118,8 +100,8 @@ impl pallet_xcm::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `232` // Estimated: `3697` - // Minimum execution time: 103_030_000 picoseconds. - Weight::from_parts(106_018_000, 0) + // Minimum execution time: 106_341_000 picoseconds. + Weight::from_parts(109_135_000, 0) .saturating_add(Weight::from_parts(0, 3697)) .saturating_add(T::DbWeight::get().reads(5)) .saturating_add(T::DbWeight::get().writes(3)) @@ -138,8 +120,8 @@ impl pallet_xcm::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `180` // Estimated: `3645` - // Minimum execution time: 107_017_000 picoseconds. - Weight::from_parts(109_214_000, 0) + // Minimum execution time: 108_372_000 picoseconds. + Weight::from_parts(112_890_000, 0) .saturating_add(Weight::from_parts(0, 3645)) .saturating_add(T::DbWeight::get().reads(5)) .saturating_add(T::DbWeight::get().writes(3)) @@ -148,16 +130,8 @@ impl pallet_xcm::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 6_864_000 picoseconds. - Weight::from_parts(7_135_000, 0) - .saturating_add(Weight::from_parts(0, 0)) - } - fn execute_blob() -> Weight { - // Proof Size summary in bytes: - // Measured: `0` - // Estimated: `0` - // Minimum execution time: 6_955_000 picoseconds. - Weight::from_parts(7_165_000, 0) + // Minimum execution time: 6_957_000 picoseconds. + Weight::from_parts(7_417_000, 0) .saturating_add(Weight::from_parts(0, 0)) } /// Storage: `XcmPallet::SupportedVersion` (r:0 w:1) @@ -166,8 +140,8 @@ impl pallet_xcm::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 6_827_000 picoseconds. - Weight::from_parts(7_211_000, 0) + // Minimum execution time: 7_053_000 picoseconds. + Weight::from_parts(7_462_000, 0) .saturating_add(Weight::from_parts(0, 0)) .saturating_add(T::DbWeight::get().writes(1)) } @@ -175,8 +149,8 @@ impl pallet_xcm::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_788_000 picoseconds. - Weight::from_parts(2_021_000, 0) + // Minimum execution time: 1_918_000 picoseconds. + Weight::from_parts(2_037_000, 0) .saturating_add(Weight::from_parts(0, 0)) } /// Storage: `XcmPallet::VersionNotifiers` (r:1 w:1) @@ -197,8 +171,8 @@ impl pallet_xcm::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `180` // Estimated: `3645` - // Minimum execution time: 30_627_000 picoseconds. - Weight::from_parts(31_350_000, 0) + // Minimum execution time: 30_417_000 picoseconds. + Weight::from_parts(31_191_000, 0) .saturating_add(Weight::from_parts(0, 3645)) .saturating_add(T::DbWeight::get().reads(6)) .saturating_add(T::DbWeight::get().writes(5)) @@ -219,8 +193,8 @@ impl pallet_xcm::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `360` // Estimated: `3825` - // Minimum execution time: 36_688_000 picoseconds. - Weight::from_parts(37_345_000, 0) + // Minimum execution time: 36_666_000 picoseconds. + Weight::from_parts(37_779_000, 0) .saturating_add(Weight::from_parts(0, 3825)) .saturating_add(T::DbWeight::get().reads(5)) .saturating_add(T::DbWeight::get().writes(4)) @@ -231,8 +205,8 @@ impl pallet_xcm::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_829_000 picoseconds. - Weight::from_parts(1_986_000, 0) + // Minimum execution time: 1_869_000 picoseconds. + Weight::from_parts(2_003_000, 0) .saturating_add(Weight::from_parts(0, 0)) .saturating_add(T::DbWeight::get().writes(1)) } @@ -242,8 +216,8 @@ impl pallet_xcm::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `22` // Estimated: `13387` - // Minimum execution time: 16_104_000 picoseconds. - Weight::from_parts(16_464_000, 0) + // Minimum execution time: 16_188_000 picoseconds. + Weight::from_parts(16_435_000, 0) .saturating_add(Weight::from_parts(0, 13387)) .saturating_add(T::DbWeight::get().reads(5)) .saturating_add(T::DbWeight::get().writes(2)) @@ -254,8 +228,8 @@ impl pallet_xcm::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `26` // Estimated: `13391` - // Minimum execution time: 16_267_000 picoseconds. - Weight::from_parts(16_675_000, 0) + // Minimum execution time: 16_431_000 picoseconds. + Weight::from_parts(16_935_000, 0) .saturating_add(Weight::from_parts(0, 13391)) .saturating_add(T::DbWeight::get().reads(5)) .saturating_add(T::DbWeight::get().writes(2)) @@ -266,8 +240,8 @@ impl pallet_xcm::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `40` // Estimated: `15880` - // Minimum execution time: 18_487_000 picoseconds. - Weight::from_parts(19_102_000, 0) + // Minimum execution time: 18_460_000 picoseconds. + Weight::from_parts(18_885_000, 0) .saturating_add(Weight::from_parts(0, 15880)) .saturating_add(T::DbWeight::get().reads(6)) } @@ -285,8 +259,8 @@ impl pallet_xcm::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `216` // Estimated: `6156` - // Minimum execution time: 29_603_000 picoseconds. - Weight::from_parts(31_002_000, 0) + // Minimum execution time: 29_623_000 picoseconds. + Weight::from_parts(30_661_000, 0) .saturating_add(Weight::from_parts(0, 6156)) .saturating_add(T::DbWeight::get().reads(6)) .saturating_add(T::DbWeight::get().writes(3)) @@ -297,8 +271,8 @@ impl pallet_xcm::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `69` // Estimated: `10959` - // Minimum execution time: 12_183_000 picoseconds. - Weight::from_parts(12_587_000, 0) + // Minimum execution time: 12_043_000 picoseconds. + Weight::from_parts(12_360_000, 0) .saturating_add(Weight::from_parts(0, 10959)) .saturating_add(T::DbWeight::get().reads(4)) } @@ -308,8 +282,8 @@ impl pallet_xcm::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `33` // Estimated: `13398` - // Minimum execution time: 16_372_000 picoseconds. - Weight::from_parts(16_967_000, 0) + // Minimum execution time: 16_511_000 picoseconds. + Weight::from_parts(17_011_000, 0) .saturating_add(Weight::from_parts(0, 13398)) .saturating_add(T::DbWeight::get().reads(5)) .saturating_add(T::DbWeight::get().writes(2)) @@ -328,8 +302,8 @@ impl pallet_xcm::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `216` // Estimated: `13581` - // Minimum execution time: 38_904_000 picoseconds. - Weight::from_parts(39_983_000, 0) + // Minimum execution time: 39_041_000 picoseconds. + Weight::from_parts(39_883_000, 0) .saturating_add(Weight::from_parts(0, 13581)) .saturating_add(T::DbWeight::get().reads(9)) .saturating_add(T::DbWeight::get().writes(4)) @@ -342,8 +316,8 @@ impl pallet_xcm::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `0` // Estimated: `1485` - // Minimum execution time: 2_067_000 picoseconds. - Weight::from_parts(2_195_000, 0) + // Minimum execution time: 2_030_000 picoseconds. + Weight::from_parts(2_150_000, 0) .saturating_add(Weight::from_parts(0, 1485)) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(2)) @@ -354,8 +328,8 @@ impl pallet_xcm::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `7576` // Estimated: `11041` - // Minimum execution time: 23_982_000 picoseconds. - Weight::from_parts(24_409_000, 0) + // Minimum execution time: 22_615_000 picoseconds. + Weight::from_parts(23_008_000, 0) .saturating_add(Weight::from_parts(0, 11041)) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(1)) @@ -366,8 +340,8 @@ impl pallet_xcm::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `23` // Estimated: `3488` - // Minimum execution time: 33_430_000 picoseconds. - Weight::from_parts(34_433_000, 0) + // 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/runtime_parachains_hrmp.rs b/polkadot/runtime/rococo/src/weights/runtime_parachains_hrmp.rs index 97b84155b36a6adb2258a714e65bf5c70bc9aa50..572ecc7d4110f0335b18a3c276032b4f6d285db5 100644 --- a/polkadot/runtime/rococo/src/weights/runtime_parachains_hrmp.rs +++ b/polkadot/runtime/rococo/src/weights/runtime_parachains_hrmp.rs @@ -16,25 +16,26 @@ //! 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-05-01, 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-unxyhko3-project-674-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` +//! WASM-EXECUTION: `Compiled`, CHAIN: `Some("rococo-dev")`, DB CACHE: 1024 // Executed Command: -// ./target/production/polkadot +// target/production/polkadot // benchmark // pallet -// --chain=rococo-dev // --steps=50 // --repeat=20 -// --pallet=runtime_parachains::hrmp // --extrinsic=* -// --execution=wasm // --wasm-execution=compiled -// --header=./file_header.txt -// --output=./runtime/rococo/src/weights/runtime_parachains_hrmp.rs +// --heap-pages=4096 +// --json-file=/builds/parity/mirrors/polkadot-sdk/.git/.artifacts/bench.json +// --pallet=runtime_parachains::hrmp +// --chain=rococo-dev +// --header=./polkadot/file_header.txt +// --output=./polkadot/runtime/rococo/src/weights/ #![cfg_attr(rustfmt, rustfmt_skip)] #![allow(unused_parens)] @@ -47,105 +48,103 @@ 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: `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 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: 37_574_000 picoseconds. + Weight::from_parts(38_789_000, 0) + .saturating_add(Weight::from_parts(0, 3953)) + .saturating_add(T::DbWeight::get().reads(9)) .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: `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 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: 34_560_000 picoseconds. + Weight::from_parts(35_760_000, 0) + .saturating_add(Weight::from_parts(0, 3943)) + .saturating_add(T::DbWeight::get().reads(6)) .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: `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 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)) + // Measured: `591` + // Estimated: `4056` + // Minimum execution time: 35_367_000 picoseconds. + Weight::from_parts(37_000_000, 0) + .saturating_add(Weight::from_parts(0, 4056)) .saturating_add(T::DbWeight::get().reads(6)) .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_134_420_000 picoseconds. + Weight::from_parts(1_144_822_000, 0) + .saturating_add(Weight::from_parts(0, 3759)) + // Standard Error: 101_380 + .saturating_add(Weight::from_parts(3_325_898, 0).saturating_mul(i.into())) + // Standard Error: 101_380 + .saturating_add(Weight::from_parts(3_338_565, 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 +154,141 @@ 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: 5_652_000 picoseconds. + Weight::from_parts(2_857_824, 0) + .saturating_add(Weight::from_parts(0, 1980)) + // Standard Error: 26_044 + .saturating_add(Weight::from_parts(20_088_467, 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_692_000 picoseconds. + Weight::from_parts(6_637_146, 0) + .saturating_add(Weight::from_parts(0, 1828)) + // Standard Error: 10_238 + .saturating_add(Weight::from_parts(12_201_629, 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: 18_920_000 picoseconds. + Weight::from_parts(27_314_843, 0) + .saturating_add(Weight::from_parts(0, 4328)) + // Standard Error: 2_127 + .saturating_add(Weight::from_parts(90_200, 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_502_000 picoseconds. + Weight::from_parts(6_477_323, 0) + .saturating_add(Weight::from_parts(0, 1755)) + // Standard Error: 3_416 + .saturating_add(Weight::from_parts(3_149_674, 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: `XcmPallet::SupportedVersion` (r:2 w:0) + /// Proof: `XcmPallet::SupportedVersion` (`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)) + // Measured: `488 + c * (235 ±0)` + // Estimated: `6428 + c * (235 ±0)` + // Minimum execution time: 56_234_000 picoseconds. + Weight::from_parts(58_259_646, 0) + .saturating_add(Weight::from_parts(0, 6428)) + // Standard Error: 160_596 + .saturating_add(Weight::from_parts(11_178_353, 0).saturating_mul(c.into())) .saturating_add(T::DbWeight::get().reads(14)) .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`) @@ -301,6 +302,8 @@ impl runtime_parachains::hrmp::WeightInfo for WeightInf /// 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: `XcmPallet::SupportedVersion` (r:2 w:0) + /// Proof: `XcmPallet::SupportedVersion` (`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) @@ -311,34 +314,56 @@ 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)) - .saturating_add(T::DbWeight::get().reads(12)) + // Measured: `488` + // Estimated: `6428` + // Minimum execution time: 56_035_000 picoseconds. + Weight::from_parts(58_217_000, 0) + .saturating_add(Weight::from_parts(0, 6428)) + .saturating_add(T::DbWeight::get().reads(14)) .saturating_add(T::DbWeight::get().writes(8)) } /// Storage: `Hrmp::HrmpChannels` (r:1 w:1) /// 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: 11_477_000 picoseconds. + Weight::from_parts(11_845_000, 0) + .saturating_add(Weight::from_parts(0, 3761)) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(1)) } + /// Storage: `Paras::ParaLifecycles` (r:2 w:0) + /// Proof: `Paras::ParaLifecycles` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `Hrmp::HrmpOpenChannelRequests` (r:2 w:2) + /// Proof: `Hrmp::HrmpOpenChannelRequests` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `Hrmp::HrmpChannels` (r:2 w:0) + /// Proof: `Hrmp::HrmpChannels` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `Hrmp::HrmpEgressChannelsIndex` (r:2 w:0) + /// Proof: `Hrmp::HrmpEgressChannelsIndex` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `Hrmp::HrmpOpenChannelRequestCount` (r:2 w:2) + /// 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: `XcmPallet::SupportedVersion` (r:2 w:0) + /// Proof: `XcmPallet::SupportedVersion` (`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:2 w:0) + /// Proof: `Hrmp::HrmpIngressChannelsIndex` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `Hrmp::HrmpAcceptedChannelRequestCount` (r:2 w:2) + /// Proof: `Hrmp::HrmpAcceptedChannelRequestCount` (`max_values`: None, `max_size`: None, mode: `Measured`) fn establish_channel_with_system() -> 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)) - .saturating_add(T::DbWeight::get().reads(12)) - .saturating_add(T::DbWeight::get().writes(8)) + // Measured: `488` + // Estimated: `6428` + // Minimum execution time: 95_305_000 picoseconds. + Weight::from_parts(97_323_000, 0) + .saturating_add(Weight::from_parts(0, 6428)) + .saturating_add(T::DbWeight::get().reads(21)) + .saturating_add(T::DbWeight::get().writes(11)) } } diff --git a/polkadot/runtime/rococo/src/xcm_config.rs b/polkadot/runtime/rococo/src/xcm_config.rs index c7063bd7ad616c2e5cb7b2e3f8c397087e522c33..decbc795143f006ee50cc98d860e795165269cf5 100644 --- a/polkadot/runtime/rococo/src/xcm_config.rs +++ b/polkadot/runtime/rococo/src/xcm_config.rs @@ -224,6 +224,7 @@ impl xcm_executor::Config for XcmConfig { type HrmpNewChannelOpenRequestHandler = (); type HrmpChannelAcceptedHandler = (); type HrmpChannelClosingHandler = (); + type XcmRecorder = XcmPallet; } parameter_types! { diff --git a/polkadot/runtime/test-runtime/Cargo.toml b/polkadot/runtime/test-runtime/Cargo.toml index 35fb684597e7d3f8082478353a643ee2adf2481d..596cc974c82599289eb9203704d37af81811b004 100644 --- a/polkadot/runtime/test-runtime/Cargo.toml +++ b/polkadot/runtime/test-runtime/Cargo.toml @@ -11,14 +11,10 @@ license.workspace = true 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"] } +parity-scale-codec = { version = "3.6.12", default-features = false, features = ["derive"] } log = { workspace = true } -rustc-hex = { version = "2.1.0", default-features = false } scale-info = { version = "2.11.1", default-features = false, features = ["derive"] } 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 } babe-primitives = { package = "sp-consensus-babe", path = "../../../substrate/primitives/consensus/babe", default-features = false } @@ -63,7 +59,6 @@ pallet-vesting = { path = "../../../substrate/frame/vesting", default-features = runtime-common = { package = "polkadot-runtime-common", path = "../common", default-features = false } primitives = { package = "polkadot-primitives", path = "../../primitives", default-features = false } pallet-xcm = { path = "../../xcm/pallet-xcm", default-features = false } -polkadot-parachain-primitives = { path = "../../parachain", default-features = false } polkadot-runtime-parachains = { path = "../parachains", default-features = false } xcm-builder = { package = "staging-xcm-builder", path = "../../xcm/xcm-builder", default-features = false } xcm-executor = { package = "staging-xcm-executor", path = "../../xcm/xcm-executor", default-features = false } @@ -92,7 +87,6 @@ std = [ "authority-discovery-primitives/std", "babe-primitives/std", "beefy-primitives/std", - "bitvec/std", "block-builder-api/std", "frame-election-provider-support/std", "frame-executive/std", @@ -118,14 +112,11 @@ std = [ "pallet-vesting/std", "pallet-xcm/std", "parity-scale-codec/std", - "polkadot-parachain-primitives/std", "polkadot-runtime-parachains/std", "primitives/std", "runtime-common/std", - "rustc-hex/std", "scale-info/std", "serde/std", - "serde_derive", "sp-api/std", "sp-core/std", "sp-genesis-builder/std", @@ -157,7 +148,6 @@ runtime-benchmarks = [ "pallet-timestamp/runtime-benchmarks", "pallet-vesting/runtime-benchmarks", "pallet-xcm/runtime-benchmarks", - "polkadot-parachain-primitives/runtime-benchmarks", "polkadot-runtime-parachains/runtime-benchmarks", "primitives/runtime-benchmarks", "runtime-common/runtime-benchmarks", diff --git a/polkadot/runtime/test-runtime/build.rs b/polkadot/runtime/test-runtime/build.rs index 404ba3f2fdbdfdc68d35d0dd08958448f30d90c6..caf24317d0b3e1e30bdc63ba2a5e6388b820be57 100644 --- a/polkadot/runtime/test-runtime/build.rs +++ b/polkadot/runtime/test-runtime/build.rs @@ -17,9 +17,5 @@ use substrate_wasm_builder::WasmBuilder; fn main() { - WasmBuilder::new() - .with_current_project() - .import_memory() - .export_heap_base() - .build() + WasmBuilder::build_using_defaults(); } diff --git a/polkadot/runtime/test-runtime/constants/Cargo.toml b/polkadot/runtime/test-runtime/constants/Cargo.toml index 2b387bbd3072a91bc00afa7326d93f66a644f39e..5b8a4d7a051af84701065a3836d813630011bd0c 100644 --- a/polkadot/runtime/test-runtime/constants/Cargo.toml +++ b/polkadot/runtime/test-runtime/constants/Cargo.toml @@ -14,18 +14,12 @@ smallvec = "1.8.0" frame-support = { path = "../../../../substrate/frame/support", default-features = false } primitives = { package = "polkadot-primitives", path = "../../../primitives", default-features = false } -runtime-common = { package = "polkadot-runtime-common", path = "../../common", default-features = false } sp-runtime = { path = "../../../../substrate/primitives/runtime", default-features = false } -sp-weights = { path = "../../../../substrate/primitives/weights", default-features = false } -sp-core = { path = "../../../../substrate/primitives/core", default-features = false } [features] default = ["std"] std = [ "frame-support/std", "primitives/std", - "runtime-common/std", - "sp-core/std", "sp-runtime/std", - "sp-weights/std", ] diff --git a/polkadot/runtime/test-runtime/constants/src/lib.rs b/polkadot/runtime/test-runtime/constants/src/lib.rs index 77c83b063cf0f8fb7771545faa074b315fa75a03..2422762ca38e925cf9666f1c42e2aa10cf70dd90 100644 --- a/polkadot/runtime/test-runtime/constants/src/lib.rs +++ b/polkadot/runtime/test-runtime/constants/src/lib.rs @@ -45,7 +45,7 @@ pub mod time { // 1 in 4 blocks (on average, not counting collisions) will be primary babe blocks. // The choice of is done in accordance to the slot duration and expected target // block time, for safely resisting network delays of maximum two seconds. - // + // pub const PRIMARY_PROBABILITY: (u64, u64) = (1, 4); } diff --git a/polkadot/runtime/test-runtime/src/lib.rs b/polkadot/runtime/test-runtime/src/lib.rs index 514643c0a20169291cde30fd9dfc259bc936853f..9eb0fcca6678b234ab2b744e3fbf2f6f837cbdbe 100644 --- a/polkadot/runtime/test-runtime/src/lib.rs +++ b/polkadot/runtime/test-runtime/src/lib.rs @@ -29,7 +29,9 @@ use sp_std::{ use polkadot_runtime_parachains::{ assigner_parachains as parachains_assigner_parachains, - configuration as parachains_configuration, disputes as parachains_disputes, + configuration as parachains_configuration, + configuration::ActiveConfigHrmpChannelSizeAndCapacityRatio, + disputes as parachains_disputes, disputes::slashing as parachains_slashing, dmp as parachains_dmp, hrmp as parachains_hrmp, inclusion as parachains_inclusion, initializer as parachains_initializer, origin as parachains_origin, paras as parachains_paras, @@ -78,7 +80,7 @@ use sp_runtime::{ SaturatedConversion, StaticLookup, Verify, }, transaction_validity::{TransactionPriority, TransactionSource, TransactionValidity}, - ApplyExtrinsicResult, FixedU128, KeyTypeId, Perbill, + ApplyExtrinsicResult, FixedU128, KeyTypeId, Perbill, Percent, }; use sp_staking::SessionIndex; #[cfg(any(feature = "std", test))] @@ -313,7 +315,6 @@ parameter_types! { pub const RewardCurve: &'static PiecewiseLinear<'static> = &REWARD_CURVE; pub const MaxExposurePageSize: u32 = 64; pub const MaxNominators: u32 = 256; - pub storage OffendingValidatorsThreshold: Perbill = Perbill::from_percent(17); pub const MaxAuthorities: u32 = 100_000; pub const OnChainMaxWinners: u32 = u32::MAX; // Unbounded number of election targets and voters. @@ -349,7 +350,6 @@ impl pallet_staking::Config for Runtime { type SessionInterface = Self; type EraPayout = pallet_staking::ConvertCurve; type MaxExposurePageSize = MaxExposurePageSize; - type OffendingValidatorsThreshold = OffendingValidatorsThreshold; type NextNewSession = Session; type ElectionProvider = onchain::OnChainExecution; type GenesisElectionProvider = onchain::OnChainExecution; @@ -364,6 +364,7 @@ impl pallet_staking::Config for Runtime { type BenchmarkingConfig = runtime_common::StakingBenchmarkingConfig; type EventListeners = (); type WeightInfo = (); + type DisablingStrategy = pallet_staking::UpToLimitDisablingStrategy; } parameter_types! { @@ -557,8 +558,7 @@ parameter_types! { impl parachains_dmp::Config for Runtime {} parameter_types! { - pub const FirstMessageFactorPercent: u64 = 100; - pub const DefaultChannelSizeAndCapacityWithSystem: (u32, u32) = (51200, 500); + pub const HrmpChannelSizeAndCapacityWithSystemRatio: Percent = Percent::from_percent(100); } impl parachains_hrmp::Config for Runtime { @@ -566,7 +566,11 @@ impl parachains_hrmp::Config for Runtime { type RuntimeEvent = RuntimeEvent; type ChannelManager = frame_system::EnsureRoot; type Currency = Balances; - type DefaultChannelSizeAndCapacityWithSystem = DefaultChannelSizeAndCapacityWithSystem; + type DefaultChannelSizeAndCapacityWithSystem = ActiveConfigHrmpChannelSizeAndCapacityRatio< + Runtime, + HrmpChannelSizeAndCapacityWithSystemRatio, + >; + type VersionWrapper = crate::Xcm; type WeightInfo = parachains_hrmp::TestWeightInfo; } @@ -1010,7 +1014,7 @@ sp_api::impl_runtime_apis! { } fn submit_report_equivocation_unsigned_extrinsic( - _equivocation_proof: beefy_primitives::EquivocationProof< + _equivocation_proof: beefy_primitives::DoubleVotingProof< BlockNumber, BeefyId, BeefySignature, @@ -1040,11 +1044,11 @@ sp_api::impl_runtime_apis! { fn generate_proof( _block_numbers: Vec, _best_known_block_number: Option, - ) -> Result<(Vec, mmr::Proof), mmr::Error> { + ) -> Result<(Vec, mmr::LeafProof), mmr::Error> { Err(mmr::Error::PalletNotIncluded) } - fn verify_proof(_leaves: Vec, _proof: mmr::Proof) + fn verify_proof(_leaves: Vec, _proof: mmr::LeafProof) -> Result<(), mmr::Error> { Err(mmr::Error::PalletNotIncluded) @@ -1053,7 +1057,7 @@ sp_api::impl_runtime_apis! { fn verify_proof_stateless( _root: Hash, _leaves: Vec, - _proof: mmr::Proof + _proof: mmr::LeafProof ) -> Result<(), mmr::Error> { Err(mmr::Error::PalletNotIncluded) } diff --git a/polkadot/runtime/test-runtime/src/xcm_config.rs b/polkadot/runtime/test-runtime/src/xcm_config.rs index 8411b79f2529d8e2d26815bd9ab806457e4ca99b..fc3d0dc42a3b93408f15c8363b631aa9761cbe36 100644 --- a/polkadot/runtime/test-runtime/src/xcm_config.rs +++ b/polkadot/runtime/test-runtime/src/xcm_config.rs @@ -156,6 +156,7 @@ impl xcm_executor::Config for XcmConfig { type HrmpNewChannelOpenRequestHandler = (); type HrmpChannelAcceptedHandler = (); type HrmpChannelClosingHandler = (); + type XcmRecorder = (); } impl pallet_xcm::Config for crate::Runtime { diff --git a/polkadot/runtime/westend/Cargo.toml b/polkadot/runtime/westend/Cargo.toml index d726adfb8e6e439edd2b5f378f5b5160ac70e6be..6a919dd00a98985714b9ab21bc17dd53f08dc0fe 100644 --- a/polkadot/runtime/westend/Cargo.toml +++ b/polkadot/runtime/westend/Cargo.toml @@ -12,7 +12,7 @@ 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", "max-encoded-len"] } +parity-scale-codec = { version = "3.6.12", default-features = false, features = ["derive", "max-encoded-len"] } scale-info = { version = "2.11.1", default-features = false, features = ["derive"] } log = { workspace = true } rustc-hex = { version = "2.1.0", default-features = false } @@ -283,6 +283,7 @@ runtime-benchmarks = [ "sp-staking/runtime-benchmarks", "xcm-builder/runtime-benchmarks", "xcm-executor/runtime-benchmarks", + "xcm-fee-payment-runtime-api/runtime-benchmarks", ] try-runtime = [ "frame-election-provider-support/try-runtime", diff --git a/polkadot/runtime/westend/build.rs b/polkadot/runtime/westend/build.rs index 428c971bc132a5c7e856e6485246c4fd2ff57822..0b3e12c78c746517a32538c8c1e5f9da63747fc5 100644 --- a/polkadot/runtime/westend/build.rs +++ b/polkadot/runtime/westend/build.rs @@ -17,9 +17,5 @@ use substrate_wasm_builder::WasmBuilder; fn main() { - WasmBuilder::new() - .with_current_project() - .import_memory() - .export_heap_base() - .build() + WasmBuilder::build_using_defaults(); } diff --git a/polkadot/runtime/westend/constants/src/lib.rs b/polkadot/runtime/westend/constants/src/lib.rs index c98f4b114fd88241dea1e2e5ffcf694848448007..1a4c1f3110614508cf3d934fe82cd5884f49d365 100644 --- a/polkadot/runtime/westend/constants/src/lib.rs +++ b/polkadot/runtime/westend/constants/src/lib.rs @@ -52,7 +52,7 @@ pub mod time { // 1 in 4 blocks (on average, not counting collisions) will be primary babe blocks. // The choice of is done in accordance to the slot duration and expected target // block time, for safely resisting network delays of maximum two seconds. - // + // pub const PRIMARY_PROBABILITY: (u64, u64) = (1, 4); } diff --git a/polkadot/runtime/westend/src/impls.rs b/polkadot/runtime/westend/src/impls.rs index d8741c939a507d49c181b3620d322c08692d730b..71e6b696a20a0feb89e669067d02b12e6eeb89fd 100644 --- a/polkadot/runtime/westend/src/impls.rs +++ b/polkadot/runtime/westend/src/impls.rs @@ -167,16 +167,11 @@ where }, ]); - let encoded_versioned_xcm = - VersionedXcm::V4(program).encode().try_into().map_err(|error| { - log::error!(target: "runtime::on_reap_identity", "XCM too large, error: {:?}", error); - pallet_xcm::Error::::XcmTooLarge - })?; // send - let _ = >::send_blob( + let _ = >::send( RawOrigin::Root.into(), Box::new(VersionedLocation::V4(destination)), - encoded_versioned_xcm, + Box::new(VersionedXcm::V4(program)), )?; Ok(()) } diff --git a/polkadot/runtime/westend/src/lib.rs b/polkadot/runtime/westend/src/lib.rs index a119d78b83ab8a76642d0bc1cf407ec4935ab5dc..b62c6d08201c4c2d3a3ba879e9f7e2c6546e51c2 100644 --- a/polkadot/runtime/westend/src/lib.rs +++ b/polkadot/runtime/westend/src/lib.rs @@ -31,9 +31,9 @@ use frame_support::{ genesis_builder_helper::{build_state, get_preset}, parameter_types, traits::{ - fungible::HoldConsideration, ConstU32, Contains, EitherOf, EitherOfDiverse, EverythingBut, - InstanceFilter, KeyOwnerProofSystem, LinearStoragePrice, ProcessMessage, - ProcessMessageError, WithdrawReasons, + fungible::HoldConsideration, tokens::UnityOrOuterConversion, ConstU32, Contains, EitherOf, + EitherOfDiverse, EverythingBut, FromContains, InstanceFilter, KeyOwnerProofSystem, + LinearStoragePrice, ProcessMessage, ProcessMessageError, WithdrawReasons, }, weights::{ConstantMultiplier, WeightMeter, WeightToFee as _}, PalletId, @@ -57,7 +57,8 @@ use runtime_common::{ elections::OnChainAccuracy, identity_migrator, impl_runtime_weights, impls::{ - LocatableAssetConverter, ToAuthor, VersionedLocatableAsset, VersionedLocationConverter, + ContainsParts, LocatableAssetConverter, ToAuthor, VersionedLocatableAsset, + VersionedLocationConverter, }, paras_registrar, paras_sudo_wrapper, prod_or_fast, slots, traits::{Leaser, OnSwap}, @@ -67,6 +68,7 @@ use runtime_common::{ use runtime_parachains::{ assigner_coretime as parachains_assigner_coretime, assigner_on_demand as parachains_assigner_on_demand, configuration as parachains_configuration, + configuration::ActiveConfigHrmpChannelSizeAndCapacityRatio, coretime, disputes as parachains_disputes, disputes::slashing as parachains_slashing, dmp as parachains_dmp, hrmp as parachains_hrmp, inclusion as parachains_inclusion, @@ -80,7 +82,7 @@ use runtime_parachains::{ shared as parachains_shared, }; use scale_info::TypeInfo; -use sp_core::{OpaqueMetadata, RuntimeDebug, H256}; +use sp_core::{ConstU8, OpaqueMetadata, RuntimeDebug, H256}; use sp_runtime::{ create_runtime_str, curve::PiecewiseLinear, @@ -106,7 +108,10 @@ use xcm::{ }; use xcm_builder::PayOverXcm; -use xcm_fee_payment_runtime_api::Error as XcmPaymentApiError; +use xcm_fee_payment_runtime_api::{ + dry_run::{Error as XcmDryRunApiError, ExtrinsicDryRunEffects, XcmDryRunEffects}, + fees::Error as XcmPaymentApiError, +}; pub use frame_system::Call as SystemCall; pub use pallet_balances::Call as BalancesCall; @@ -152,10 +157,10 @@ pub const VERSION: RuntimeVersion = RuntimeVersion { spec_name: create_runtime_str!("westend"), impl_name: create_runtime_str!("parity-westend"), authoring_version: 2, - spec_version: 1_010_000, + spec_version: 1_011_000, impl_version: 0, apis: RUNTIME_API_VERSIONS, - transaction_version: 24, + transaction_version: 25, state_version: 1, }; @@ -612,7 +617,6 @@ parameter_types! { // this is an unbounded number. We just set it to a reasonably high value, 1 full page // of nominators. pub const MaxNominators: u32 = 64; - pub const OffendingValidatorsThreshold: Perbill = Perbill::from_percent(17); pub const MaxNominations: u32 = ::LIMIT as u32; pub const MaxControllersInDeprecationBatch: u32 = 751; } @@ -633,7 +637,6 @@ impl pallet_staking::Config for Runtime { type SessionInterface = Self; type EraPayout = pallet_staking::ConvertCurve; type MaxExposurePageSize = MaxExposurePageSize; - type OffendingValidatorsThreshold = OffendingValidatorsThreshold; type NextNewSession = Session; type ElectionProvider = ElectionProviderMultiPhase; type GenesisElectionProvider = onchain::OnChainExecution; @@ -646,6 +649,7 @@ impl pallet_staking::Config for Runtime { type BenchmarkingConfig = runtime_common::StakingBenchmarkingConfig; type EventListeners = NominationPools; type WeightInfo = weights::pallet_staking::WeightInfo; + type DisablingStrategy = pallet_staking::UpToLimitDisablingStrategy; } impl pallet_fast_unstake::Config for Runtime { @@ -712,7 +716,15 @@ impl pallet_treasury::Config for Runtime { LocatableAssetConverter, VersionedLocationConverter, >; - type BalanceConverter = AssetRate; + type BalanceConverter = UnityOrOuterConversion< + ContainsParts< + FromContains< + xcm_builder::IsChildSystemParachain, + xcm_builder::IsParentsOnly>, + >, + >, + AssetRate, + >; type PayoutPeriod = PayoutSpendPeriod; #[cfg(feature = "runtime-benchmarks")] type BenchmarkHelper = runtime_common::impls::benchmarks::TreasuryArguments; @@ -1155,7 +1167,7 @@ impl pallet_message_queue::Config for Runtime { impl parachains_dmp::Config for Runtime {} parameter_types! { - pub const DefaultChannelSizeAndCapacityWithSystem: (u32, u32) = (4096, 4); + pub const HrmpChannelSizeAndCapacityWithSystemRatio: Percent = Percent::from_percent(100); } impl parachains_hrmp::Config for Runtime { @@ -1163,7 +1175,11 @@ impl parachains_hrmp::Config for Runtime { type RuntimeEvent = RuntimeEvent; type ChannelManager = EnsureRoot; type Currency = Balances; - type DefaultChannelSizeAndCapacityWithSystem = DefaultChannelSizeAndCapacityWithSystem; + type DefaultChannelSizeAndCapacityWithSystem = ActiveConfigHrmpChannelSizeAndCapacityRatio< + Runtime, + HrmpChannelSizeAndCapacityWithSystemRatio, + >; + type VersionWrapper = crate::XcmPallet; type WeightInfo = weights::runtime_parachains_hrmp::WeightInfo; } @@ -1179,6 +1195,7 @@ impl parachains_scheduler::Config for Runtime { parameter_types! { pub const BrokerId: u32 = BROKER_ID; + pub MaxXcmTransactWeight: Weight = Weight::from_parts(200_000_000, 20_000); } impl coretime::Config for Runtime { @@ -1188,6 +1205,7 @@ impl coretime::Config for Runtime { type BrokerId = BrokerId; type WeightInfo = weights::runtime_parachains_coretime::WeightInfo; type SendXcm = crate::xcm_config::XcmRouter; + type MaxXcmTransactWeight = MaxXcmTransactWeight; } parameter_types! { @@ -1637,36 +1655,8 @@ pub mod migrations { } } - // We don't have a limit in the Relay Chain. - const IDENTITY_MIGRATION_KEY_LIMIT: u64 = u64::MAX; - /// Unreleased migrations. Add new ones here: - pub type Unreleased = ( - parachains_configuration::migration::v7::MigrateToV7, - pallet_staking::migrations::v14::MigrateToV14, - assigned_slots::migration::v1::MigrateToV1, - parachains_scheduler::migration::MigrateV1ToV2, - parachains_configuration::migration::v8::MigrateToV8, - parachains_configuration::migration::v9::MigrateToV9, - paras_registrar::migration::MigrateToV1, - pallet_referenda::migration::v1::MigrateV0ToV1, - pallet_grandpa::migrations::MigrateV4ToV5, - parachains_configuration::migration::v10::MigrateToV10, - pallet_nomination_pools::migration::unversioned::TotalValueLockedSync, - // 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, - >, - parachains_inclusion::migration::MigrateToV1, - ); + pub type Unreleased = (pallet_staking::migrations::v15::MigrateV14ToV15,); } /// Unchecked extrinsic type as expected by this runtime. @@ -1984,7 +1974,7 @@ sp_api::impl_runtime_apis! { } fn submit_report_equivocation_unsigned_extrinsic( - equivocation_proof: beefy_primitives::EquivocationProof< + equivocation_proof: beefy_primitives::DoubleVotingProof< BlockNumber, BeefyId, BeefySignature, @@ -2023,7 +2013,7 @@ sp_api::impl_runtime_apis! { fn generate_proof( block_numbers: Vec, best_known_block_number: Option, - ) -> Result<(Vec, mmr::Proof), mmr::Error> { + ) -> Result<(Vec, mmr::LeafProof), mmr::Error> { Mmr::generate_proof(block_numbers, best_known_block_number).map( |(leaves, proof)| { ( @@ -2037,7 +2027,7 @@ sp_api::impl_runtime_apis! { ) } - fn verify_proof(leaves: Vec, proof: mmr::Proof) + fn verify_proof(leaves: Vec, proof: mmr::LeafProof) -> Result<(), mmr::Error> { let leaves = leaves.into_iter().map(|leaf| @@ -2050,7 +2040,7 @@ sp_api::impl_runtime_apis! { fn verify_proof_stateless( root: mmr::Hash, leaves: Vec, - proof: mmr::Proof + proof: mmr::LeafProof ) -> Result<(), mmr::Error> { let nodes = leaves.into_iter().map(|leaf|mmr::DataOrHash::Data(leaf.into_opaque_leaf())).collect(); pallet_mmr::verify_leaves_proof::(root, nodes, proof) @@ -2211,26 +2201,34 @@ sp_api::impl_runtime_apis! { } } - impl xcm_fee_payment_runtime_api::XcmPaymentApi for Runtime { + impl xcm_fee_payment_runtime_api::fees::XcmPaymentApi for Runtime { fn query_acceptable_payment_assets(xcm_version: xcm::Version) -> Result, XcmPaymentApiError> { - if !matches!(xcm_version, 3 | 4) { - return Err(XcmPaymentApiError::UnhandledXcmVersion); - } - Ok([VersionedAssetId::V4(xcm_config::TokenLocation::get().into())] + let acceptable = vec![ + // native token + VersionedAssetId::from(AssetId(xcm_config::TokenLocation::get())) + ]; + + Ok(acceptable .into_iter() .filter_map(|asset| asset.into_version(xcm_version).ok()) .collect()) } fn query_weight_to_asset_fee(weight: Weight, asset: VersionedAssetId) -> Result { - let local_asset = VersionedAssetId::V4(xcm_config::TokenLocation::get().into()); - let asset = asset - .into_version(4) - .map_err(|_| XcmPaymentApiError::VersionedConversionFailed)?; - - if asset != local_asset { return Err(XcmPaymentApiError::AssetNotFound); } - - Ok(WeightToFee::weight_to_fee(&weight)) + match asset.try_as::() { + Ok(asset_id) if asset_id.0 == xcm_config::TokenLocation::get() => { + // for native token + Ok(WeightToFee::weight_to_fee(&weight)) + }, + Ok(asset_id) => { + log::trace!(target: "xcm::xcm_fee_payment_runtime_api", "query_weight_to_asset_fee - unhandled asset_id: {asset_id:?}!"); + Err(XcmPaymentApiError::AssetNotFound) + }, + Err(_) => { + log::trace!(target: "xcm::xcm_fee_payment_runtime_api", "query_weight_to_asset_fee - failed to convert asset: {asset:?}!"); + Err(XcmPaymentApiError::VersionedConversionFailed) + } + } } fn query_xcm_weight(message: VersionedXcm<()>) -> Result { @@ -2242,6 +2240,66 @@ sp_api::impl_runtime_apis! { } } + impl xcm_fee_payment_runtime_api::dry_run::XcmDryRunApi for Runtime { + fn dry_run_extrinsic(extrinsic: ::Extrinsic) -> Result, XcmDryRunApiError> { + use xcm_builder::InspectMessageQueues; + use xcm_executor::RecordXcm; + pallet_xcm::Pallet::::set_record_xcm(true); + let result = Executive::apply_extrinsic(extrinsic).map_err(|error| { + log::error!( + target: "xcm::XcmDryRunApi::dry_run_extrinsic", + "Applying extrinsic failed with error {:?}", + error, + ); + XcmDryRunApiError::InvalidExtrinsic + })?; + let local_xcm = pallet_xcm::Pallet::::recorded_xcm(); + let forwarded_xcms = xcm_config::XcmRouter::get_messages(); + let events: Vec = System::read_events_no_consensus().map(|record| record.event.clone()).collect(); + Ok(ExtrinsicDryRunEffects { + local_xcm: local_xcm.map(VersionedXcm::<()>::V4), + forwarded_xcms, + emitted_events: events, + execution_result: result, + }) + } + + fn dry_run_xcm(origin_location: VersionedLocation, xcm: VersionedXcm) -> Result, XcmDryRunApiError> { + use xcm_builder::InspectMessageQueues; + let origin_location: Location = origin_location.try_into().map_err(|error| { + log::error!( + target: "xcm::XcmDryRunApi::dry_run_xcm", + "Location version conversion failed with error: {:?}", + error, + ); + XcmDryRunApiError::VersionedConversionFailed + })?; + let xcm: Xcm = xcm.try_into().map_err(|error| { + log::error!( + target: "xcm::XcmDryRunApi::dry_run_xcm", + "Xcm version conversion failed with error {:?}", + error, + ); + XcmDryRunApiError::VersionedConversionFailed + })?; + let mut hash = xcm.using_encoded(sp_io::hashing::blake2_256); + let result = xcm_executor::XcmExecutor::::prepare_and_execute( + origin_location, + xcm, + &mut hash, + Weight::MAX, // Max limit available for execution. + Weight::zero(), + ); + let forwarded_xcms = xcm_config::XcmRouter::get_messages(); + let events: Vec = System::read_events_no_consensus().map(|record| record.event.clone()).collect(); + Ok(XcmDryRunEffects { + forwarded_xcms, + emitted_events: events, + execution_result: result, + }) + } + } + impl pallet_nomination_pools_runtime_api::NominationPoolsApi< Block, AccountId, @@ -2268,6 +2326,10 @@ sp_api::impl_runtime_apis! { fn eras_stakers_page_count(era: sp_staking::EraIndex, account: AccountId) -> sp_staking::Page { Staking::api_eras_stakers_page_count(era, account) } + + fn pending_rewards(era: sp_staking::EraIndex, account: AccountId) -> bool { + Staking::api_pending_rewards(era, account) + } } #[cfg(feature = "try-runtime")] diff --git a/polkadot/runtime/westend/src/weights/pallet_balances.rs b/polkadot/runtime/westend/src/weights/pallet_balances.rs index 25626e940209d50859a57dee60f483b15a8db257..5e91f31920cab122d044465fa6c3538053f4acf5 100644 --- a/polkadot/runtime/westend/src/weights/pallet_balances.rs +++ b/polkadot/runtime/westend/src/weights/pallet_balances.rs @@ -16,10 +16,10 @@ //! 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-05-06, 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-unxyhko3-project-674-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` //! WASM-EXECUTION: `Compiled`, CHAIN: `Some("westend-dev")`, DB CACHE: 1024 // Executed Command: @@ -54,8 +54,8 @@ impl pallet_balances::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `0` // Estimated: `3593` - // Minimum execution time: 43_680_000 picoseconds. - Weight::from_parts(45_012_000, 0) + // Minimum execution time: 43_248_000 picoseconds. + Weight::from_parts(43_872_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 +66,8 @@ impl pallet_balances::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `0` // Estimated: `3593` - // Minimum execution time: 34_038_000 picoseconds. - Weight::from_parts(35_771_000, 0) + // Minimum execution time: 33_990_000 picoseconds. + Weight::from_parts(34_693_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 +78,8 @@ impl pallet_balances::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `174` // Estimated: `3593` - // Minimum execution time: 12_609_000 picoseconds. - Weight::from_parts(13_142_000, 0) + // Minimum execution time: 12_681_000 picoseconds. + Weight::from_parts(13_183_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 +90,8 @@ impl pallet_balances::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `174` // Estimated: `3593` - // Minimum execution time: 17_533_000 picoseconds. - Weight::from_parts(18_061_000, 0) + // Minimum execution time: 17_474_000 picoseconds. + Weight::from_parts(18_063_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 +102,8 @@ impl pallet_balances::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `103` // Estimated: `6196` - // Minimum execution time: 45_278_000 picoseconds. - Weight::from_parts(46_670_000, 0) + // Minimum execution time: 45_699_000 picoseconds. + Weight::from_parts(46_099_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 +114,8 @@ impl pallet_balances::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `0` // Estimated: `3593` - // Minimum execution time: 43_125_000 picoseconds. - Weight::from_parts(43_925_000, 0) + // Minimum execution time: 42_453_000 picoseconds. + Weight::from_parts(43_133_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 +126,8 @@ impl pallet_balances::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `174` // Estimated: `3593` - // Minimum execution time: 15_580_000 picoseconds. - Weight::from_parts(16_023_000, 0) + // Minimum execution time: 15_066_000 picoseconds. + Weight::from_parts(15_605_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 +139,11 @@ impl pallet_balances::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `0 + u * (136 ±0)` // Estimated: `990 + u * (2603 ±0)` - // Minimum execution time: 14_868_000 picoseconds. - Weight::from_parts(15_130_000, 0) + // Minimum execution time: 14_180_000 picoseconds. + Weight::from_parts(14_598_000, 0) .saturating_add(Weight::from_parts(0, 990)) - // Standard Error: 10_719 - .saturating_add(Weight::from_parts(13_394_926, 0).saturating_mul(u.into())) + // Standard Error: 13_221 + .saturating_add(Weight::from_parts(13_422_901, 0).saturating_mul(u.into())) .saturating_add(T::DbWeight::get().reads((1_u64).saturating_mul(u.into()))) .saturating_add(T::DbWeight::get().writes((1_u64).saturating_mul(u.into()))) .saturating_add(Weight::from_parts(0, 2603).saturating_mul(u.into())) @@ -152,8 +152,24 @@ impl pallet_balances::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 5_174_000 picoseconds. - Weight::from_parts(5_457_000, 0) + // Minimum execution time: 5_130_000 picoseconds. + Weight::from_parts(5_257_000, 0) + .saturating_add(Weight::from_parts(0, 0)) + } + fn burn_allow_death() -> Weight { + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 27_328_000 picoseconds. + Weight::from_parts(27_785_000, 0) + .saturating_add(Weight::from_parts(0, 0)) + } + fn burn_keep_alive() -> Weight { + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 17_797_000 picoseconds. + Weight::from_parts(18_103_000, 0) .saturating_add(Weight::from_parts(0, 0)) } } diff --git a/polkadot/runtime/westend/src/weights/pallet_xcm.rs b/polkadot/runtime/westend/src/weights/pallet_xcm.rs index 80bc551ba1e264f9703f5fd307ec7075642bc3bd..10725cecf24995e34b3254baa23535cb91dd9981 100644 --- a/polkadot/runtime/westend/src/weights/pallet_xcm.rs +++ b/polkadot/runtime/westend/src/weights/pallet_xcm.rs @@ -17,9 +17,9 @@ //! Autogenerated weights for `pallet_xcm` //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 32.0.0 -//! DATE: 2024-03-21, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! DATE: 2024-02-20, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` //! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `runner-h2rr8wx7-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: @@ -60,26 +60,8 @@ impl pallet_xcm::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `147` // Estimated: `3612` - // Minimum execution time: 24_535_000 picoseconds. - Weight::from_parts(25_618_000, 0) - .saturating_add(Weight::from_parts(0, 3612)) - .saturating_add(T::DbWeight::get().reads(4)) - .saturating_add(T::DbWeight::get().writes(2)) - } - /// 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 send_blob() -> Weight { - // Proof Size summary in bytes: - // Measured: `147` - // Estimated: `3612` - // Minimum execution time: 25_376_000 picoseconds. - Weight::from_parts(26_180_000, 0) + // 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)) @@ -98,8 +80,8 @@ impl pallet_xcm::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `250` // Estimated: `6196` - // Minimum execution time: 108_786_000 picoseconds. - Weight::from_parts(112_208_000, 0) + // 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)) @@ -118,8 +100,8 @@ impl pallet_xcm::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `302` // Estimated: `6196` - // Minimum execution time: 105_190_000 picoseconds. - Weight::from_parts(107_140_000, 0) + // 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)) @@ -138,8 +120,8 @@ impl pallet_xcm::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `250` // Estimated: `6196` - // Minimum execution time: 109_027_000 picoseconds. - Weight::from_parts(111_404_000, 0) + // 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)) @@ -154,24 +136,14 @@ 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 execute_blob() -> 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: `XcmPallet::SupportedVersion` (r:0 w:1) /// Proof: `XcmPallet::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: 6_668_000 picoseconds. - Weight::from_parts(7_013_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)) } @@ -179,8 +151,8 @@ impl pallet_xcm::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_740_000 picoseconds. - Weight::from_parts(1_884_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) @@ -201,8 +173,8 @@ impl pallet_xcm::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `147` // Estimated: `3612` - // Minimum execution time: 30_200_000 picoseconds. - Weight::from_parts(30_768_000, 0) + // 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)) @@ -223,8 +195,8 @@ impl pallet_xcm::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `327` // Estimated: `3792` - // Minimum execution time: 33_928_000 picoseconds. - Weight::from_parts(35_551_000, 0) + // 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)) @@ -235,8 +207,8 @@ impl pallet_xcm::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_759_000 picoseconds. - Weight::from_parts(1_880_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)) } @@ -246,8 +218,8 @@ impl pallet_xcm::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `22` // Estimated: `13387` - // Minimum execution time: 16_507_000 picoseconds. - Weight::from_parts(17_219_000, 0) + // 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)) @@ -258,8 +230,8 @@ impl pallet_xcm::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `26` // Estimated: `13391` - // Minimum execution time: 16_633_000 picoseconds. - Weight::from_parts(16_889_000, 0) + // 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)) @@ -270,8 +242,8 @@ impl pallet_xcm::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `40` // Estimated: `15880` - // Minimum execution time: 19_297_000 picoseconds. - Weight::from_parts(19_820_000, 0) + // 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)) } @@ -289,8 +261,8 @@ impl pallet_xcm::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `183` // Estimated: `6123` - // Minimum execution time: 30_364_000 picoseconds. - Weight::from_parts(31_122_000, 0) + // 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)) @@ -301,8 +273,8 @@ impl pallet_xcm::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `69` // Estimated: `10959` - // Minimum execution time: 11_997_000 picoseconds. - Weight::from_parts(12_392_000, 0) + // 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)) } @@ -312,8 +284,8 @@ impl pallet_xcm::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `33` // Estimated: `13398` - // Minimum execution time: 16_894_000 picoseconds. - Weight::from_parts(17_452_000, 0) + // 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)) @@ -332,8 +304,8 @@ impl pallet_xcm::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `183` // Estimated: `13548` - // Minimum execution time: 39_864_000 picoseconds. - Weight::from_parts(40_859_000, 0) + // 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)) @@ -346,8 +318,8 @@ impl pallet_xcm::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `0` // Estimated: `1485` - // Minimum execution time: 2_363_000 picoseconds. - Weight::from_parts(2_519_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)) @@ -358,8 +330,8 @@ impl pallet_xcm::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `7576` // Estimated: `11041` - // Minimum execution time: 22_409_000 picoseconds. - Weight::from_parts(22_776_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)) @@ -370,8 +342,8 @@ impl pallet_xcm::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `23` // Estimated: `3488` - // Minimum execution time: 33_551_000 picoseconds. - Weight::from_parts(34_127_000, 0) + // 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_hrmp.rs b/polkadot/runtime/westend/src/weights/runtime_parachains_hrmp.rs index 3d2ab827b8fd125b74a2c892803038557998b8be..f1d7932fe8b7c09d069144f624c0f29bce7c4e5b 100644 --- a/polkadot/runtime/westend/src/weights/runtime_parachains_hrmp.rs +++ b/polkadot/runtime/westend/src/weights/runtime_parachains_hrmp.rs @@ -16,28 +16,26 @@ //! Autogenerated weights for `runtime_parachains::hrmp` //! -//! 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: `[]` +//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 32.0.0 +//! DATE: 2024-05-01, 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-unxyhko3-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=runtime_parachains::hrmp // --extrinsic=* -// --execution=wasm // --wasm-execution=compiled -// --header=./file_header.txt -// --output=./runtime/westend/src/weights/runtime_parachains_hrmp.rs +// --heap-pages=4096 +// --json-file=/builds/parity/mirrors/polkadot-sdk/.git/.artifacts/bench.json +// --pallet=runtime_parachains::hrmp +// --chain=westend-dev +// --header=./polkadot/file_header.txt +// --output=./polkadot/runtime/westend/src/weights/ #![cfg_attr(rustfmt, rustfmt_skip)] #![allow(unused_parens)] @@ -50,99 +48,103 @@ 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: 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: `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 hrmp_init_open_channel() -> Weight { // Proof Size summary in bytes: - // Measured: `307` - // Estimated: `6247` - // Minimum execution time: 35_676_000 picoseconds. - Weight::from_parts(36_608_000, 0) - .saturating_add(Weight::from_parts(0, 6247)) + // Measured: `455` + // Estimated: `3920` + // Minimum execution time: 35_900_000 picoseconds. + Weight::from_parts(37_587_000, 0) + .saturating_add(Weight::from_parts(0, 3920)) .saturating_add(T::DbWeight::get().reads(9)) .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: 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: `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 hrmp_accept_open_channel() -> Weight { // Proof Size summary in bytes: - // Measured: `421` - // Estimated: `3886` - // Minimum execution time: 32_773_000 picoseconds. - Weight::from_parts(33_563_000, 0) - .saturating_add(Weight::from_parts(0, 3886)) + // Measured: `445` + // Estimated: `3910` + // Minimum execution time: 35_670_000 picoseconds. + Weight::from_parts(36_853_000, 0) + .saturating_add(Weight::from_parts(0, 3910)) .saturating_add(T::DbWeight::get().reads(6)) .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: 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: `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 hrmp_close_channel() -> Weight { // Proof Size summary in bytes: - // Measured: `238` - // Estimated: `3703` - // Minimum execution time: 28_134_000 picoseconds. - Weight::from_parts(29_236_000, 0) - .saturating_add(Weight::from_parts(0, 3703)) - .saturating_add(T::DbWeight::get().reads(5)) + // Measured: `558` + // Estimated: `4023` + // Minimum execution time: 36_953_000 picoseconds. + Weight::from_parts(38_638_000, 0) + .saturating_add(Weight::from_parts(0, 4023)) + .saturating_add(T::DbWeight::get().reads(6)) .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: `158 + e * (100 ±0) + i * (100 ±0)` - // Estimated: `3620 + e * (2575 ±0) + i * (2575 ±0)` - // Minimum execution time: 1_217_145_000 picoseconds. - Weight::from_parts(1_251_187_000, 0) - .saturating_add(Weight::from_parts(0, 3620)) - // Standard Error: 118_884 - .saturating_add(Weight::from_parts(4_002_678, 0).saturating_mul(i.into())) - // Standard Error: 118_884 - .saturating_add(Weight::from_parts(3_641_596, 0).saturating_mul(e.into())) + // Measured: `264 + e * (100 ±0) + i * (100 ±0)` + // Estimated: `3726 + e * (2575 ±0) + i * (2575 ±0)` + // Minimum execution time: 1_202_266_000 picoseconds. + Weight::from_parts(1_217_618_000, 0) + .saturating_add(Weight::from_parts(0, 3726)) + // Standard Error: 113_091 + .saturating_add(Weight::from_parts(3_550_787, 0).saturating_mul(i.into())) + // Standard Error: 113_091 + .saturating_add(Weight::from_parts(3_615_215, 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()))) @@ -152,135 +154,141 @@ 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: 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: `386 + c * (136 ±0)` - // Estimated: `1841 + c * (5086 ±0)` - // Minimum execution time: 6_277_000 picoseconds. - Weight::from_parts(6_357_000, 0) - .saturating_add(Weight::from_parts(0, 1841)) - // Standard Error: 41_189 - .saturating_add(Weight::from_parts(22_159_709, 0).saturating_mul(c.into())) + // Measured: `492 + c * (136 ±0)` + // Estimated: `1947 + c * (5086 ±0)` + // Minimum execution time: 6_105_000 picoseconds. + Weight::from_parts(6_313_000, 0) + .saturating_add(Weight::from_parts(0, 1947)) + // Standard Error: 16_081 + .saturating_add(Weight::from_parts(21_097_410, 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: `229 + c * (124 ±0)` - // Estimated: `1689 + c * (2600 ±0)` - // Minimum execution time: 5_070_000 picoseconds. - Weight::from_parts(5_225_000, 0) - .saturating_add(Weight::from_parts(0, 1689)) - // Standard Error: 24_173 - .saturating_add(Weight::from_parts(13_645_307, 0).saturating_mul(c.into())) + // Measured: `335 + c * (124 ±0)` + // Estimated: `1795 + c * (2600 ±0)` + // Minimum execution time: 5_073_000 picoseconds. + Weight::from_parts(5_398_000, 0) + .saturating_add(Weight::from_parts(0, 1795)) + // Standard Error: 12_934 + .saturating_add(Weight::from_parts(13_222_909, 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: `920 + c * (13 ±0)` - // Estimated: `4189 + c * (15 ±0)` - // Minimum execution time: 20_449_000 picoseconds. - Weight::from_parts(30_861_799, 0) - .saturating_add(Weight::from_parts(0, 4189)) - // Standard Error: 6_642 - .saturating_add(Weight::from_parts(236_293, 0).saturating_mul(c.into())) + // Measured: `1026 + c * (13 ±0)` + // Estimated: `4295 + c * (15 ±0)` + // Minimum execution time: 16_793_000 picoseconds. + Weight::from_parts(27_430_638, 0) + .saturating_add(Weight::from_parts(0, 4295)) + // Standard Error: 2_996 + .saturating_add(Weight::from_parts(191_905, 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: `137 + c * (63 ±0)` - // Estimated: `1616 + c * (2538 ±0)` - // Minimum execution time: 3_911_000 picoseconds. - Weight::from_parts(5_219_837, 0) - .saturating_add(Weight::from_parts(0, 1616)) - // Standard Error: 10_219 - .saturating_add(Weight::from_parts(3_647_782, 0).saturating_mul(c.into())) + // Measured: `243 + c * (63 ±0)` + // Estimated: `1722 + c * (2538 ±0)` + // Minimum execution time: 3_805_000 picoseconds. + Weight::from_parts(445_643, 0) + .saturating_add(Weight::from_parts(0, 1722)) + // Standard Error: 4_991 + .saturating_add(Weight::from_parts(3_459_894, 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: 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: `XcmPallet::SupportedVersion` (r:2 w:0) + /// Proof: `XcmPallet::SupportedVersion` (`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: `307` - // Estimated: `6247` - // Minimum execution time: 50_870_000 picoseconds. - Weight::from_parts(53_335_000, 0) - .saturating_add(Weight::from_parts(0, 6247)) - .saturating_add(T::DbWeight::get().reads(13)) + // Measured: `455 + c * (235 ±0)` + // Estimated: `6395 + c * (235 ±0)` + // Minimum execution time: 53_580_000 picoseconds. + Weight::from_parts(55_701_720, 0) + .saturating_add(Weight::from_parts(0, 6395)) + // Standard Error: 159_757 + .saturating_add(Weight::from_parts(15_601_979, 0).saturating_mul(c.into())) + .saturating_add(T::DbWeight::get().reads(14)) .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`) @@ -294,6 +302,8 @@ impl runtime_parachains::hrmp::WeightInfo for WeightInf /// 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: `XcmPallet::SupportedVersion` (r:2 w:0) + /// Proof: `XcmPallet::SupportedVersion` (`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) @@ -304,12 +314,12 @@ 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)) - .saturating_add(T::DbWeight::get().reads(12)) + // Measured: `455` + // Estimated: `6395` + // Minimum execution time: 54_226_000 picoseconds. + Weight::from_parts(55_572_000, 0) + .saturating_add(Weight::from_parts(0, 6395)) + .saturating_add(T::DbWeight::get().reads(14)) .saturating_add(T::DbWeight::get().writes(8)) } /// Storage: `Hrmp::HrmpChannels` (r:1 w:1) @@ -318,20 +328,42 @@ impl runtime_parachains::hrmp::WeightInfo for WeightInf // Proof Size summary in bytes: // Measured: `263` // Estimated: `3728` - // Minimum execution time: 173_371_000 picoseconds. - Weight::from_parts(175_860_000, 0) + // Minimum execution time: 11_850_000 picoseconds. + Weight::from_parts(12_428_000, 0) .saturating_add(Weight::from_parts(0, 3728)) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(1)) } + /// Storage: `Paras::ParaLifecycles` (r:2 w:0) + /// Proof: `Paras::ParaLifecycles` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `Hrmp::HrmpOpenChannelRequests` (r:2 w:2) + /// Proof: `Hrmp::HrmpOpenChannelRequests` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `Hrmp::HrmpChannels` (r:2 w:0) + /// Proof: `Hrmp::HrmpChannels` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `Hrmp::HrmpEgressChannelsIndex` (r:2 w:0) + /// Proof: `Hrmp::HrmpEgressChannelsIndex` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `Hrmp::HrmpOpenChannelRequestCount` (r:2 w:2) + /// 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: `XcmPallet::SupportedVersion` (r:2 w:0) + /// Proof: `XcmPallet::SupportedVersion` (`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:2 w:0) + /// Proof: `Hrmp::HrmpIngressChannelsIndex` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `Hrmp::HrmpAcceptedChannelRequestCount` (r:2 w:2) + /// Proof: `Hrmp::HrmpAcceptedChannelRequestCount` (`max_values`: None, `max_size`: None, mode: `Measured`) fn establish_channel_with_system() -> 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)) - .saturating_add(T::DbWeight::get().reads(12)) - .saturating_add(T::DbWeight::get().writes(8)) + // Measured: `455` + // Estimated: `6395` + // Minimum execution time: 93_465_000 picoseconds. + Weight::from_parts(95_845_000, 0) + .saturating_add(Weight::from_parts(0, 6395)) + .saturating_add(T::DbWeight::get().reads(21)) + .saturating_add(T::DbWeight::get().writes(11)) } } diff --git a/polkadot/runtime/westend/src/xcm_config.rs b/polkadot/runtime/westend/src/xcm_config.rs index f661c4b0e4f437a2f2d597d8bdef26e0b76930c3..c6c5fb9e72a46afa70c6db09fd3a2b0f38d7e3a5 100644 --- a/polkadot/runtime/westend/src/xcm_config.rs +++ b/polkadot/runtime/westend/src/xcm_config.rs @@ -222,6 +222,7 @@ impl xcm_executor::Config for XcmConfig { type HrmpNewChannelOpenRequestHandler = (); type HrmpChannelAcceptedHandler = (); type HrmpChannelClosingHandler = (); + type XcmRecorder = XcmPallet; } parameter_types! { diff --git a/polkadot/statement-table/Cargo.toml b/polkadot/statement-table/Cargo.toml index 37b8a99d640a2d23e0d7a532adc0c43b04bba1f2..ad4a053fa3f9e434f8cc3f7ca9ef54f4435eba9c 100644 --- a/polkadot/statement-table/Cargo.toml +++ b/polkadot/statement-table/Cargo.toml @@ -10,7 +10,7 @@ description = "Stores messages other authorities issue about candidates in Polka workspace = true [dependencies] -parity-scale-codec = { version = "3.6.1", default-features = false, features = ["derive"] } +parity-scale-codec = { version = "3.6.12", 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/xcm/Cargo.toml b/polkadot/xcm/Cargo.toml index b214342d2f4860837ec0d2a56daa9108f1a53fe2..2cd8e822ae16b39b4d9465b91b45869b1776dbf8 100644 --- a/polkadot/xcm/Cargo.toml +++ b/polkadot/xcm/Cargo.toml @@ -10,12 +10,12 @@ license.workspace = true workspace = true [dependencies] -array-bytes = "6.1" +array-bytes = "6.2.2" 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 = { workspace = true } -parity-scale-codec = { version = "3.6.1", default-features = false, features = ["derive", "max-encoded-len"] } +parity-scale-codec = { version = "3.6.12", default-features = false, features = ["derive", "max-encoded-len"] } scale-info = { version = "2.11.1", default-features = false, features = ["derive", "serde"] } sp-weights = { path = "../../substrate/primitives/weights", default-features = false, features = ["serde"] } serde = { features = ["alloc", "derive", "rc"], workspace = true } diff --git a/polkadot/xcm/docs/Cargo.toml b/polkadot/xcm/docs/Cargo.toml new file mode 100644 index 0000000000000000000000000000000000000000..9820bd36dc0b1fb84fb6c4e43e4b1608308432a2 --- /dev/null +++ b/polkadot/xcm/docs/Cargo.toml @@ -0,0 +1,39 @@ +[package] +name = "xcm-docs" +description = "Documentation and guides for XCM" +version = "0.1.0" +license = "GPL-3.0-or-later WITH Classpath-exception-2.0" +repository.workspace = true +authors.workspace = true +edition.workspace = true +publish = false + +[dependencies] +# For XCM stuff +xcm = { path = "../../xcm", package = "staging-xcm" } +xcm-executor = { path = "../../xcm/xcm-executor", package = "staging-xcm-executor" } +xcm-builder = { path = "../../xcm/xcm-builder", package = "staging-xcm-builder" } +xcm-simulator = { path = "../../xcm/xcm-simulator" } +pallet-xcm = { path = "../../xcm/pallet-xcm" } + +# For building FRAME runtimes +frame = { package = "polkadot-sdk-frame", path = "../../../substrate/frame", features = ["experimental", "runtime"] } +codec = { package = "parity-scale-codec", version = "3.6.9" } +scale-info = { version = "2.6.0", default-features = false } +polkadot-parachain-primitives = { path = "../../../polkadot/parachain" } +polkadot-runtime-parachains = { path = "../../../polkadot/runtime/parachains" } +polkadot-primitives = { path = "../../../polkadot/primitives" } +sp-runtime = { path = "../../../substrate/primitives/runtime" } +sp-std = { path = "../../../substrate/primitives/std" } +sp-io = { path = "../../../substrate/primitives/io" } + +# Some pallets +pallet-message-queue = { path = "../../../substrate/frame/message-queue" } +pallet-balances = { path = "../../../substrate/frame/balances" } + +# For building docs +simple-mermaid = { git = "https://github.com/kianenigma/simple-mermaid.git", branch = "main" } +docify = "0.2.6" + +[dev-dependencies] +test-log = "0.2.14" diff --git a/polkadot/xcm/docs/mermaid/location_hierarchy.mmd b/polkadot/xcm/docs/mermaid/location_hierarchy.mmd new file mode 100644 index 0000000000000000000000000000000000000000..54fcfc8072a9aa08032da54f3b4332ef7db5d7c1 --- /dev/null +++ b/polkadot/xcm/docs/mermaid/location_hierarchy.mmd @@ -0,0 +1,9 @@ +flowchart + relay[Relaychain] --> paraA["Parachain(1000)"] + relay --> paraB["Parachain(2000)"] + + paraA --> pallet[Pallet] + pallet --> indexA[Index 1] + pallet --> indexB[Index 2] + + paraA --> account[Account] diff --git a/polkadot/xcm/docs/mermaid/structure.mmd b/polkadot/xcm/docs/mermaid/structure.mmd new file mode 100644 index 0000000000000000000000000000000000000000..17f60467241a351ab3c623b451b8ff4d79df2b9b --- /dev/null +++ b/polkadot/xcm/docs/mermaid/structure.mmd @@ -0,0 +1,4 @@ +flowchart + docs[xcm_docs] --> fundamentals + docs --> guides + docs --> cookbook diff --git a/polkadot/xcm/docs/mermaid/transport_protocols.mmd b/polkadot/xcm/docs/mermaid/transport_protocols.mmd new file mode 100644 index 0000000000000000000000000000000000000000..c0340db0651a3f273bbd35dd5fa51afe15a11c24 --- /dev/null +++ b/polkadot/xcm/docs/mermaid/transport_protocols.mmd @@ -0,0 +1,6 @@ +flowchart + relay[Relaychain] --"DMP"--> paraA["Parachain(2000)"] + relay --"DMP"--> paraB["Parachain(2001)"] + + paraA --"UMP"--> relay + paraB --"UMP"--> relay diff --git a/polkadot/xcm/docs/mermaid/universal_location.mmd b/polkadot/xcm/docs/mermaid/universal_location.mmd new file mode 100644 index 0000000000000000000000000000000000000000..97bfa747319db21dfe07032a3e7fea4d7a54f056 --- /dev/null +++ b/polkadot/xcm/docs/mermaid/universal_location.mmd @@ -0,0 +1,3 @@ +flowchart + universe[Universal Location] --> polkadot[Polkadot] + universe --> ethereum[Ethereum] diff --git a/polkadot/xcm/docs/mermaid/usdt_location.mmd b/polkadot/xcm/docs/mermaid/usdt_location.mmd new file mode 100644 index 0000000000000000000000000000000000000000..5e9222f6098ec900ed18b99a16a51c9e2584ee6e --- /dev/null +++ b/polkadot/xcm/docs/mermaid/usdt_location.mmd @@ -0,0 +1,6 @@ +flowchart + relay[Polkadot] --> assetHub["Asset Hub"] + relay --> anotherPara["Another parachain"] + + assetHub --> assetsPallet["Assets Pallet"] + assetsPallet --> usdt[1984] diff --git a/polkadot/xcm/docs/src/cookbook/mod.rs b/polkadot/xcm/docs/src/cookbook/mod.rs new file mode 100644 index 0000000000000000000000000000000000000000..1c69bf0ead6f81e4a11010cbf314f9638dda9ccb --- /dev/null +++ b/polkadot/xcm/docs/src/cookbook/mod.rs @@ -0,0 +1,27 @@ +// Copyright Parity Technologies (UK) Ltd. +// This file is part of Polkadot. + +// Polkadot is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// Polkadot is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with Polkadot. If not, see . + +//! # XCM Cookbook +//! +//! A collection of XCM recipes. +//! +//! Each recipe is tested and explains all the code necessary to run it -- they're not just snippets +//! to copy and paste. + +/// Configuring a parachain that only uses the Relay Chain native token. +/// In the case of Polkadot, this recipe will show you how to launch a parachain with no native +/// token -- dealing only on DOT. +pub mod relay_token_transactor; diff --git a/polkadot/xcm/docs/src/cookbook/relay_token_transactor/mod.rs b/polkadot/xcm/docs/src/cookbook/relay_token_transactor/mod.rs new file mode 100644 index 0000000000000000000000000000000000000000..279dd71a35f7410b6a6899e5c018c4f55ca18d15 --- /dev/null +++ b/polkadot/xcm/docs/src/cookbook/relay_token_transactor/mod.rs @@ -0,0 +1,51 @@ +// Copyright 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 . + +//! # Relay Asset Transactor +//! +//! This example shows how to configure a parachain to only deal with the Relay Chain token. +//! +//! The first step is using the [`xcm_builder::FungibleAdapter`] to create an `AssetTransactor` that +//! can handle the relay chain token. +#![doc = docify::embed!("src/cookbook/relay_token_transactor/parachain/xcm_config.rs", asset_transactor)] +//! +//! The second step is to configure `IsReserve` to recognize the relay chain as a reserve for its +//! own asset. +//! With this, you'll be able to easily mint a derivative asset, backed one-to-one from the Relay +//! Chain, by using the xcm pallet's `transfer_assets` extrinsic. +//! +//! The `IsReserve` type takes a type that implements `ContainsPair`. +//! In this case, we want a type that contains the pair `(relay_chain_native_token, relay_chain)`. +#![doc = docify::embed!("src/cookbook/relay_token_transactor/parachain/xcm_config.rs", is_reserve)] +//! +//! With this setup, we are able to do a reserve asset transfer to and from the parachain and relay +//! chain. +#![doc = docify::embed!("src/cookbook/relay_token_transactor/tests.rs", reserve_asset_transfers_work)] +//! +//! For the rest of the code, be sure to check the contents of this module. + +/// The parachain runtime for this example +pub mod parachain; + +/// The relay chain runtime for this example. +pub mod relay_chain; + +/// The network for this example. +pub mod network; + +/// Tests for this example. +#[cfg(test)] +pub mod tests; diff --git a/polkadot/xcm/docs/src/cookbook/relay_token_transactor/network.rs b/polkadot/xcm/docs/src/cookbook/relay_token_transactor/network.rs new file mode 100644 index 0000000000000000000000000000000000000000..46ac0e5df6372babf84b3494436e554353ba2820 --- /dev/null +++ b/polkadot/xcm/docs/src/cookbook/relay_token_transactor/network.rs @@ -0,0 +1,90 @@ +// Copyright Parity Technologies (UK) Ltd. +// This file is part of Polkadot. + +// Polkadot is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// Polkadot is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with Polkadot. If not, see . + +//! Mock network + +use frame::deps::{ + frame_system, + sp_io::TestExternalities, + sp_runtime::{AccountId32, BuildStorage}, +}; +use xcm_simulator::{decl_test_network, decl_test_parachain, decl_test_relay_chain, TestExt}; + +use super::{parachain, relay_chain}; + +pub const ALICE: AccountId32 = AccountId32::new([0u8; 32]); +pub const BOB: AccountId32 = AccountId32::new([1u8; 32]); +pub const UNITS: u64 = 10_000_000_000; +pub const CENTS: u64 = 100_000_000; +pub const INITIAL_BALANCE: u64 = UNITS; + +decl_test_parachain! { + pub struct ParaA { + Runtime = parachain::Runtime, + XcmpMessageHandler = parachain::MessageQueue, + DmpMessageHandler = parachain::MessageQueue, + new_ext = para_ext(), + } +} + +decl_test_relay_chain! { + pub struct Relay { + Runtime = relay_chain::Runtime, + RuntimeCall = relay_chain::RuntimeCall, + RuntimeEvent = relay_chain::RuntimeEvent, + XcmConfig = relay_chain::XcmConfig, + MessageQueue = relay_chain::MessageQueue, + System = relay_chain::System, + new_ext = relay_ext(), + } +} + +decl_test_network! { + pub struct MockNet { + relay_chain = Relay, + parachains = vec![ + (2222, ParaA), + ], + } +} + +pub fn para_ext() -> TestExternalities { + use parachain::{MessageQueue, Runtime, System}; + + let t = frame_system::GenesisConfig::::default().build_storage().unwrap(); + let mut ext = frame::deps::sp_io::TestExternalities::new(t); + ext.execute_with(|| { + System::set_block_number(1); + MessageQueue::set_para_id(2222.into()); + }); + ext +} + +pub fn relay_ext() -> TestExternalities { + use relay_chain::{Runtime, System}; + + let mut t = frame_system::GenesisConfig::::default().build_storage().unwrap(); + + pallet_balances::GenesisConfig:: { balances: vec![(ALICE, INITIAL_BALANCE)] } + .assimilate_storage(&mut t) + .unwrap(); + + let mut ext = TestExternalities::new(t); + ext.execute_with(|| { + System::set_block_number(1); + }); + ext +} diff --git a/polkadot/xcm/docs/src/cookbook/relay_token_transactor/parachain/mod.rs b/polkadot/xcm/docs/src/cookbook/relay_token_transactor/parachain/mod.rs new file mode 100644 index 0000000000000000000000000000000000000000..e3fdda2e733376ca3eb780acbc17256c12e6acac --- /dev/null +++ b/polkadot/xcm/docs/src/cookbook/relay_token_transactor/parachain/mod.rs @@ -0,0 +1,56 @@ +// Copyright Parity Technologies (UK) Ltd. +// This file is part of Polkadot. + +// Polkadot is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// Polkadot is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with Polkadot. If not, see . + +//! # Runtime + +use frame::{deps::frame_system, prelude::*, runtime::prelude::*, traits::IdentityLookup}; +use xcm_executor::XcmExecutor; +use xcm_simulator::mock_message_queue; + +mod xcm_config; +use xcm_config::XcmConfig; + +pub type Block = frame_system::mocking::MockBlock; +pub type AccountId = frame::deps::sp_runtime::AccountId32; +pub type Balance = u64; + +construct_runtime! { + pub struct Runtime { + System: frame_system, + MessageQueue: mock_message_queue, + Balances: pallet_balances, + XcmPallet: pallet_xcm, + } +} + +#[derive_impl(frame_system::config_preludes::TestDefaultConfig as frame_system::DefaultConfig)] +impl frame_system::Config for Runtime { + type Block = Block; + type AccountId = AccountId; + type Lookup = IdentityLookup; + type AccountData = pallet_balances::AccountData; +} + +impl mock_message_queue::Config for Runtime { + type RuntimeEvent = RuntimeEvent; + type XcmExecutor = XcmExecutor; +} + +#[derive_impl(pallet_balances::config_preludes::TestDefaultConfig as pallet_balances::DefaultConfig)] +impl pallet_balances::Config for Runtime { + type Balance = Balance; + type AccountStore = System; +} diff --git a/polkadot/xcm/docs/src/cookbook/relay_token_transactor/parachain/xcm_config.rs b/polkadot/xcm/docs/src/cookbook/relay_token_transactor/parachain/xcm_config.rs new file mode 100644 index 0000000000000000000000000000000000000000..99f17693093e7f0472d78caf54f842847a8a3e84 --- /dev/null +++ b/polkadot/xcm/docs/src/cookbook/relay_token_transactor/parachain/xcm_config.rs @@ -0,0 +1,189 @@ +// Copyright Parity Technologies (UK) Ltd. +// This file is part of Polkadot. + +// Polkadot is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// Polkadot is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with Polkadot. If not, see . + +//! # XCM Configuration + +use frame::{ + deps::frame_system, + runtime::prelude::*, + traits::{Everything, Nothing}, +}; +use xcm::v4::prelude::*; +use xcm_builder::{ + AccountId32Aliases, DescribeAllTerminal, DescribeFamily, EnsureXcmOrigin, + FrameTransactionalProcessor, FungibleAdapter, HashedDescription, IsConcrete, + SignedToAccountId32, +}; +use xcm_executor::XcmExecutor; + +use super::{AccountId, Balances, MessageQueue, Runtime, RuntimeCall, RuntimeEvent, RuntimeOrigin}; + +parameter_types! { + pub RelayLocation: Location = Location::parent(); + pub ThisNetwork: NetworkId = NetworkId::Polkadot; +} + +pub type LocationToAccountId = ( + HashedDescription>, + AccountId32Aliases, +); + +/// Configuration related to asset transactors +#[docify::export] +mod asset_transactor { + use super::*; + + parameter_types! { + pub ParentRelayLocation: Location = Location::parent(); + } + + /// AssetTransactor for handling the relay chain token + pub type FungibleTransactor = FungibleAdapter< + // Use this implementation of the `fungible::*` traits. + // `Balances` is the name given to the balances pallet in this particular recipe. + // Any implementation of the traits would suffice. + Balances, + // This transactor deals with the native token of the Relay Chain. + // This token is referenced by the Location of the Relay Chain relative to this chain + // -- Location::parent(). + IsConcrete, + // How to convert an XCM Location into a local account id. + // This is also something that's configured in the XCM executor. + LocationToAccountId, + // The type for account ids, only needed because `fungible` is generic over it. + AccountId, + // Not tracking teleports. + // This recipe only uses reserve asset transfers to handle the Relay Chain token. + (), + >; + + /// Actual configuration item that'll be set in the XCM config. + /// A tuple could be used here to have multiple transactors, each (potentially) handling + /// different assets. + /// In this recipe, we only have one. + pub type AssetTransactor = FungibleTransactor; +} + +/// Configuration related to token reserves +#[docify::export] +mod is_reserve { + use super::*; + + parameter_types! { + /// Reserves are specified using a pair `(AssetFilter, Location)`. + /// Each pair means that the specified Location is a reserve for all the assets in AssetsFilter. + /// Here, we are specifying that the Relay Chain is the reserve location for its native token. + pub RelayTokenForRelay: (AssetFilter, Location) = + (Wild(AllOf { id: AssetId(Parent.into()), fun: WildFungible }), Parent.into()); + } + + /// The wrapper type xcm_builder::Case is needed in order to use this in the configuration. + pub type IsReserve = xcm_builder::Case; +} + +mod weigher { + use super::*; + use xcm_builder::FixedWeightBounds; + + parameter_types! { + pub const WeightPerInstruction: Weight = Weight::from_parts(1, 1); + pub const MaxInstructions: u32 = 100; + } + + pub type Weigher = FixedWeightBounds; +} + +parameter_types! { + pub UniversalLocation: InteriorLocation = [GlobalConsensus(NetworkId::Polkadot), Parachain(2222)].into(); +} + +pub struct XcmConfig; +impl xcm_executor::Config for XcmConfig { + type RuntimeCall = RuntimeCall; + type XcmSender = (); + type AssetTransactor = asset_transactor::AssetTransactor; + type OriginConverter = (); + // The declaration of which Locations are reserves for which Assets. + type IsReserve = is_reserve::IsReserve; + type IsTeleporter = (); + type UniversalLocation = UniversalLocation; + // This is not safe, you should use `xcm_builder::AllowTopLevelPaidExecutionFrom` in a + // production chain + type Barrier = xcm_builder::AllowUnpaidExecutionFrom; + type Weigher = weigher::Weigher; + type Trader = (); + type ResponseHandler = (); + type AssetTrap = (); + type AssetLocker = (); + type AssetExchanger = (); + type AssetClaims = (); + type SubscriptionService = (); + type PalletInstancesInfo = (); + type FeeManager = (); + type MaxAssetsIntoHolding = frame::traits::ConstU32<1>; + type MessageExporter = (); + type UniversalAliases = Nothing; + type CallDispatcher = RuntimeCall; + type SafeCallFilter = Everything; + type Aliasers = Nothing; + type TransactionalProcessor = FrameTransactionalProcessor; + type HrmpNewChannelOpenRequestHandler = (); + type HrmpChannelAcceptedHandler = (); + type HrmpChannelClosingHandler = (); + type XcmRecorder = (); +} + +pub type LocalOriginToLocation = SignedToAccountId32; + +impl pallet_xcm::Config for Runtime { + // We turn off sending for these tests + type SendXcmOrigin = EnsureXcmOrigin; + type XcmRouter = super::super::network::ParachainXcmRouter; // Provided by xcm-simulator + // Anyone can execute XCM programs + type ExecuteXcmOrigin = EnsureXcmOrigin; + // We execute any type of program + type XcmExecuteFilter = Everything; + // How we execute programs + type XcmExecutor = XcmExecutor; + // We don't allow teleports + type XcmTeleportFilter = Nothing; + // We allow all reserve transfers + type XcmReserveTransferFilter = Everything; + // Same weigher executor uses to weigh XCM programs + type Weigher = weigher::Weigher; + // Same universal location + type UniversalLocation = UniversalLocation; + // No version discovery needed + const VERSION_DISCOVERY_QUEUE_SIZE: u32 = 0; + type AdvertisedXcmVersion = frame::traits::ConstU32<3>; + type AdminOrigin = frame_system::EnsureRoot; + // No locking + type TrustedLockers = (); + type MaxLockers = frame::traits::ConstU32<0>; + type MaxRemoteLockConsumers = frame::traits::ConstU32<0>; + type RemoteLockConsumerIdentifier = (); + // How to turn locations into accounts + type SovereignAccountOf = LocationToAccountId; + // A currency to pay for things and its matcher, we are using the relay token + type Currency = Balances; + type CurrencyMatcher = IsConcrete; + // Pallet benchmarks, no need for this recipe + type WeightInfo = pallet_xcm::TestWeightInfo; + // Runtime types + type RuntimeOrigin = RuntimeOrigin; + type RuntimeCall = RuntimeCall; + type RuntimeEvent = RuntimeEvent; +} diff --git a/polkadot/xcm/docs/src/cookbook/relay_token_transactor/relay_chain/mod.rs b/polkadot/xcm/docs/src/cookbook/relay_token_transactor/relay_chain/mod.rs new file mode 100644 index 0000000000000000000000000000000000000000..25c35dd4aaa83c12b0176ea528d09f7d84bc87ce --- /dev/null +++ b/polkadot/xcm/docs/src/cookbook/relay_token_transactor/relay_chain/mod.rs @@ -0,0 +1,103 @@ +// Copyright 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 . + +//! Relay chain runtime mock. + +use frame::{ + deps::{frame_support::weights::WeightMeter, sp_runtime::AccountId32}, + prelude::*, + runtime::prelude::*, + traits::{IdentityLookup, ProcessMessage, ProcessMessageError}, +}; +use polkadot_runtime_parachains::inclusion::{AggregateMessageOrigin, UmpQueueId}; +use xcm::v4::prelude::*; + +mod xcm_config; +pub use xcm_config::LocationToAccountId; +use xcm_config::XcmConfig; + +pub type AccountId = AccountId32; +pub type Balance = u64; + +parameter_types! { + pub const BlockHashCount: u64 = 250; +} + +#[derive_impl(frame_system::config_preludes::TestDefaultConfig as frame_system::DefaultConfig)] +impl frame_system::Config for Runtime { + type AccountId = AccountId; + type Lookup = IdentityLookup; + type Block = Block; + type AccountData = pallet_balances::AccountData; +} + +#[derive_impl(pallet_balances::config_preludes::TestDefaultConfig as pallet_balances::DefaultConfig)] +impl pallet_balances::Config for Runtime { + type AccountStore = System; +} + +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); + pub const MessageQueueHeapSize: u32 = 65_536; + pub const MessageQueueMaxStale: u32 = 16; +} + +/// Message processor to handle any messages that were enqueued into the `MessageQueue` pallet. +pub struct MessageProcessor; +impl ProcessMessage for MessageProcessor { + type Origin = AggregateMessageOrigin; + + fn process_message( + message: &[u8], + origin: Self::Origin, + meter: &mut WeightMeter, + id: &mut [u8; 32], + ) -> Result { + let para = match origin { + AggregateMessageOrigin::Ump(UmpQueueId::Para(para)) => para, + }; + xcm_builder::ProcessXcmMessage::< + Junction, + xcm_executor::XcmExecutor, + RuntimeCall, + >::process_message(message, Junction::Parachain(para.into()), meter, id) + } +} + +impl pallet_message_queue::Config for Runtime { + type RuntimeEvent = RuntimeEvent; + type Size = u32; + type HeapSize = MessageQueueHeapSize; + type MaxStale = MessageQueueMaxStale; + type ServiceWeight = MessageQueueServiceWeight; + type MessageProcessor = MessageProcessor; + type QueueChangeHandler = (); + type QueuePausedQuery = (); + type WeightInfo = (); + type IdleMaxServiceWeight = MessageQueueServiceWeight; +} + +construct_runtime! { + pub struct Runtime { + System: frame_system, + Balances: pallet_balances, + MessageQueue: pallet_message_queue, + XcmPallet: pallet_xcm, + } +} diff --git a/polkadot/xcm/docs/src/cookbook/relay_token_transactor/relay_chain/xcm_config.rs b/polkadot/xcm/docs/src/cookbook/relay_token_transactor/relay_chain/xcm_config.rs new file mode 100644 index 0000000000000000000000000000000000000000..987bb3f9ab6649bc299edafa97dc1d06166db440 --- /dev/null +++ b/polkadot/xcm/docs/src/cookbook/relay_token_transactor/relay_chain/xcm_config.rs @@ -0,0 +1,163 @@ +// Copyright 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 . + +//! Relay chain XCM configuration + +use frame::{ + deps::frame_system, + runtime::prelude::*, + traits::{Everything, Nothing}, +}; +use xcm::v4::prelude::*; +use xcm_builder::{ + AccountId32Aliases, DescribeAllTerminal, DescribeFamily, EnsureXcmOrigin, + FrameTransactionalProcessor, FungibleAdapter, HashedDescription, IsConcrete, + SignedToAccountId32, +}; +use xcm_executor::XcmExecutor; + +use super::{AccountId, Balances, Runtime, RuntimeCall, RuntimeEvent, RuntimeOrigin}; + +parameter_types! { + pub HereLocation: Location = Location::here(); + pub ThisNetwork: NetworkId = NetworkId::Polkadot; +} + +/// Converter from XCM Locations to accounts. +/// This generates sovereign accounts for Locations and converts +/// local AccountId32 junctions to local accounts. +pub type LocationToAccountId = ( + HashedDescription>, + AccountId32Aliases, +); + +mod asset_transactor { + use super::*; + + /// AssetTransactor for handling the Relay Chain token. + pub type FungibleTransactor = FungibleAdapter< + // Use this `fungible` implementation. + Balances, + // This transactor handles the native token. + IsConcrete, + // How to convert an XCM Location into a local account id. + // Whenever assets are handled, the location is turned into an account. + // This account is the one where balances are withdrawn/deposited. + LocationToAccountId, + // The account id type, needed because `fungible` is generic over it. + AccountId, + // Not tracking teleports. + (), + >; + + /// All asset transactors, in this case only one + pub type AssetTransactor = FungibleTransactor; +} + +mod weigher { + use super::*; + use xcm_builder::FixedWeightBounds; + + parameter_types! { + pub const WeightPerInstruction: Weight = Weight::from_parts(1, 1); + pub const MaxInstructions: u32 = 100; + } + + pub type Weigher = FixedWeightBounds; +} + +parameter_types! { + pub UniversalLocation: InteriorLocation = [GlobalConsensus(NetworkId::Polkadot)].into(); +} + +pub struct XcmConfig; +impl xcm_executor::Config for XcmConfig { + type RuntimeCall = RuntimeCall; + type XcmSender = (); + type AssetTransactor = asset_transactor::AssetTransactor; + type OriginConverter = (); + // We don't need to recognize anyone as a reserve + type IsReserve = (); + type IsTeleporter = (); + type UniversalLocation = UniversalLocation; + // This is not safe, you should use `xcm_builder::AllowTopLevelPaidExecutionFrom` in a + // production chain + type Barrier = xcm_builder::AllowUnpaidExecutionFrom; + type Weigher = weigher::Weigher; + type Trader = (); + type ResponseHandler = (); + type AssetTrap = (); + type AssetLocker = (); + type AssetExchanger = (); + type AssetClaims = (); + type SubscriptionService = (); + type PalletInstancesInfo = (); + type FeeManager = (); + type MaxAssetsIntoHolding = frame::traits::ConstU32<1>; + type MessageExporter = (); + type UniversalAliases = Nothing; + type CallDispatcher = RuntimeCall; + type SafeCallFilter = Everything; + type Aliasers = Nothing; + type TransactionalProcessor = FrameTransactionalProcessor; + type HrmpNewChannelOpenRequestHandler = (); + type HrmpChannelAcceptedHandler = (); + type HrmpChannelClosingHandler = (); + type XcmRecorder = (); +} + +pub type LocalOriginToLocation = SignedToAccountId32; + +impl pallet_xcm::Config for Runtime { + // No one can call `send` + type SendXcmOrigin = EnsureXcmOrigin; + type XcmRouter = super::super::network::RelayChainXcmRouter; // Provided by xcm-simulator + // Anyone can execute XCM programs + type ExecuteXcmOrigin = EnsureXcmOrigin; + // We execute any type of program + type XcmExecuteFilter = Everything; + // How we execute programs + type XcmExecutor = XcmExecutor; + // We don't allow teleports + type XcmTeleportFilter = Nothing; + // We allow all reserve transfers. + // This is so it can act as a reserve for its native token. + type XcmReserveTransferFilter = Everything; + // Same weigher executor uses to weigh XCM programs + type Weigher = weigher::Weigher; + // Same universal location + type UniversalLocation = UniversalLocation; + // No version discovery needed + const VERSION_DISCOVERY_QUEUE_SIZE: u32 = 0; + type AdvertisedXcmVersion = frame::traits::ConstU32<3>; + type AdminOrigin = frame_system::EnsureRoot; + // No locking + type TrustedLockers = (); + type MaxLockers = frame::traits::ConstU32<0>; + type MaxRemoteLockConsumers = frame::traits::ConstU32<0>; + type RemoteLockConsumerIdentifier = (); + // How to turn locations into accounts + type SovereignAccountOf = LocationToAccountId; + // A currency to pay for things and its matcher, we are using the relay token + type Currency = Balances; + type CurrencyMatcher = IsConcrete; + // Pallet benchmarks, no need for this example + type WeightInfo = pallet_xcm::TestWeightInfo; + // Runtime types + type RuntimeOrigin = RuntimeOrigin; + type RuntimeCall = RuntimeCall; + type RuntimeEvent = RuntimeEvent; +} diff --git a/polkadot/xcm/docs/src/cookbook/relay_token_transactor/tests.rs b/polkadot/xcm/docs/src/cookbook/relay_token_transactor/tests.rs new file mode 100644 index 0000000000000000000000000000000000000000..792cf6149e7cb418f5ffa5720f41ae44956ff036 --- /dev/null +++ b/polkadot/xcm/docs/src/cookbook/relay_token_transactor/tests.rs @@ -0,0 +1,128 @@ +// Copyright Parity Technologies (UK) Ltd. +// This file is part of Polkadot. + +// Polkadot is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// Polkadot is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with Polkadot. If not, see . + +use frame::testing_prelude::*; +use test_log::test; +use xcm::prelude::*; +use xcm_executor::traits::ConvertLocation; +use xcm_simulator::TestExt; + +use super::{ + network::{MockNet, ParaA, Relay, ALICE, BOB, CENTS, INITIAL_BALANCE}, + parachain, relay_chain, +}; + +#[docify::export] +#[test] +fn reserve_asset_transfers_work() { + // Scenario: + // ALICE on the relay chain holds some of Relay Chain's native tokens. + // She transfers them to BOB's account on the parachain using a reserve transfer. + // BOB receives Relay Chain native token derivatives on the parachain, + // which are backed one-to-one with the real tokens on the Relay Chain. + // + // NOTE: We could've used ALICE on both chains because it's a different account, + // but using ALICE and BOB makes it clearer. + + // We restart the mock network. + MockNet::reset(); + + // ALICE starts with INITIAL_BALANCE on the relay chain + Relay::execute_with(|| { + assert_eq!(relay_chain::Balances::free_balance(&ALICE), INITIAL_BALANCE); + }); + + // BOB starts with 0 on the parachain + ParaA::execute_with(|| { + assert_eq!(parachain::Balances::free_balance(&BOB), 0); + }); + + // ALICE on the Relay Chain sends some Relay Chain native tokens to BOB on the parachain. + // The transfer is done with the `transfer_assets` extrinsic in the XCM pallet. + // The extrinsic figures out it should do a reserve asset transfer + // with the local chain as reserve. + Relay::execute_with(|| { + // The parachain id is specified in the network.rs file in this recipe. + let destination: Location = Parachain(2222).into(); + let beneficiary: Location = + AccountId32 { id: BOB.clone().into(), network: Some(NetworkId::Polkadot) }.into(); + // We need to use `u128` here for the conversion to work properly. + // If we don't specify anything, it will be a `u64`, which the conversion + // will turn into a non-fungible token instead of a fungible one. + let assets: Assets = (Here, 50u128 * CENTS as u128).into(); + assert_ok!(relay_chain::XcmPallet::transfer_assets( + relay_chain::RuntimeOrigin::signed(ALICE), + Box::new(VersionedLocation::V4(destination.clone())), + Box::new(VersionedLocation::V4(beneficiary)), + Box::new(VersionedAssets::V4(assets)), + 0, + WeightLimit::Unlimited, + )); + + // ALICE now has less Relay Chain tokens. + assert_eq!(relay_chain::Balances::free_balance(&ALICE), INITIAL_BALANCE - 50 * CENTS); + + // The funds of the sovereign account of the parachain increase by 50 cents, + // the ones transferred over to BOB. + // The funds in this sovereign account represent how many Relay Chain tokens + // have been sent to this parachain. + // If the parachain wants to send those assets somewhere else they have to go + // via the reserve, and this balance is updated accordingly. + // This is why the derivatives are backed one-to-one. + let parachains_sovereign_account = + relay_chain::LocationToAccountId::convert_location(&destination).unwrap(); + assert_eq!(relay_chain::Balances::free_balance(parachains_sovereign_account), 50 * CENTS); + }); + + ParaA::execute_with(|| { + // On the parachain, BOB has received the derivative tokens + assert_eq!(parachain::Balances::free_balance(&BOB), 50 * CENTS); + + // BOB gives back half to ALICE in the relay chain + let destination: Location = Parent.into(); + let beneficiary: Location = + AccountId32 { id: ALICE.clone().into(), network: Some(NetworkId::Polkadot) }.into(); + // We specify `Parent` because we are referencing the Relay Chain token. + // This chain doesn't have a token of its own, so we always refer to this token, + // and we do so by the Location of the Relay Chain. + let assets: Assets = (Parent, 25u128 * CENTS as u128).into(); + assert_ok!(parachain::XcmPallet::transfer_assets( + parachain::RuntimeOrigin::signed(BOB), + Box::new(VersionedLocation::V4(destination)), + Box::new(VersionedLocation::V4(beneficiary)), + Box::new(VersionedAssets::V4(assets)), + 0, + WeightLimit::Unlimited, + )); + + // BOB's balance decreased + assert_eq!(parachain::Balances::free_balance(&BOB), 25 * CENTS); + }); + + Relay::execute_with(|| { + // ALICE's balance increases + assert_eq!( + relay_chain::Balances::free_balance(&ALICE), + INITIAL_BALANCE - 50 * CENTS + 25 * CENTS + ); + + // The funds in the parachain's sovereign account decrease. + let parachain: Location = Parachain(2222).into(); + let parachains_sovereign_account = + relay_chain::LocationToAccountId::convert_location(¶chain).unwrap(); + assert_eq!(relay_chain::Balances::free_balance(parachains_sovereign_account), 25 * CENTS); + }); +} diff --git a/polkadot/xcm/docs/src/fundamentals.rs b/polkadot/xcm/docs/src/fundamentals.rs new file mode 100644 index 0000000000000000000000000000000000000000..28899df801aa4f533cdfedaea8815804dc8bd7c2 --- /dev/null +++ b/polkadot/xcm/docs/src/fundamentals.rs @@ -0,0 +1,177 @@ +// Copyright Parity Technologies (UK) Ltd. +// This file is part of Polkadot. + +// Polkadot is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// Polkadot is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with Polkadot. If not, see . + +//! # XCM Fundamentals +//! +//! XCM standardizes usual actions users take in consensus systems, for example +//! dealing with assets locally, on other chains, and locking them. +//! XCM programs can both be executed locally or sent to a different consensus system. +//! Examples of consensus systems are blockchains and smart contracts. +//! +//! The goal of XCM is to allow multi-chain ecosystems to thrive via specialization. +//! Very specific functionalities can be abstracted away and standardized in this common language. +//! Then, every member of the ecosystem can implement the subset of the language that makes sense +//! for them. +//! +//! The language evolves over time to accomodate the needs of the community +//! via the [RFC process](https://github.com/paritytech/xcm-format/blob/master/proposals/0032-process.md). +//! +//! XCM is the language, it deals with interpreting and executing programs. +//! It does not deal with actually **sending** these programs from one consensus system to another. +//! This responsibility falls to a transport protocol. +//! XCM can even be interpreted on the local system, with no need of a transport protocol. +//! However, automatic and composable workflows can be achieved via the use of one. +//! +//! At the core of XCM lies the XCVM, the Cross-Consensus Virtual Machine. +//! It's the virtual machine that executes XCM programs. +//! It is a specification that comes with the language. +//! +//! For these docs, we'll use a Rust implementation of XCM and the XCVM, consisting of the following +//! parts: +//! - [`XCM`](xcm): Holds the definition of an XCM program, the instructions and main concepts. +//! - [`Executor`](xcm_executor): Implements the XCVM, capable of executing XCMs. Highly +//! configurable. +//! - [`Builder`](xcm_builder): A collection of types used to configure the executor. +//! - [`XCM Pallet`](pallet_xcm): A FRAME pallet for interacting with the executor. +//! - [`Simulator`](xcm_simulator): A playground to tinker with different XCM programs and executor +//! configurations. +//! +//! XCM programs are composed of Instructions, which reference Locations and Assets. +//! +//! ## Locations +//! +//! Locations are XCM's vocabulary of places we want to talk about in our XCM programs. +//! They are used to reference things like 32-byte accounts, governance bodies, smart contracts, +//! blockchains and more. +//! +//! Locations are hierarchical. +//! This means some places in consensus are wholly encapsulated in other places. +//! Say we have two systems A and B. +//! If any change in A's state implies a change in B's state, then we say A is interior to B. +#![doc = simple_mermaid::mermaid!("../mermaid/location_hierarchy.mmd")] +//! +//! Parachains are interior to their Relay Chain, since a change in their state implies a change in +//! the Relay Chain's state. +//! +//! Because of this hierarchy, the way we represent locations is with both a number of **parents**, +//! times we move __up__ the hierarchy, and a sequence of **junctions**, the steps we take __down__ +//! the hierarchy after going up the specified number of parents. +//! +//! In Rust, this is specified with the following datatype: +//! ```ignore +//! pub struct Location { +//! parents: u8, +//! interior: Junctions, +//! } +//! ``` +//! +//! Many junctions are available; parachains, pallets, 32 and 20 byte accounts, governance bodies, +//! and arbitrary indices are the most common. +//! A full list of available junctions can be found in the [format](https://github.com/paritytech/xcm-format#interior-locations--junctions) +//! and [Junction enum](xcm::v4::prelude::Junction). +//! +//! We'll use a file system notation to represent locations, and start with relative locations. +//! In the diagram, the location of parachain 1000 as seen from all other locations is as follows: +//! - From the relaychain: `Parachain(1000)` +//! - From parachain 1000 itself: `Here` +//! - From parachain 2000: `../Parachain(1000)` +//! +//! Relative locations are interpreted by the system that is executing an XCM program, which is the +//! receiver of a message in the case where it's sent. +//! +//! Locations can also be absolute. +//! Keeping in line with our filesystem analogy, we can imagine the root of our filesystem to exist. +//! This would be a location with no parents, that is also the parent of all systems that derive +//! their own consensus, say Polkadot or Ethereum or Bitcoin. +//! Such a location does not exist concretely, but we can still use this definition for it. +//! This is the **universal location**. +//! We need the universal location to be able to describe locations in an absolute way. +#![doc = simple_mermaid::mermaid!("../mermaid/universal_location.mmd")] +//! +//! Here, the absolute location of parachain 1000 would be +//! `GlobalConsensus(Polkadot)/Parachain(1000)`. +//! +//! ## Assets +//! +//! We want to be able to reference assets in our XCM programs, if only to be able to pay for fees. +//! Assets are represented using locations. +//! +//! The native asset of a chain is represented by the location of that chain. +//! For example, DOT is represented by the location of the Polkadot relaychain. +//! If the interpreting chain has its own asset, it would be represented by `Here`. +//! +//! How do we represent other assets? +//! The asset hub system parachain in Polkadot, for example, holds a lot of assets. +//! To represent each of them, it uses the indices we mentioned, and it makes them interior to the +//! assets pallet instance it uses. +//! USDT, an example asset that lives on asset hub, is identified by the location +//! `Parachain(1000)/PalletInstance(53)/GeneralIndex(1984)`, when seen from the Polkadot relaychain. +#![doc = simple_mermaid::mermaid!("../mermaid/usdt_location.mmd")] +//! +//! Asset Hub also has another type of assets called `ForeignAssets`. +//! These assets are identified by the XCM Location to their origin. +//! Two such assets are a Parachain asset, like Moonbeam's GLMR, and KSM, from the cousin Kusama +//! network. These are represented as `../Parachain(2004)/PalletInstance(10)` and +//! `../../GlobalConsensus(Kusama)` respectively. +//! +//! The whole type can be seen in the [format](https://github.com/paritytech/xcm-format#6-universal-asset-identifiers) +//! and [rust docs](xcm::v4::prelude::Asset). +//! +//! ## Instructions +//! +//! Given the vocabulary to talk about both locations -- chains and accounts -- and assets, we now +//! need a way to express what we want the consensus system to do when executing our programs. +//! We need a way of writing our programs. +//! +//! XCM programs are composed of a sequence of instructions. +//! +//! All available instructions can be seen in the [format](https://github.com/paritytech/xcm-format#5-the-xcvm-instruction-set) +//! and the [Instruction enum](xcm::v4::prelude::Instruction). +//! +//! A very simple example is the following: +//! +//! ```ignore +//! let message = Xcm(vec![ +//! TransferAsset { assets, beneficiary }, +//! ]); +//! ``` +//! +//! This instruction is enough to transfer `assets` from the account of the **origin** of a message +//! to the `beneficiary` account. However, because of XCM's generality, fees need to be paid +//! explicitly. This next example sheds more light on this: +//! +//! ```ignore +//! let message = Xcm(vec![ +//! WithdrawAsset(assets), +//! BuyExecution { fees: assets, weight_limit }, +//! DepositAsset { assets: AssetFilter(Wild(All)), beneficiary }, +//! ]); +//! ``` +//! +//! Here we see the process of transferring assets was broken down into smaller instructions, and we +//! add the explicit fee payment step in the middle. +//! `WithdrawAsset` withdraws assets from the account of the **origin** of the message for usage +//! inside this message's execution. `BuyExecution` explicitly buys execution for this program using +//! the assets specified in `fees`, with a sanity check of `weight_limit`. `DepositAsset` uses a +//! wildcard, specifying all remaining `assets` after subtracting the fees and a `beneficiary` +//! account. +//! +//! ## Next steps +//! +//! Continue with the [guides](crate::guides) for step-by-step tutorials on XCM, +//! or jump to the [cookbook](crate::cookbook) to see examples. +//! +//! The [glossary](crate::glossary) can be useful if some of the terms are confusing. diff --git a/polkadot/xcm/docs/src/glossary.rs b/polkadot/xcm/docs/src/glossary.rs new file mode 100644 index 0000000000000000000000000000000000000000..6035888ab733b2751a4f24d51336132111d6ef57 --- /dev/null +++ b/polkadot/xcm/docs/src/glossary.rs @@ -0,0 +1,123 @@ +// Copyright 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 . + +//! # Glossary +//! +//! ## XCM (Cross-Consensus Messaging) +//! +//! A messaging format meant to communicate intentions between consensus systems. +//! XCM could also refer to a single message. +//! +//! ## Instructions +//! +//! XCMs are composed of a sequence of instructions. +//! Each instruction aims to convey a particular intention. +//! There are instructions for transferring and locking assets, handling fees, calling arbitrary +//! blobs, and more. +//! +//! ## Consensus system +//! +//! A system that can reach any kind of consensus. +//! For example, relay chains, parachains, smart contracts. +//! Most messaging between consensus systems has to be done asynchronously, for this, XCM is used. +//! Between two smart contracts on the same parachain, however, communication can be done +//! synchronously. +//! +//! ## [`Location`](xcm::v4::prelude::Location) +//! +//! A way of addressing consensus systems. +//! These could be relative or absolute. +//! +//! ## [`Junction`](xcm::v4::prelude::Junction) +//! +//! The different ways of descending down a [`Location`](xcm::v4::prelude::Location) hierarchy. +//! A junction can be a Parachain, an Account, or more. +//! +//! ## [`Asset`](xcm::v4::prelude::Asset) +//! +//! A way of identifying assets in the same or another consensus system, by using a +//! [`Location`](xcm::v4::prelude::Location). +//! +//! ## Sovereign account +//! +//! An account in a consensus system that is controlled by an account in another consensus system. +//! +//! Runtimes use a converter between a [`Location`](xcm::v4::prelude::Location) and an account. +//! These converters implement the [`ConvertLocation`](xcm_executor::traits::ConvertLocation) trait. +//! +//! ## Teleport +//! +//! A way of transferring assets between two consensus systems without the need of a third party. +//! It consists of the sender system burning the asset that wants to be sent over and the recipient +//! minting an equivalent amount of that asset. It requires a lot of trust between the two systems, +//! since failure to mint or burn will reduce or increase the total issuance of the token. +//! +//! ## Reserve asset transfer +//! +//! A way of transferring assets between two consensus systems that don't trust each other, by using +//! a third system they both trust, called the reserve. The real asset only exists on the reserve, +//! both sender and recipient only deal with derivatives. It consists of the sender burning a +//! certain amount of derivatives, telling the reserve to move real assets from its sovereign +//! account to the destination's sovereign account, and then telling the recipient to mint the right +//! amount of derivatives. +//! In practice, the reserve chain can also be one of the source or destination. +//! +//! ## XCVM +//! +//! The virtual machine behind XCM. +//! Every XCM is an XCVM programme. +//! Holds state in registers. +//! +//! An implementation of the virtual machine is the [`xcm-executor`](xcm_executor::XcmExecutor). +//! +//! ## Holding register +//! +//! An XCVM register used to hold arbitrary `Asset`s during the execution of an XCVM programme. +//! +//! ## Barrier +//! +//! An XCM executor configuration item that works as a firewall for incoming XCMs. +//! All XCMs have to pass the barrier to be executed, else they are dropped. +//! It can be used for whitelisting only certain types or messages or messages from certain senders. +//! +//! Lots of barrier definitions exist in [`xcm-builder`](xcm_builder). +//! +//! ## VMP (Vertical Message Passing) +//! +//! Umbrella term for both UMP (Upward Message Passing) and DMP (Downward Message Passing). +//! +//! The following diagram shows the uses of both protocols: +#![doc = simple_mermaid::mermaid!("../mermaid/transport_protocols.mmd")] +//! +//! ## UMP (Upward Message Passing) +//! +//! Transport-layer protocol that allows parachains to send messages upwards to their relay chain. +//! +//! ## DMP (Downward Message Passing) +//! +//! Transport-layer protocol that allows the relay chain to send messages downwards to one of their +//! parachains. +//! +//! ## XCMP (Cross-Consensus Message Passing) +//! +//! Transport-layer protocol that allows parachains to send messages between themselves, without +//! going through the relay chain. +//! +//! ## HRMP (Horizontal Message Passing) +//! +//! Transport-layer protocol that allows a parachain to send messages to a sibling parachain going +//! through the relay chain. It's a precursor to XCMP, also known as XCMP-lite. +//! It uses a mixture of UMP and DMP. diff --git a/polkadot/xcm/docs/src/guides/mod.rs b/polkadot/xcm/docs/src/guides/mod.rs new file mode 100644 index 0000000000000000000000000000000000000000..5af89428d9a4c570831c17f48b5974e5ded5fd58 --- /dev/null +++ b/polkadot/xcm/docs/src/guides/mod.rs @@ -0,0 +1,25 @@ +// Copyright Parity Technologies (UK) Ltd. +// This file is part of Polkadot. + +// Polkadot is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// Polkadot is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with Polkadot. If not, see . + +//! # XCM Guides +//! +//! These guides aim to get you up and running with XCM. +//! +//! Coming soon. +//! +//! ## Next steps +//! +//! Jump to the [cookbook](crate::cookbook) for different examples. diff --git a/polkadot/xcm/docs/src/lib.rs b/polkadot/xcm/docs/src/lib.rs new file mode 100644 index 0000000000000000000000000000000000000000..287c97140c91b371765257475b0d7a3ade2e2f06 --- /dev/null +++ b/polkadot/xcm/docs/src/lib.rs @@ -0,0 +1,63 @@ +// Copyright Parity Technologies (UK) Ltd. +// This file is part of Polkadot. + +// Polkadot is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// Polkadot is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with Polkadot. If not, see . + +//! # XCM Docs +//! +//! Documentation and guides for XCM +//! +//! Welcome to the Cross-Consensus Messaging documentation! +//! +//! XCM is a **language** for communicating **intentions** between **consensus systems**. +//! Whether you're a developer, a blockchain enthusiast, or just interested in Polkadot, this guide +//! aims to provide you with an easy-to-understand and comprehensive introduction to XCM. +//! +//! ## Getting started +//! +//! Head over to the [fundamentals](fundamentals) section. +//! Then, go to the [guides](guides), to learn about how to do things with XCM. +//! +//! ## Cookbook +//! +//! There's also the [cookbook](cookbook) for useful recipes for XCM. +//! +//! ## Glossary +//! +//! There's a [glossary](glossary) with common terms used throughout the docs. +//! +//! ## Contribute +//! +//! To contribute to the format, check out the [RFC process](https://github.com/paritytech/xcm-format/blob/master/proposals/0032-process.md). +//! To contribute to these docs, [make a PR](https://github.com/paritytech/polkadot-sdk). +//! +//! ## Why Rust Docs? +//! +//! Rust Docs allow docs to be as close to the source as possible. +//! They're also available offline automatically for anyone who has the `polkadot-sdk` repo locally. +//! +//! ## Docs structure +#![doc = simple_mermaid::mermaid!("../mermaid/structure.mmd")] + +/// Fundamentals of the XCM language. The virtual machine, instructions, locations and assets. +pub mod fundamentals; + +/// Step-by-step guides to set up an XCM environment and start hacking. +pub mod guides; + +/// Useful recipes for programs and configurations. +pub mod cookbook; + +/// Glossary +pub mod glossary; diff --git a/polkadot/xcm/pallet-xcm-benchmarks/Cargo.toml b/polkadot/xcm/pallet-xcm-benchmarks/Cargo.toml index 8c71426a6faee49023603caa250f37bcbb42f631..8bf3b9abf66349834b3c2b7d7cd367e4b0b835d8 100644 --- a/polkadot/xcm/pallet-xcm-benchmarks/Cargo.toml +++ b/polkadot/xcm/pallet-xcm-benchmarks/Cargo.toml @@ -13,7 +13,7 @@ workspace = true targets = ["x86_64-unknown-linux-gnu"] [dependencies] -codec = { package = "parity-scale-codec", version = "3.6.1", default-features = false } +codec = { package = "parity-scale-codec", version = "3.6.12", default-features = false } scale-info = { version = "2.11.1", default-features = false, features = ["derive"] } frame-support = { path = "../../../substrate/frame/support", default-features = false } frame-system = { path = "../../../substrate/frame/system", default-features = false } @@ -29,7 +29,6 @@ log = { workspace = true, default-features = true } [dev-dependencies] pallet-balances = { path = "../../../substrate/frame/balances" } pallet-assets = { path = "../../../substrate/frame/assets" } -sp-core = { path = "../../../substrate/primitives/core" } sp-tracing = { path = "../../../substrate/primitives/tracing" } xcm = { package = "staging-xcm", path = ".." } # temp diff --git a/polkadot/xcm/pallet-xcm-benchmarks/src/fungible/benchmarking.rs b/polkadot/xcm/pallet-xcm-benchmarks/src/fungible/benchmarking.rs index 4b77199069d341320a67f196719604cedcc35157..d99da9184b5d8c7f2680b23140df1083d487b452 100644 --- a/polkadot/xcm/pallet-xcm-benchmarks/src/fungible/benchmarking.rs +++ b/polkadot/xcm/pallet-xcm-benchmarks/src/fungible/benchmarking.rs @@ -146,8 +146,6 @@ benchmarks_instance_pallet! { initiate_reserve_withdraw { let (sender_account, sender_location) = account_and_location::(1); - let holding = T::worst_case_holding(1); - let assets_filter = AssetFilter::Definite(holding.clone().into_inner().into_iter().take(MAX_ITEMS_IN_ASSETS).collect::>().into()); let reserve = T::valid_destination().map_err(|_| BenchmarkError::Skip)?; let (expected_fees_mode, expected_assets_in_holding) = T::DeliveryHelper::ensure_successful_delivery( @@ -157,15 +155,29 @@ benchmarks_instance_pallet! { ); let sender_account_balance_before = T::TransactAsset::balance(&sender_account); + // generate holding and add possible required fees + let holding = if let Some(expected_assets_in_holding) = expected_assets_in_holding { + let mut holding = T::worst_case_holding(1 + expected_assets_in_holding.len() as u32); + for a in expected_assets_in_holding.into_inner() { + holding.push(a); + } + holding + } else { + T::worst_case_holding(1) + }; + let mut executor = new_executor::(sender_location); - executor.set_holding(holding.into()); + executor.set_holding(holding.clone().into()); if let Some(expected_fees_mode) = expected_fees_mode { executor.set_fees_mode(expected_fees_mode); } - if let Some(expected_assets_in_holding) = expected_assets_in_holding { - executor.set_holding(expected_assets_in_holding.into()); - } - let instruction = Instruction::InitiateReserveWithdraw { assets: assets_filter, reserve, xcm: Xcm(vec![]) }; + + let instruction = Instruction::InitiateReserveWithdraw { + // Worst case is looking through all holdings for every asset explicitly - respecting the limit `MAX_ITEMS_IN_ASSETS`. + assets: Definite(holding.into_inner().into_iter().take(MAX_ITEMS_IN_ASSETS).collect::>().into()), + reserve, + xcm: Xcm(vec![]) + }; let xcm = Xcm(vec![instruction]); }: { executor.bench_process(xcm)?; diff --git a/polkadot/xcm/pallet-xcm-benchmarks/src/fungible/mock.rs b/polkadot/xcm/pallet-xcm-benchmarks/src/fungible/mock.rs index c831cd024659135fd3fd5d85a4406351945d887f..c0dfa91afc7866500b8761753fb83c76b5b23069 100644 --- a/polkadot/xcm/pallet-xcm-benchmarks/src/fungible/mock.rs +++ b/polkadot/xcm/pallet-xcm-benchmarks/src/fungible/mock.rs @@ -16,17 +16,16 @@ //! A mock runtime for XCM benchmarking. -use crate::{fungible as xcm_balances_benchmark, mock::*}; +use crate::{fungible as xcm_balances_benchmark, generate_holding_assets, mock::*}; use frame_benchmarking::BenchmarkError; use frame_support::{ derive_impl, parameter_types, - traits::{ConstU32, Everything, Nothing}, - weights::Weight, + traits::{Everything, Nothing}, }; -use sp_core::H256; -use sp_runtime::traits::{BlakeTwo256, IdentityLookup}; use xcm::latest::prelude::*; -use xcm_builder::{AllowUnpaidExecutionFrom, FrameTransactionalProcessor, MintLocation}; +use xcm_builder::{ + AllowUnpaidExecutionFrom, EnsureDecodableXcm, FrameTransactionalProcessor, MintLocation, +}; type Block = frame_system::mocking::MockBlock; @@ -40,37 +39,10 @@ frame_support::construct_runtime!( } ); -parameter_types! { - pub const BlockHashCount: u64 = 250; - pub BlockWeights: frame_system::limits::BlockWeights = - frame_system::limits::BlockWeights::simple_max(Weight::from_parts(1024, u64::MAX)); -} - #[derive_impl(frame_system::config_preludes::TestDefaultConfig)] impl frame_system::Config for Test { - type BaseCallFilter = 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 = BlockHashCount; - 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! { @@ -121,7 +93,7 @@ parameter_types! { pub struct XcmConfig; impl xcm_executor::Config for XcmConfig { type RuntimeCall = RuntimeCall; - type XcmSender = DevNull; + type XcmSender = EnsureDecodableXcm; type AssetTransactor = AssetTransactor; type OriginConverter = (); type IsReserve = TrustedReserves; @@ -148,6 +120,7 @@ impl xcm_executor::Config for XcmConfig { type HrmpNewChannelOpenRequestHandler = (); type HrmpChannelAcceptedHandler = (); type HrmpChannelClosingHandler = (); + type XcmRecorder = (); } impl crate::Config for Test { @@ -160,9 +133,8 @@ impl crate::Config for Test { Ok(valid_destination) } fn worst_case_holding(depositable_count: u32) -> Assets { - crate::mock_worst_case_holding( - depositable_count, - ::MaxAssetsIntoHolding::get(), + generate_holding_assets( + ::MaxAssetsIntoHolding::get() - depositable_count, ) } } diff --git a/polkadot/xcm/pallet-xcm-benchmarks/src/generic/benchmarking.rs b/polkadot/xcm/pallet-xcm-benchmarks/src/generic/benchmarking.rs index 8c6ed4b5d0e0245a1758820bf5ab9ec9f7d095e9..760b21f93566e12b77a00f2c7b9b744f6db91d68 100644 --- a/polkadot/xcm/pallet-xcm-benchmarks/src/generic/benchmarking.rs +++ b/polkadot/xcm/pallet-xcm-benchmarks/src/generic/benchmarking.rs @@ -19,9 +19,9 @@ use crate::{account_and_location, new_executor, EnsureDelivery, XcmCallOf}; use codec::Encode; use frame_benchmarking::{benchmarks, BenchmarkError}; use frame_support::{dispatch::GetDispatchInfo, traits::fungible::Inspect}; -use sp_std::vec; +use sp_std::{prelude::*, vec}; use xcm::{ - latest::{prelude::*, MaxDispatchErrorLen, MaybeErrorCode, Weight}, + latest::{prelude::*, MaxDispatchErrorLen, MaybeErrorCode, Weight, MAX_ITEMS_IN_ASSETS}, DoubleEncoded, }; use xcm_executor::{ @@ -32,7 +32,6 @@ use xcm_executor::{ benchmarks! { report_holding { let (sender_account, sender_location) = account_and_location::(1); - let holding = T::worst_case_holding(0); let destination = T::valid_destination().map_err(|_| BenchmarkError::Skip)?; let (expected_fees_mode, expected_assets_in_holding) = T::DeliveryHelper::ensure_successful_delivery( @@ -42,14 +41,22 @@ benchmarks! { ); let sender_account_balance_before = T::TransactAsset::balance(&sender_account); + // generate holding and add possible required fees + let holding = if let Some(expected_assets_in_holding) = expected_assets_in_holding { + let mut holding = T::worst_case_holding(expected_assets_in_holding.len() as u32); + for a in expected_assets_in_holding.into_inner() { + holding.push(a); + } + holding + } else { + T::worst_case_holding(0) + }; + let mut executor = new_executor::(sender_location); executor.set_holding(holding.clone().into()); if let Some(expected_fees_mode) = expected_fees_mode { executor.set_fees_mode(expected_fees_mode); } - if let Some(expected_assets_in_holding) = expected_assets_in_holding { - executor.set_holding(expected_assets_in_holding.into()); - } let instruction = Instruction::>::ReportHolding { response_info: QueryResponseInfo { @@ -57,8 +64,8 @@ benchmarks! { query_id: Default::default(), max_weight: Weight::MAX, }, - // Worst case is looking through all holdings for every asset explicitly. - assets: Definite(holding), + // Worst case is looking through all holdings for every asset explicitly - respecting the limit `MAX_ITEMS_IN_ASSETS`. + assets: Definite(holding.into_inner().into_iter().take(MAX_ITEMS_IN_ASSETS).collect::>().into()), }; let xcm = Xcm(vec![instruction]); @@ -612,14 +619,19 @@ benchmarks! { let sender_account = T::AccountIdConverter::convert_location(&owner).unwrap(); let sender_account_balance_before = T::TransactAsset::balance(&sender_account); + // generate holding and add possible required fees + let mut holding: Assets = asset.clone().into(); + if let Some(expected_assets_in_holding) = expected_assets_in_holding { + for a in expected_assets_in_holding.into_inner() { + holding.push(a); + } + }; + let mut executor = new_executor::(owner); - executor.set_holding(asset.clone().into()); + executor.set_holding(holding.into()); if let Some(expected_fees_mode) = expected_fees_mode { executor.set_fees_mode(expected_fees_mode); } - if let Some(expected_assets_in_holding) = expected_assets_in_holding { - executor.set_holding(expected_assets_in_holding.into()); - } let instruction = Instruction::LockAsset { asset, unlocker }; let xcm = Xcm(vec![instruction]); diff --git a/polkadot/xcm/pallet-xcm-benchmarks/src/generic/mock.rs b/polkadot/xcm/pallet-xcm-benchmarks/src/generic/mock.rs index 534f7d85ea2e9aa9759aca4bda9e4759dbf49517..f51d34092616b6191cefcb82803673f43f42e4c3 100644 --- a/polkadot/xcm/pallet-xcm-benchmarks/src/generic/mock.rs +++ b/polkadot/xcm/pallet-xcm-benchmarks/src/generic/mock.rs @@ -21,16 +21,15 @@ use codec::Decode; use frame_support::{ derive_impl, parameter_types, traits::{Contains, Everything, OriginTrait}, - weights::Weight, }; -use sp_core::H256; -use sp_runtime::traits::{BlakeTwo256, IdentityLookup, TrailingZeroInput}; +use sp_runtime::traits::TrailingZeroInput; use xcm_builder::{ test_utils::{ AssetsInHolding, TestAssetExchanger, TestAssetLocker, TestAssetTrap, TestSubscriptionService, TestUniversalAliases, }, - AliasForeignAccountId32, AllowUnpaidExecutionFrom, FrameTransactionalProcessor, + AliasForeignAccountId32, AllowUnpaidExecutionFrom, EnsureDecodableXcm, + FrameTransactionalProcessor, }; use xcm_executor::traits::ConvertOrigin; @@ -45,37 +44,10 @@ frame_support::construct_runtime!( } ); -parameter_types! { - pub const BlockHashCount: u64 = 250; - pub BlockWeights: frame_system::limits::BlockWeights = - frame_system::limits::BlockWeights::simple_max(Weight::from_parts(1024, u64::MAX)); -} - #[derive_impl(frame_system::config_preludes::TestDefaultConfig)] impl frame_system::Config for Test { - type BaseCallFilter = 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 = 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>; } /// The benchmarks in this pallet should never need an asset transactor to begin with. @@ -110,7 +82,7 @@ type Aliasers = AliasForeignAccountId32; pub struct XcmConfig; impl xcm_executor::Config for XcmConfig { type RuntimeCall = RuntimeCall; - type XcmSender = DevNull; + type XcmSender = EnsureDecodableXcm; type AssetTransactor = NoAssetTransactor; type OriginConverter = AlwaysSignedByDefault; type IsReserve = AllAssetLocationsPass; @@ -138,6 +110,7 @@ impl xcm_executor::Config for XcmConfig { type HrmpNewChannelOpenRequestHandler = (); type HrmpChannelAcceptedHandler = (); type HrmpChannelClosingHandler = (); + type XcmRecorder = (); } parameter_types! { @@ -161,9 +134,8 @@ impl crate::Config for Test { Ok(valid_destination) } fn worst_case_holding(depositable_count: u32) -> Assets { - crate::mock_worst_case_holding( - depositable_count, - ::MaxAssetsIntoHolding::get(), + generate_holding_assets( + ::MaxAssetsIntoHolding::get() - depositable_count, ) } } diff --git a/polkadot/xcm/pallet-xcm-benchmarks/src/lib.rs b/polkadot/xcm/pallet-xcm-benchmarks/src/lib.rs index 63ed0ac0ca736450077a4677d29d65a81e9eaf3b..a43f27bf47e7242308adc1b53d146508f14e36b2 100644 --- a/polkadot/xcm/pallet-xcm-benchmarks/src/lib.rs +++ b/polkadot/xcm/pallet-xcm-benchmarks/src/lib.rs @@ -50,6 +50,8 @@ pub trait Config: frame_system::Config { fn valid_destination() -> Result; /// Worst case scenario for a holding account in this runtime. + /// - `depositable_count` specifies the count of assets we plan to add to the holding on top of + /// those generated by the `worst_case_holding` implementation. fn worst_case_holding(depositable_count: u32) -> Assets; } @@ -64,19 +66,22 @@ pub type AssetTransactorOf = <::XcmConfig as XcmConfig>::AssetTr /// The call type of executor's config. Should eventually resolve to the same overarching call type. pub type XcmCallOf = <::XcmConfig as XcmConfig>::RuntimeCall; -pub fn mock_worst_case_holding(depositable_count: u32, max_assets: u32) -> Assets { +pub fn generate_holding_assets(max_assets: u32) -> Assets { let fungibles_amount: u128 = 100; - let holding_fungibles = max_assets / 2 - depositable_count; - let holding_non_fungibles = holding_fungibles; + let holding_fungibles = max_assets / 2; + let holding_non_fungibles = max_assets - holding_fungibles - 1; // -1 because of adding `Here` asset + // add count of `holding_fungibles` (0..holding_fungibles) .map(|i| { Asset { id: AssetId(GeneralIndex(i as u128).into()), - fun: Fungible(fungibles_amount * i as u128), + fun: Fungible(fungibles_amount * (i + 1) as u128), // non-zero amount } .into() }) + // add one more `Here` asset .chain(core::iter::once(Asset { id: AssetId(Here.into()), fun: Fungible(u128::MAX) })) + // add count of `holding_non_fungibles` .chain((0..holding_non_fungibles).map(|i| Asset { id: AssetId(GeneralIndex(i as u128).into()), fun: NonFungible(asset_instance_from(i)), diff --git a/polkadot/xcm/pallet-xcm-benchmarks/src/mock.rs b/polkadot/xcm/pallet-xcm-benchmarks/src/mock.rs index 78a9e5f8a018aad85fde699412a816fb54f30391..be3af5d4a3f325feb215d597e4328a90baf68911 100644 --- a/polkadot/xcm/pallet-xcm-benchmarks/src/mock.rs +++ b/polkadot/xcm/pallet-xcm-benchmarks/src/mock.rs @@ -58,7 +58,7 @@ impl xcm_executor::traits::ConvertLocation for AccountIdConverter { } parameter_types! { - pub UniversalLocation: InteriorLocation = Junction::Parachain(101).into(); + pub UniversalLocation: InteriorLocation = [GlobalConsensus(ByGenesis([1; 32])), Junction::Parachain(101)].into(); pub UnitWeightCost: Weight = Weight::from_parts(10, 10); pub WeightPrice: (AssetId, u128, u128) = (AssetId(Here.into()), 1_000_000, 1024); } diff --git a/polkadot/xcm/pallet-xcm/Cargo.toml b/polkadot/xcm/pallet-xcm/Cargo.toml index 460597e6649ab27acec712e1b055fbf5968005f2..6f9b389ab6f12db50c27fab0f5f20961c7f171c6 100644 --- a/polkadot/xcm/pallet-xcm/Cargo.toml +++ b/polkadot/xcm/pallet-xcm/Cargo.toml @@ -11,7 +11,7 @@ workspace = true [dependencies] bounded-collections = { version = "0.2.0", default-features = false } -codec = { package = "parity-scale-codec", version = "3.6.1", default-features = false, features = ["derive"] } +codec = { package = "parity-scale-codec", version = "3.6.12", default-features = false, features = ["derive"] } scale-info = { version = "2.11.1", default-features = false, features = ["derive"] } serde = { optional = true, features = ["derive"], workspace = true, default-features = true } log = { workspace = true } @@ -69,6 +69,7 @@ runtime-benchmarks = [ "sp-runtime/runtime-benchmarks", "xcm-builder/runtime-benchmarks", "xcm-executor/runtime-benchmarks", + "xcm-fee-payment-runtime-api/runtime-benchmarks", ] try-runtime = [ "frame-support/try-runtime", diff --git a/polkadot/xcm/pallet-xcm/src/benchmarking.rs b/polkadot/xcm/pallet-xcm/src/benchmarking.rs index e2903d592dc18aeafc7ef15d5ccc8d3fade1bcef..081a4235b7794b72beda33895c2e5e5c9577d219 100644 --- a/polkadot/xcm/pallet-xcm/src/benchmarking.rs +++ b/polkadot/xcm/pallet-xcm/src/benchmarking.rs @@ -16,12 +16,8 @@ use super::*; use bounded_collections::{ConstU32, WeakBoundedVec}; -use codec::Encode; use frame_benchmarking::{benchmarks, whitelisted_caller, BenchmarkError, BenchmarkResult}; -use frame_support::{ - traits::fungible::{Inspect, Mutate}, - weights::Weight, -}; +use frame_support::{assert_ok, weights::Weight}; use frame_system::RawOrigin; use sp_std::prelude::*; use xcm::{latest::prelude::*, v2}; @@ -90,11 +86,6 @@ pub trait Config: crate::Config { } benchmarks! { - where_clause { - where - T: pallet_balances::Config, - ::Balance: From + Into, - } send { let send_origin = T::SendXcmOrigin::try_successful_origin().map_err(|_| BenchmarkError::Weightless)?; @@ -109,31 +100,12 @@ benchmarks! { let versioned_msg = VersionedXcm::from(msg); }: _>(send_origin, Box::new(versioned_dest), Box::new(versioned_msg)) - send_blob { - let send_origin = - T::SendXcmOrigin::try_successful_origin().map_err(|_| BenchmarkError::Weightless)?; - if T::SendXcmOrigin::try_origin(send_origin.clone()).is_err() { - return Err(BenchmarkError::Override(BenchmarkResult::from_weight(Weight::MAX))) - } - let msg = Xcm::<()>(vec![ClearOrigin]); - let versioned_dest: VersionedLocation = T::reachable_dest().ok_or( - BenchmarkError::Override(BenchmarkResult::from_weight(Weight::MAX)), - )? - .into(); - let versioned_msg = VersionedXcm::from(msg); - let encoded_versioned_msg = versioned_msg.encode().try_into().unwrap(); - }: _>(send_origin, Box::new(versioned_dest), encoded_versioned_msg) - teleport_assets { let (asset, destination) = T::teleportable_asset_and_dest().ok_or( BenchmarkError::Override(BenchmarkResult::from_weight(Weight::MAX)), )?; - let transferred_amount = match &asset.fun { - Fungible(amount) => *amount, - _ => return Err(BenchmarkError::Stop("Benchmark asset not fungible")), - }.into(); - let assets: Assets = asset.into(); + let assets: Assets = asset.clone().into(); let caller: T::AccountId = whitelisted_caller(); let send_origin = RawOrigin::Signed(caller.clone()); @@ -150,13 +122,26 @@ benchmarks! { 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); + match &asset.fun { + Fungible(amount) => { + // Add transferred_amount to origin + ::AssetTransactor::deposit_asset( + &Asset { fun: Fungible(*amount), id: asset.id }, + &origin_location, + None, + ).map_err(|error| { + log::error!("Fungible asset couldn't be deposited, error: {:?}", error); + BenchmarkError::Override(BenchmarkResult::from_weight(Weight::MAX)) + })?; + }, + NonFungible(instance) => { + ::AssetTransactor::deposit_asset(&asset, &origin_location, None) + .map_err(|error| { + log::error!("Nonfungible asset couldn't be deposited, error: {:?}", error); + BenchmarkError::Override(BenchmarkResult::from_weight(Weight::MAX)) + })?; + } + }; let recipient = [0u8; 32]; let versioned_dest: VersionedLocation = destination.into(); @@ -164,21 +149,13 @@ benchmarks! { AccountId32 { network: None, id: recipient.into() }.into(); let versioned_assets: VersionedAssets = assets.into(); }: _>(send_origin.into(), Box::new(versioned_dest), Box::new(versioned_beneficiary), Box::new(versioned_assets), 0) - verify { - // verify balance after transfer, decreased by transferred amount (+ maybe XCM delivery fees) - assert!( as Inspect<_>>::balance(&caller) <= balance - transferred_amount); - } reserve_transfer_assets { let (asset, destination) = T::reserve_transferable_asset_and_dest().ok_or( BenchmarkError::Override(BenchmarkResult::from_weight(Weight::MAX)), )?; - let transferred_amount = match &asset.fun { - Fungible(amount) => *amount, - _ => return Err(BenchmarkError::Stop("Benchmark asset not fungible")), - }.into(); - let assets: Assets = asset.into(); + let assets: Assets = asset.clone().into(); let caller: T::AccountId = whitelisted_caller(); let send_origin = RawOrigin::Signed(caller.clone()); @@ -195,23 +172,50 @@ benchmarks! { 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); + match &asset.fun { + Fungible(amount) => { + // Add transferred_amount to origin + ::AssetTransactor::deposit_asset( + &Asset { fun: Fungible(*amount), id: asset.id.clone() }, + &origin_location, + None, + ).map_err(|error| { + log::error!("Fungible asset couldn't be deposited, error: {:?}", error); + BenchmarkError::Override(BenchmarkResult::from_weight(Weight::MAX)) + })?; + }, + NonFungible(instance) => { + ::AssetTransactor::deposit_asset(&asset, &origin_location, None) + .map_err(|error| { + log::error!("Nonfungible asset couldn't be deposited, error: {:?}", error); + BenchmarkError::Override(BenchmarkResult::from_weight(Weight::MAX)) + })?; + } + }; let recipient = [0u8; 32]; - let versioned_dest: VersionedLocation = destination.into(); + let versioned_dest: VersionedLocation = destination.clone().into(); let versioned_beneficiary: VersionedLocation = AccountId32 { network: None, id: recipient.into() }.into(); let versioned_assets: VersionedAssets = assets.into(); }: _>(send_origin.into(), Box::new(versioned_dest), Box::new(versioned_beneficiary), Box::new(versioned_assets), 0) verify { - // verify balance after transfer, decreased by transferred amount (+ maybe XCM delivery fees) - assert!( as Inspect<_>>::balance(&caller) <= balance - transferred_amount); + match &asset.fun { + Fungible(amount) => { + assert_ok!(::AssetTransactor::withdraw_asset( + &Asset { fun: Fungible(*amount), id: asset.id }, + &destination, + None, + )); + }, + NonFungible(instance) => { + assert_ok!(::AssetTransactor::withdraw_asset( + &asset, + &destination, + None, + )); + } + }; } transfer_assets { @@ -243,19 +247,6 @@ benchmarks! { let versioned_msg = VersionedXcm::from(msg); }: _>(execute_origin, Box::new(versioned_msg), Weight::MAX) - execute_blob { - let execute_origin = - T::ExecuteXcmOrigin::try_successful_origin().map_err(|_| BenchmarkError::Weightless)?; - let origin_location = T::ExecuteXcmOrigin::try_origin(execute_origin.clone()) - .map_err(|_| BenchmarkError::Override(BenchmarkResult::from_weight(Weight::MAX)))?; - let msg = Xcm(vec![ClearOrigin]); - if !T::XcmExecuteFilter::contains(&(origin_location, msg.clone())) { - return Err(BenchmarkError::Override(BenchmarkResult::from_weight(Weight::MAX))) - } - let versioned_msg = VersionedXcm::from(msg); - let encoded_versioned_msg = versioned_msg.encode().try_into().unwrap(); - }: _>(execute_origin, encoded_versioned_msg, Weight::MAX) - force_xcm_version { let loc = T::reachable_dest().ok_or( BenchmarkError::Override(BenchmarkResult::from_weight(Weight::MAX)), diff --git a/polkadot/xcm/pallet-xcm/src/lib.rs b/polkadot/xcm/pallet-xcm/src/lib.rs index cf22b86cf82c9e4552beee53be5786e57db0f896..37fc121ba2174c95f3a8ac82131d525ff8279f48 100644 --- a/polkadot/xcm/pallet-xcm/src/lib.rs +++ b/polkadot/xcm/pallet-xcm/src/lib.rs @@ -45,13 +45,13 @@ use sp_runtime::{ AccountIdConversion, BadOrigin, BlakeTwo256, BlockNumberProvider, Dispatchable, Hash, Saturating, Zero, }, - RuntimeDebug, + Either, RuntimeDebug, }; use sp_std::{boxed::Box, marker::PhantomData, prelude::*, result::Result, vec}; use xcm::{latest::QueryResponseInfo, prelude::*}; use xcm_builder::{ - ExecuteController, ExecuteControllerWeightInfo, MaxXcmEncodedSize, QueryController, - QueryControllerWeightInfo, SendController, SendControllerWeightInfo, + ExecuteController, ExecuteControllerWeightInfo, QueryController, QueryControllerWeightInfo, + SendController, SendControllerWeightInfo, }; use xcm_executor::{ traits::{ @@ -61,7 +61,7 @@ use xcm_executor::{ }, AssetsInHolding, }; -use xcm_fee_payment_runtime_api::Error as FeePaymentError; +use xcm_fee_payment_runtime_api::fees::Error as XcmPaymentApiError; #[cfg(any(feature = "try-runtime", test))] use sp_runtime::TryRuntimeError; @@ -87,8 +87,6 @@ pub trait WeightInfo { fn new_query() -> Weight; fn take_response() -> Weight; fn claim_assets() -> Weight; - fn execute_blob() -> Weight; - fn send_blob() -> Weight; } /// fallback implementation @@ -173,14 +171,6 @@ impl WeightInfo for TestWeightInfo { fn claim_assets() -> Weight { Weight::from_parts(100_000_000, 0) } - - fn execute_blob() -> Weight { - Weight::from_parts(100_000_000, 0) - } - - fn send_blob() -> Weight { - Weight::from_parts(100_000_000, 0) - } } #[frame_support::pallet] @@ -296,49 +286,76 @@ pub mod pallet { } impl ExecuteControllerWeightInfo for Pallet { - fn execute_blob() -> Weight { - T::WeightInfo::execute_blob() + fn execute() -> Weight { + T::WeightInfo::execute() } } impl ExecuteController, ::RuntimeCall> for Pallet { type WeightInfo = Self; - fn execute_blob( + fn execute( origin: OriginFor, - encoded_message: BoundedVec, + message: Box::RuntimeCall>>, max_weight: Weight, ) -> Result { - let origin_location = T::ExecuteXcmOrigin::ensure_origin(origin)?; - let message = - VersionedXcm::<::RuntimeCall>::decode(&mut &encoded_message[..]) - .map_err(|error| { - log::error!(target: "xcm::execute_blob", "Unable to decode XCM, error: {:?}", error); - Error::::UnableToDecode - })?; - Self::execute_base(origin_location, Box::new(message), max_weight) + 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() }); + 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) } } impl SendControllerWeightInfo for Pallet { - fn send_blob() -> Weight { - T::WeightInfo::send_blob() + fn send() -> Weight { + T::WeightInfo::send() } } impl SendController> for Pallet { type WeightInfo = Self; - fn send_blob( + fn send( origin: OriginFor, dest: Box, - encoded_message: BoundedVec, + message: Box>, ) -> Result { let origin_location = T::SendXcmOrigin::ensure_origin(origin)?; - let message = - VersionedXcm::<()>::decode(&mut &encoded_message[..]).map_err(|error| { - log::error!(target: "xcm::send_blob", "Unable to decode XCM, error: {:?}", error); - Error::::UnableToDecode - })?; - Self::send_base(origin_location, dest, Box::new(message)) + let interior: Junctions = + origin_location.clone().try_into().map_err(|_| Error::::InvalidOrigin)?; + let dest = Location::try_from(*dest).map_err(|()| Error::::BadVersion)?; + let message: Xcm<()> = (*message).try_into().map_err(|()| Error::::BadVersion)?; + + let message_id = Self::send_xcm(interior, dest.clone(), message.clone()) + .map_err(Error::::from)?; + let e = Event::Sent { origin: origin_location, destination: dest, message, message_id }; + Self::deposit_event(e); + Ok(message_id) } } @@ -535,21 +552,18 @@ pub mod pallet { LockNotFound, /// The unlock operation cannot succeed because there are still consumers of the lock. InUse, - /// Invalid non-concrete asset. - InvalidAssetNotConcrete, /// Invalid asset, reserve chain could not be determined for it. + #[codec(index = 21)] InvalidAssetUnknownReserve, /// Invalid asset, do not support remote asset reserves with different fees reserves. + #[codec(index = 22)] InvalidAssetUnsupportedReserve, /// Too many assets with different reserve locations have been attempted for transfer. + #[codec(index = 23)] TooManyReserves, /// Local XCM execution incomplete. + #[codec(index = 24)] LocalExecutionIncomplete, - /// Could not decode XCM. - UnableToDecode, - /// XCM encoded length is too large. - /// Returned when an XCM encoded length is larger than `MaxXcmEncodedSize`. - XcmTooLarge, } impl From for Error { @@ -565,7 +579,6 @@ pub mod pallet { impl From for Error { fn from(e: AssetTransferError) -> Self { match e { - AssetTransferError::NotConcrete => Error::::InvalidAssetNotConcrete, AssetTransferError::UnknownReserve => Error::::InvalidAssetUnknownReserve, } } @@ -751,6 +764,25 @@ pub mod pallet { #[pallet::storage] pub(super) type XcmExecutionSuspended = StorageValue<_, bool, ValueQuery>; + /// Whether or not incoming XCMs (both executed locally and received) should be recorded. + /// Only one XCM program will be recorded at a time. + /// This is meant to be used in runtime APIs, and it's advised it stays false + /// for all other use cases, so as to not degrade regular performance. + /// + /// Only relevant if this pallet is being used as the [`xcm_executor::traits::RecordXcm`] + /// implementation in the XCM executor configuration. + #[pallet::storage] + pub(crate) type ShouldRecordXcm = StorageValue<_, bool, ValueQuery>; + + /// If [`ShouldRecordXcm`] is set to true, then the last XCM program executed locally + /// will be stored here. + /// Runtime APIs can fetch the XCM that was executed by accessing this value. + /// + /// Only relevant if this pallet is being used as the [`xcm_executor::traits::RecordXcm`] + /// implementation in the XCM executor configuration. + #[pallet::storage] + pub(crate) type RecordedXcm = StorageValue<_, Xcm<()>>; + #[pallet::genesis_config] pub struct GenesisConfig { #[serde(skip)] @@ -887,72 +919,15 @@ pub mod pallet { } } - impl Pallet { - /// Underlying logic for both [`execute_blob`] and [`execute`]. - fn execute_base( - origin_location: Location, - message: Box::RuntimeCall>>, - max_weight: Weight, - ) -> Result { - log::trace!(target: "xcm::pallet_xcm::execute", "message {:?}, max_weight {:?}", message, max_weight); - let outcome = (|| { - 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(T::WeightInfo::execute()))?; - - Self::deposit_event(Event::Attempted { outcome: outcome.clone() }); - let weight_used = outcome.weight_used(); - outcome.ensure_complete().map_err(|error| { - log::error!(target: "xcm::pallet_xcm::execute", "XCM execution failed with error {:?}", error); - Error::::LocalExecutionIncomplete - .with_weight(weight_used.saturating_add(T::WeightInfo::execute())) - })?; - Ok(weight_used) - } - - /// Underlying logic for both [`send_blob`] and [`send`]. - fn send_base( - origin_location: Location, - dest: Box, - message: Box>, - ) -> Result { - let interior: Junctions = - origin_location.clone().try_into().map_err(|_| Error::::InvalidOrigin)?; - let dest = Location::try_from(*dest).map_err(|()| Error::::BadVersion)?; - let message: Xcm<()> = (*message).try_into().map_err(|()| Error::::BadVersion)?; - - let message_id = Self::send_xcm(interior, dest.clone(), message.clone()) - .map_err(Error::::from)?; - let e = Event::Sent { origin: origin_location, destination: dest, message, message_id }; - Self::deposit_event(e); - Ok(message_id) - } - } - #[pallet::call(weight(::WeightInfo))] impl Pallet { - /// WARNING: DEPRECATED. `send` will be removed after June 2024. Use `send_blob` instead. - #[allow(deprecated)] - #[deprecated(note = "`send` will be removed after June 2024. Use `send_blob` instead.")] #[pallet::call_index(0)] pub fn send( origin: OriginFor, dest: Box, message: Box>, ) -> DispatchResult { - let origin_location = T::SendXcmOrigin::ensure_origin(origin)?; - Self::send_base(origin_location, dest, message)?; + >::send(origin, dest, message)?; Ok(()) } @@ -1049,13 +1024,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. - /// - /// WARNING: DEPRECATED. `execute` will be removed after June 2024. Use `execute_blob` - /// instead. - #[allow(deprecated)] - #[deprecated( - note = "`execute` will be removed after June 2024. Use `execute_blob` instead." - )] #[pallet::call_index(3)] #[pallet::weight(max_weight.saturating_add(T::WeightInfo::execute()))] pub fn execute( @@ -1063,8 +1031,8 @@ pub mod pallet { message: Box::RuntimeCall>>, max_weight: Weight, ) -> DispatchResultWithPostInfo { - let origin_location = T::ExecuteXcmOrigin::ensure_origin(origin)?; - let weight_used = Self::execute_base(origin_location, message, max_weight)?; + let weight_used = + >::execute(origin, message, max_weight)?; Ok(Some(weight_used.saturating_add(T::WeightInfo::execute())).into()) } @@ -1308,7 +1276,7 @@ pub mod pallet { Self::do_transfer_assets( origin, dest, - beneficiary, + Either::Left(beneficiary), assets, assets_transfer_type, fee_asset_item, @@ -1359,47 +1327,6 @@ pub mod pallet { Ok(()) } - /// Execute an XCM from a local, signed, origin. - /// - /// An event is deposited indicating whether the message could be executed completely - /// or only partially. - /// - /// 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. - /// - /// The message is passed in encoded. It needs to be decodable as a [`VersionedXcm`]. - #[pallet::call_index(13)] - #[pallet::weight(max_weight.saturating_add(T::WeightInfo::execute_blob()))] - pub fn execute_blob( - origin: OriginFor, - encoded_message: BoundedVec, - max_weight: Weight, - ) -> DispatchResultWithPostInfo { - let weight_used = >::execute_blob( - origin, - encoded_message, - max_weight, - )?; - Ok(Some(weight_used.saturating_add(T::WeightInfo::execute_blob())).into()) - } - - /// Send an XCM from a local, signed, origin. - /// - /// The destination, `dest`, will receive this message with a `DescendOrigin` instruction - /// that makes the origin of the message be the origin on this system. - /// - /// The message is passed in encoded. It needs to be decodable as a [`VersionedXcm`]. - #[pallet::call_index(14)] - pub fn send_blob( - origin: OriginFor, - dest: Box, - encoded_message: BoundedVec, - ) -> DispatchResult { - >::send_blob(origin, dest, encoded_message)?; - Ok(()) - } - /// Transfer assets from the local chain to the destination chain using explicit transfer /// types for assets and fees. /// @@ -1418,50 +1345,60 @@ pub mod pallet { /// - `TransferType::Teleport`: burn local assets and forward XCM to `dest` chain to /// mint/teleport assets and deposit them to `beneficiary`. /// - /// Fee payment on the source, destination and all intermediary hops, is specified through - /// `fees_id`, but make sure enough of the specified `fees_id` asset is included in the - /// given list of `assets`. `fees_id` should be enough to pay for `weight_limit`. If more - /// weight is needed than `weight_limit`, then the operation will fail and the sent assets - /// may be at risk. + /// On the destination chain, as well as any intermediary hops, `BuyExecution` is used to + /// buy execution using transferred `assets` identified by `remote_fees_id`. + /// Make sure enough of the specified `remote_fees_id` asset is included in the given list + /// of `assets`. `remote_fees_id` should be enough to pay for `weight_limit`. If more weight + /// is needed than `weight_limit`, then the operation will fail and the sent assets may be + /// at risk. + /// + /// `remote_fees_id` may use different transfer type than rest of `assets` and can be + /// specified through `fees_transfer_type`. /// - /// `fees_id` may use different transfer type than rest of `assets` and can be specified - /// through `fees_transfer_type`. + /// The caller needs to specify what should happen to the transferred assets once they reach + /// the `dest` chain. This is done through the `custom_xcm_on_dest` parameter, which + /// contains the instructions to execute on `dest` as a final step. + /// This is usually as simple as: + /// `Xcm(vec![DepositAsset { assets: Wild(AllCounted(assets.len())), beneficiary }])`, + /// but could be something more exotic like sending the `assets` even further. /// /// - `origin`: Must be capable of withdrawing the `assets` and executing XCM. /// - `dest`: Destination context for the assets. Will typically be `[Parent, /// Parachain(..)]` to send from parachain to parachain, or `[Parachain(..)]` to send from /// relay to parachain, or `(parents: 2, (GlobalConsensus(..), ..))` to send from /// parachain across a bridge to another ecosystem destination. - /// - `beneficiary`: A beneficiary location for the assets in the context of `dest`. Will - /// generally be an `AccountId32` value. /// - `assets`: The assets to be withdrawn. This should include the assets used to pay the /// fee on the `dest` (and possibly reserve) chains. /// - `assets_transfer_type`: The XCM `TransferType` used to transfer the `assets`. - /// - `fees_id`: One of the included `assets` to be be used to pay fees. + /// - `remote_fees_id`: One of the included `assets` to be be used to pay fees. /// - `fees_transfer_type`: The XCM `TransferType` used to transfer the `fees` assets. + /// - `custom_xcm_on_dest`: The XCM to be executed on `dest` chain as the last step of the + /// transfer, which also determines what happens to the assets on the destination chain. /// - `weight_limit`: The remote-side weight limit, if any, for the XCM fee purchase. - #[pallet::call_index(15)] + #[pallet::call_index(13)] #[pallet::weight(T::WeightInfo::transfer_assets())] - pub fn transfer_assets_using_type( + pub fn transfer_assets_using_type_and_then( origin: OriginFor, dest: Box, - beneficiary: Box, assets: Box, assets_transfer_type: Box, - fees_id: Box, + remote_fees_id: Box, fees_transfer_type: Box, + custom_xcm_on_dest: Box>, weight_limit: WeightLimit, ) -> DispatchResult { let origin_location = T::ExecuteXcmOrigin::ensure_origin(origin)?; let dest: Location = (*dest).try_into().map_err(|()| Error::::BadVersion)?; - let beneficiary: Location = - (*beneficiary).try_into().map_err(|()| Error::::BadVersion)?; let assets: Assets = (*assets).try_into().map_err(|()| Error::::BadVersion)?; - let fees_id: AssetId = (*fees_id).try_into().map_err(|()| Error::::BadVersion)?; + let fees_id: AssetId = + (*remote_fees_id).try_into().map_err(|()| Error::::BadVersion)?; + let remote_xcm: Xcm<()> = + (*custom_xcm_on_dest).try_into().map_err(|()| Error::::BadVersion)?; log::debug!( - target: "xcm::pallet_xcm::transfer_assets_using_type", - "origin {:?}, dest {:?}, beneficiary {:?}, assets {:?} through {:?}, fees-id {:?} through {:?}", - origin_location, dest, beneficiary, assets, assets_transfer_type, fees_id, fees_transfer_type, + target: "xcm::pallet_xcm::transfer_assets_using_type_and_then", + "origin {origin_location:?}, dest {dest:?}, assets {assets:?} through {assets_transfer_type:?}, \ + remote_fees_id {fees_id:?} through {fees_transfer_type:?}, \ + custom_xcm_on_dest {remote_xcm:?}, weight-limit {weight_limit:?}", ); let assets = assets.into_inner(); @@ -1472,7 +1409,7 @@ pub mod pallet { Self::do_transfer_assets( origin_location, dest, - beneficiary, + Either::Right(remote_xcm), assets, *assets_transfer_type, fee_asset_index, @@ -1647,7 +1584,7 @@ impl Pallet { let (local_xcm, remote_xcm) = Self::build_xcm_transfer_type( origin.clone(), dest.clone(), - beneficiary, + Either::Left(beneficiary), assets, assets_transfer_type, FeesHandling::Batched { fees }, @@ -1689,7 +1626,7 @@ impl Pallet { let (local_xcm, remote_xcm) = Self::build_xcm_transfer_type( origin_location.clone(), dest.clone(), - beneficiary, + Either::Left(beneficiary), assets, TransferType::Teleport, FeesHandling::Batched { fees }, @@ -1701,7 +1638,7 @@ impl Pallet { fn do_transfer_assets( origin: Location, dest: Location, - beneficiary: Location, + beneficiary: Either>, mut assets: Vec, assets_transfer_type: TransferType, fee_asset_index: usize, @@ -1767,7 +1704,7 @@ impl Pallet { fn build_xcm_transfer_type( origin: Location, dest: Location, - beneficiary: Location, + beneficiary: Either>, assets: Vec, transfer_type: TransferType, fees: FeesHandling, @@ -1779,57 +1716,51 @@ impl Pallet { fees_handling {:?}, weight_limit: {:?}", origin, dest, beneficiary, assets, transfer_type, fees, weight_limit, ); - Ok(match transfer_type { - TransferType::LocalReserve => { - let (local, remote) = Self::local_reserve_transfer_programs( - origin.clone(), - dest.clone(), - beneficiary, - assets, - fees, - weight_limit, - )?; - (local, Some(remote)) - }, - TransferType::DestinationReserve => { - let (local, remote) = Self::destination_reserve_transfer_programs( - origin.clone(), - dest.clone(), - beneficiary, - assets, - fees, - weight_limit, - )?; - (local, Some(remote)) - }, + match transfer_type { + TransferType::LocalReserve => Self::local_reserve_transfer_programs( + origin.clone(), + dest.clone(), + beneficiary, + assets, + fees, + weight_limit, + ) + .map(|(local, remote)| (local, Some(remote))), + TransferType::DestinationReserve => Self::destination_reserve_transfer_programs( + origin.clone(), + dest.clone(), + beneficiary, + assets, + fees, + weight_limit, + ) + .map(|(local, remote)| (local, Some(remote))), TransferType::RemoteReserve(reserve) => { let fees = match fees { FeesHandling::Batched { fees } => fees, _ => return Err(Error::::InvalidAssetUnsupportedReserve.into()), }; - let local = Self::remote_reserve_transfer_program( + Self::remote_reserve_transfer_program( origin.clone(), reserve.try_into().map_err(|()| Error::::BadVersion)?, - dest.clone(), beneficiary, - assets, - fees, - weight_limit, - )?; - (local, None) - }, - TransferType::Teleport => { - let (local, remote) = Self::teleport_assets_program( - origin.clone(), dest.clone(), - beneficiary, assets, fees, weight_limit, - )?; - (local, Some(remote)) + ) + .map(|local| (local, None)) }, - }) + TransferType::Teleport => Self::teleport_assets_program( + origin.clone(), + dest.clone(), + beneficiary, + assets, + fees, + weight_limit, + ) + .map(|(local, remote)| (local, Some(remote))), + } } fn execute_xcm_transfer( @@ -1944,7 +1875,7 @@ impl Pallet { fn local_reserve_transfer_programs( origin: Location, dest: Location, - beneficiary: Location, + beneficiary: Either>, assets: Vec, fees: FeesHandling, weight_limit: WeightLimit, @@ -1977,10 +1908,16 @@ impl Pallet { ]); // handle fees Self::add_fees_to_xcm(dest, fees, weight_limit, &mut local_execute_xcm, &mut xcm_on_dest)?; - // deposit all remaining assets in holding to `beneficiary` location - xcm_on_dest - .inner_mut() - .push(DepositAsset { assets: Wild(AllCounted(max_assets)), beneficiary }); + + // Use custom XCM on remote chain, or just default to depositing everything to beneficiary. + let custom_remote_xcm = match beneficiary { + Either::Right(custom_xcm) => custom_xcm, + Either::Left(beneficiary) => { + // deposit all remaining assets in holding to `beneficiary` location + Xcm(vec![DepositAsset { assets: Wild(AllCounted(max_assets)), beneficiary }]) + }, + }; + xcm_on_dest.0.extend(custom_remote_xcm.into_iter()); Ok((local_execute_xcm, xcm_on_dest)) } @@ -2019,7 +1956,7 @@ impl Pallet { fn destination_reserve_transfer_programs( origin: Location, dest: Location, - beneficiary: Location, + beneficiary: Either>, assets: Vec, fees: FeesHandling, weight_limit: WeightLimit, @@ -2055,10 +1992,15 @@ impl Pallet { // handle fees Self::add_fees_to_xcm(dest, fees, weight_limit, &mut local_execute_xcm, &mut xcm_on_dest)?; - // deposit all remaining assets in holding to `beneficiary` location - xcm_on_dest - .inner_mut() - .push(DepositAsset { assets: Wild(AllCounted(max_assets)), beneficiary }); + // Use custom XCM on remote chain, or just default to depositing everything to beneficiary. + let custom_remote_xcm = match beneficiary { + Either::Right(custom_xcm) => custom_xcm, + Either::Left(beneficiary) => { + // deposit all remaining assets in holding to `beneficiary` location + Xcm(vec![DepositAsset { assets: Wild(AllCounted(max_assets)), beneficiary }]) + }, + }; + xcm_on_dest.0.extend(custom_remote_xcm.into_iter()); Ok((local_execute_xcm, xcm_on_dest)) } @@ -2067,8 +2009,8 @@ impl Pallet { fn remote_reserve_transfer_program( origin: Location, reserve: Location, + beneficiary: Either>, dest: Location, - beneficiary: Location, assets: Vec, fees: Asset, weight_limit: WeightLimit, @@ -2093,10 +2035,17 @@ impl Pallet { // identifies `dest` as seen by `reserve` let dest = dest.reanchored(&reserve, &context).map_err(|_| Error::::CannotReanchor)?; // 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 }, - ]); + let mut xcm_on_dest = + Xcm(vec![BuyExecution { fees: dest_fees, weight_limit: weight_limit.clone() }]); + // Use custom XCM on remote chain, or just default to depositing everything to beneficiary. + let custom_xcm_on_dest = match beneficiary { + Either::Right(custom_xcm) => custom_xcm, + Either::Left(beneficiary) => { + // deposit all remaining assets in holding to `beneficiary` location + Xcm(vec![DepositAsset { assets: Wild(AllCounted(max_assets)), beneficiary }]) + }, + }; + xcm_on_dest.0.extend(custom_xcm_on_dest.into_iter()); // xcm to be executed on reserve let xcm_on_reserve = Xcm(vec![ BuyExecution { fees: reserve_fees, weight_limit }, @@ -2168,7 +2117,7 @@ impl Pallet { fn teleport_assets_program( origin: Location, dest: Location, - beneficiary: Location, + beneficiary: Either>, assets: Vec, fees: FeesHandling, weight_limit: WeightLimit, @@ -2228,10 +2177,16 @@ impl Pallet { ]); // handle fees Self::add_fees_to_xcm(dest, fees, weight_limit, &mut local_execute_xcm, &mut xcm_on_dest)?; - // deposit all remaining assets in holding to `beneficiary` location - xcm_on_dest - .inner_mut() - .push(DepositAsset { assets: Wild(AllCounted(max_assets)), beneficiary }); + + // Use custom XCM on remote chain, or just default to depositing everything to beneficiary. + let custom_remote_xcm = match beneficiary { + Either::Right(custom_xcm) => custom_xcm, + Either::Left(beneficiary) => { + // deposit all remaining assets in holding to `beneficiary` location + Xcm(vec![DepositAsset { assets: Wild(AllCounted(max_assets)), beneficiary }]) + }, + }; + xcm_on_dest.0.extend(custom_remote_xcm.into_iter()); Ok((local_execute_xcm, xcm_on_dest)) } @@ -2477,35 +2432,37 @@ impl Pallet { AccountIdConversion::::into_account_truncating(&ID) } - pub fn query_xcm_weight(message: VersionedXcm<()>) -> Result { - let message = - Xcm::<()>::try_from(message).map_err(|_| FeePaymentError::VersionedConversionFailed)?; + pub fn query_xcm_weight(message: VersionedXcm<()>) -> Result { + let message = Xcm::<()>::try_from(message) + .map_err(|_| XcmPaymentApiError::VersionedConversionFailed)?; T::Weigher::weight(&mut message.into()).map_err(|()| { log::error!(target: "xcm::pallet_xcm::query_xcm_weight", "Error when querying XCM weight"); - FeePaymentError::WeightNotComputable + XcmPaymentApiError::WeightNotComputable }) } pub fn query_delivery_fees( destination: VersionedLocation, message: VersionedXcm<()>, - ) -> Result { + ) -> Result { let result_version = destination.identify_version().max(message.identify_version()); - let destination = - destination.try_into().map_err(|_| FeePaymentError::VersionedConversionFailed)?; + let destination = destination + .try_into() + .map_err(|_| XcmPaymentApiError::VersionedConversionFailed)?; - let message = message.try_into().map_err(|_| FeePaymentError::VersionedConversionFailed)?; + let message = + message.try_into().map_err(|_| XcmPaymentApiError::VersionedConversionFailed)?; let (_, fees) = validate_send::(destination, message).map_err(|error| { log::error!(target: "xcm::pallet_xcm::query_delivery_fees", "Error when querying delivery fees: {:?}", error); - FeePaymentError::Unroutable + XcmPaymentApiError::Unroutable })?; VersionedAssets::from(fees) .into_version(result_version) - .map_err(|_| FeePaymentError::VersionedConversionFailed) + .map_err(|_| XcmPaymentApiError::VersionedConversionFailed) } /// Create a new expectation of a query response with the querier being here. @@ -3169,6 +3126,24 @@ impl CheckSuspension for Pallet { } } +impl xcm_executor::traits::RecordXcm for Pallet { + fn should_record() -> bool { + ShouldRecordXcm::::get() + } + + fn set_record_xcm(enabled: bool) { + ShouldRecordXcm::::put(enabled); + } + + fn recorded_xcm() -> Option> { + RecordedXcm::::get() + } + + fn record(xcm: Xcm<()>) { + RecordedXcm::::put(xcm); + } +} + /// Ensure that the origin `o` represents an XCM (`Transact`) origin. /// /// Returns `Ok` with the location of the XCM sender or an `Err` otherwise. diff --git a/polkadot/xcm/pallet-xcm/src/mock.rs b/polkadot/xcm/pallet-xcm/src/mock.rs index 2cc228476ba8e18dace2fc950d7253cba61cd8a4..b3b7529217f5a4929ce7beedcc1ffa423227112a 100644 --- a/polkadot/xcm/pallet-xcm/src/mock.rs +++ b/polkadot/xcm/pallet-xcm/src/mock.rs @@ -33,10 +33,11 @@ use xcm::prelude::*; use xcm_builder::{ AccountId32Aliases, AllowKnownQueryResponses, AllowSubscriptionsFrom, AllowTopLevelPaidExecutionFrom, Case, ChildParachainAsNative, ChildParachainConvertsVia, - ChildSystemParachainAsSuperuser, DescribeAllTerminal, FixedRateOfFungible, FixedWeightBounds, - FrameTransactionalProcessor, FungibleAdapter, FungiblesAdapter, HashedDescription, IsConcrete, - MatchedConvertedConcreteId, NoChecking, SignedAccountId32AsNative, SignedToAccountId32, - SovereignSignedViaLocation, TakeWeightCredit, XcmFeeManagerFromComponents, XcmFeeToAccount, + ChildSystemParachainAsSuperuser, DescribeAllTerminal, EnsureDecodableXcm, FixedRateOfFungible, + FixedWeightBounds, FrameTransactionalProcessor, FungibleAdapter, FungiblesAdapter, + HashedDescription, IsConcrete, MatchedConvertedConcreteId, NoChecking, + SignedAccountId32AsNative, SignedToAccountId32, SovereignSignedViaLocation, TakeWeightCredit, + XcmFeeManagerFromComponents, XcmFeeToAccount, }; use xcm_executor::{ traits::{Identity, JustTry}, @@ -413,7 +414,7 @@ parameter_types! { )), }; pub const AnyNetwork: Option = None; - pub UniversalLocation: InteriorLocation = Here; + pub UniversalLocation: InteriorLocation = GlobalConsensus(ByGenesis([0; 32])).into(); pub UnitWeightCost: u64 = 1_000; pub CheckingAccount: AccountId = XcmPallet::check_account(); } @@ -488,7 +489,8 @@ pub type Barrier = ( AllowSubscriptionsFrom, ); -pub type XcmRouter = (TestPaidForPara3000SendXcm, TestSendXcmErrX8, TestSendXcm); +pub type XcmRouter = + EnsureDecodableXcm<(TestPaidForPara3000SendXcm, TestSendXcmErrX8, TestSendXcm)>; pub struct XcmConfig; impl xcm_executor::Config for XcmConfig { @@ -529,6 +531,7 @@ impl xcm_executor::Config for XcmConfig { type HrmpNewChannelOpenRequestHandler = (); type HrmpChannelAcceptedHandler = (); type HrmpChannelClosingHandler = (); + type XcmRecorder = XcmPallet; } pub type LocalOriginToLocation = SignedToAccountId32; diff --git a/polkadot/xcm/pallet-xcm/src/tests/assets_transfer.rs b/polkadot/xcm/pallet-xcm/src/tests/assets_transfer.rs index 7dc05c1cc70e69f7de32d26356eaacdf52d9debf..f42e220d693203f7fa6e1391676f36a84feb9be0 100644 --- a/polkadot/xcm/pallet-xcm/src/tests/assets_transfer.rs +++ b/polkadot/xcm/pallet-xcm/src/tests/assets_transfer.rs @@ -22,12 +22,12 @@ use crate::{ DispatchResult, OriginFor, }; use frame_support::{ - assert_ok, + assert_err, assert_ok, traits::{tokens::fungibles::Inspect, Currency}, weights::Weight, }; use polkadot_parachain_primitives::primitives::Id as ParaId; -use sp_runtime::{traits::AccountIdConversion, DispatchError, ModuleError}; +use sp_runtime::traits::AccountIdConversion; use xcm::prelude::*; use xcm_executor::traits::ConvertLocation; @@ -112,14 +112,8 @@ fn limited_teleport_filtered_assets_disallowed() { 0, Unlimited, ); - assert_eq!( - result, - Err(DispatchError::Module(ModuleError { - index: 4, - error: [2, 0, 0, 0], - message: Some("Filtered") - })) - ); + let expected_result = Err(crate::Error::::Filtered.into()); + assert_eq!(result, expected_result); }); } @@ -365,11 +359,7 @@ fn reserve_transfer_assets_with_local_asset_reserve_and_local_fee_reserve_works( /// Test `limited_teleport_assets` with local asset reserve and local fee reserve disallowed. #[test] fn teleport_assets_with_local_asset_reserve_and_local_fee_reserve_disallowed() { - let expected_result = Err(DispatchError::Module(ModuleError { - index: 4, - error: [2, 0, 0, 0], - message: Some("Filtered"), - })); + let expected_result = Err(crate::Error::::Filtered.into()); local_asset_reserve_and_local_fee_reserve_call( XcmPallet::limited_teleport_assets, expected_result, @@ -527,11 +517,7 @@ fn transfer_assets_with_destination_asset_reserve_and_local_fee_reserve_works() /// disallowed. #[test] fn reserve_transfer_assets_with_destination_asset_reserve_and_local_fee_reserve_disallowed() { - let expected_result = Err(DispatchError::Module(ModuleError { - index: 4, - error: [23, 0, 0, 0], - message: Some("TooManyReserves"), - })); + let expected_result = Err(crate::Error::::TooManyReserves.into()); destination_asset_reserve_and_local_fee_reserve_call( XcmPallet::limited_reserve_transfer_assets, expected_result, @@ -542,11 +528,7 @@ fn reserve_transfer_assets_with_destination_asset_reserve_and_local_fee_reserve_ /// disallowed. #[test] fn teleport_assets_with_destination_asset_reserve_and_local_fee_reserve_disallowed() { - let expected_result = Err(DispatchError::Module(ModuleError { - index: 4, - error: [2, 0, 0, 0], - message: Some("Filtered"), - })); + let expected_result = Err(crate::Error::::Filtered.into()); destination_asset_reserve_and_local_fee_reserve_call( XcmPallet::limited_teleport_assets, expected_result, @@ -633,11 +615,7 @@ fn remote_asset_reserve_and_local_fee_reserve_call_disallowed( /// Test `transfer_assets` with remote asset reserve and local fee reserve is disallowed. #[test] fn transfer_assets_with_remote_asset_reserve_and_local_fee_reserve_disallowed() { - let expected_result = Err(DispatchError::Module(ModuleError { - index: 4, - error: [22, 0, 0, 0], - message: Some("InvalidAssetUnsupportedReserve"), - })); + let expected_result = Err(crate::Error::::InvalidAssetUnsupportedReserve.into()); remote_asset_reserve_and_local_fee_reserve_call_disallowed( XcmPallet::transfer_assets, expected_result, @@ -648,11 +626,7 @@ fn transfer_assets_with_remote_asset_reserve_and_local_fee_reserve_disallowed() /// disallowed. #[test] fn reserve_transfer_assets_with_remote_asset_reserve_and_local_fee_reserve_disallowed() { - let expected_result = Err(DispatchError::Module(ModuleError { - index: 4, - error: [23, 0, 0, 0], - message: Some("TooManyReserves"), - })); + let expected_result = Err(crate::Error::::TooManyReserves.into()); remote_asset_reserve_and_local_fee_reserve_call_disallowed( XcmPallet::limited_reserve_transfer_assets, expected_result, @@ -662,11 +636,7 @@ fn reserve_transfer_assets_with_remote_asset_reserve_and_local_fee_reserve_disal /// Test `limited_teleport_assets` with remote asset reserve and local fee reserve is disallowed. #[test] fn teleport_assets_with_remote_asset_reserve_and_local_fee_reserve_disallowed() { - let expected_result = Err(DispatchError::Module(ModuleError { - index: 4, - error: [2, 0, 0, 0], - message: Some("Filtered"), - })); + let expected_result = Err(crate::Error::::Filtered.into()); remote_asset_reserve_and_local_fee_reserve_call_disallowed( XcmPallet::limited_teleport_assets, expected_result, @@ -745,7 +715,7 @@ fn local_asset_reserve_and_destination_fee_reserve_call( assert_eq!(result, expected_result); if expected_result.is_err() { // short-circuit here for tests where we expect failure - return + return; } let weight = BaseXcmWeight::get() * 3; @@ -821,11 +791,7 @@ fn transfer_assets_with_local_asset_reserve_and_destination_fee_reserve_works() /// disallowed. #[test] fn reserve_transfer_assets_with_local_asset_reserve_and_destination_fee_reserve_disallowed() { - let expected_result = Err(DispatchError::Module(ModuleError { - index: 4, - error: [23, 0, 0, 0], - message: Some("TooManyReserves"), - })); + let expected_result = Err(crate::Error::::TooManyReserves.into()); local_asset_reserve_and_destination_fee_reserve_call( XcmPallet::limited_reserve_transfer_assets, expected_result, @@ -835,11 +801,7 @@ fn reserve_transfer_assets_with_local_asset_reserve_and_destination_fee_reserve_ /// Test `limited_teleport_assets` with local asset reserve and destination fee reserve disallowed. #[test] fn teleport_assets_with_local_asset_reserve_and_destination_fee_reserve_disallowed() { - let expected_result = Err(DispatchError::Module(ModuleError { - index: 4, - error: [2, 0, 0, 0], - message: Some("Filtered"), - })); + let expected_result = Err(crate::Error::::Filtered.into()); local_asset_reserve_and_destination_fee_reserve_call( XcmPallet::limited_teleport_assets, expected_result, @@ -993,11 +955,7 @@ fn reserve_transfer_assets_with_destination_asset_reserve_and_destination_fee_re /// disallowed. #[test] fn teleport_assets_with_destination_asset_reserve_and_destination_fee_reserve_disallowed() { - let expected_result = Err(DispatchError::Module(ModuleError { - index: 4, - error: [2, 0, 0, 0], - message: Some("Filtered"), - })); + let expected_result = Err(crate::Error::::Filtered.into()); destination_asset_reserve_and_destination_fee_reserve_call( XcmPallet::limited_teleport_assets, expected_result, @@ -1102,11 +1060,7 @@ fn remote_asset_reserve_and_destination_fee_reserve_call_disallowed( /// Test `transfer_assets` with remote asset reserve and destination fee reserve is disallowed. #[test] fn transfer_assets_with_remote_asset_reserve_and_destination_fee_reserve_disallowed() { - let expected_result = Err(DispatchError::Module(ModuleError { - index: 4, - error: [22, 0, 0, 0], - message: Some("InvalidAssetUnsupportedReserve"), - })); + let expected_result = Err(crate::Error::::InvalidAssetUnsupportedReserve.into()); remote_asset_reserve_and_destination_fee_reserve_call_disallowed( XcmPallet::transfer_assets, expected_result, @@ -1117,11 +1071,7 @@ fn transfer_assets_with_remote_asset_reserve_and_destination_fee_reserve_disallo /// disallowed. #[test] fn reserve_transfer_assets_with_remote_asset_reserve_and_destination_fee_reserve_disallowed() { - let expected_result = Err(DispatchError::Module(ModuleError { - index: 4, - error: [23, 0, 0, 0], - message: Some("TooManyReserves"), - })); + let expected_result = Err(crate::Error::::TooManyReserves.into()); remote_asset_reserve_and_destination_fee_reserve_call_disallowed( XcmPallet::limited_reserve_transfer_assets, expected_result, @@ -1132,11 +1082,7 @@ fn reserve_transfer_assets_with_remote_asset_reserve_and_destination_fee_reserve /// disallowed. #[test] fn teleport_assets_with_remote_asset_reserve_and_destination_fee_reserve_disallowed() { - let expected_result = Err(DispatchError::Module(ModuleError { - index: 4, - error: [2, 0, 0, 0], - message: Some("Filtered"), - })); + let expected_result = Err(crate::Error::::Filtered.into()); remote_asset_reserve_and_destination_fee_reserve_call_disallowed( XcmPallet::limited_teleport_assets, expected_result, @@ -1222,11 +1168,7 @@ fn local_asset_reserve_and_remote_fee_reserve_call_disallowed( /// Test `transfer_assets` with local asset reserve and remote fee reserve is disallowed. #[test] fn transfer_assets_with_local_asset_reserve_and_remote_fee_reserve_disallowed() { - let expected_result = Err(DispatchError::Module(ModuleError { - index: 4, - error: [22, 0, 0, 0], - message: Some("InvalidAssetUnsupportedReserve"), - })); + let expected_result = Err(crate::Error::::InvalidAssetUnsupportedReserve.into()); local_asset_reserve_and_remote_fee_reserve_call_disallowed( XcmPallet::transfer_assets, expected_result, @@ -1237,11 +1179,7 @@ fn transfer_assets_with_local_asset_reserve_and_remote_fee_reserve_disallowed() /// disallowed. #[test] fn reserve_transfer_assets_with_local_asset_reserve_and_remote_fee_reserve_disallowed() { - let expected_result = Err(DispatchError::Module(ModuleError { - index: 4, - error: [23, 0, 0, 0], - message: Some("TooManyReserves"), - })); + let expected_result = Err(crate::Error::::TooManyReserves.into()); local_asset_reserve_and_remote_fee_reserve_call_disallowed( XcmPallet::limited_reserve_transfer_assets, expected_result, @@ -1251,11 +1189,7 @@ fn reserve_transfer_assets_with_local_asset_reserve_and_remote_fee_reserve_disal /// Test `limited_teleport_assets` with local asset reserve and remote fee reserve is disallowed. #[test] fn teleport_assets_with_local_asset_reserve_and_remote_fee_reserve_disallowed() { - let expected_result = Err(DispatchError::Module(ModuleError { - index: 4, - error: [2, 0, 0, 0], - message: Some("Filtered"), - })); + let expected_result = Err(crate::Error::::Filtered.into()); local_asset_reserve_and_remote_fee_reserve_call_disallowed( XcmPallet::limited_teleport_assets, expected_result, @@ -1366,11 +1300,7 @@ fn destination_asset_reserve_and_remote_fee_reserve_call_disallowed( /// Test `transfer_assets` with destination asset reserve and remote fee reserve is disallowed. #[test] fn transfer_assets_with_destination_asset_reserve_and_remote_fee_reserve_disallowed() { - let expected_result = Err(DispatchError::Module(ModuleError { - index: 4, - error: [22, 0, 0, 0], - message: Some("InvalidAssetUnsupportedReserve"), - })); + let expected_result = Err(crate::Error::::InvalidAssetUnsupportedReserve.into()); destination_asset_reserve_and_remote_fee_reserve_call_disallowed( XcmPallet::transfer_assets, expected_result, @@ -1381,11 +1311,7 @@ fn transfer_assets_with_destination_asset_reserve_and_remote_fee_reserve_disallo /// disallowed. #[test] fn reserve_transfer_assets_with_destination_asset_reserve_and_remote_fee_reserve_disallowed() { - let expected_result = Err(DispatchError::Module(ModuleError { - index: 4, - error: [23, 0, 0, 0], - message: Some("TooManyReserves"), - })); + let expected_result = Err(crate::Error::::TooManyReserves.into()); destination_asset_reserve_and_remote_fee_reserve_call_disallowed( XcmPallet::limited_reserve_transfer_assets, expected_result, @@ -1396,11 +1322,7 @@ fn reserve_transfer_assets_with_destination_asset_reserve_and_remote_fee_reserve /// disallowed. #[test] fn teleport_assets_with_destination_asset_reserve_and_remote_fee_reserve_disallowed() { - let expected_result = Err(DispatchError::Module(ModuleError { - index: 4, - error: [2, 0, 0, 0], - message: Some("Filtered"), - })); + let expected_result = Err(crate::Error::::Filtered.into()); destination_asset_reserve_and_remote_fee_reserve_call_disallowed( XcmPallet::limited_teleport_assets, expected_result, @@ -1485,7 +1407,7 @@ fn remote_asset_reserve_and_remote_fee_reserve_call( assert_eq!(result, expected_result); if expected_result.is_err() { // short-circuit here for tests where we expect failure - return + return; } assert!(matches!( @@ -1558,11 +1480,7 @@ fn reserve_transfer_assets_with_remote_asset_reserve_and_remote_fee_reserve_work /// disallowed. #[test] fn teleport_assets_with_remote_asset_reserve_and_remote_fee_reserve_disallowed() { - let expected_result = Err(DispatchError::Module(ModuleError { - index: 4, - error: [2, 0, 0, 0], - message: Some("Filtered"), - })); + let expected_result = Err(crate::Error::::Filtered.into()); remote_asset_reserve_and_remote_fee_reserve_call( XcmPallet::limited_teleport_assets, expected_result, @@ -1702,11 +1620,7 @@ fn transfer_assets_with_local_asset_reserve_and_teleported_fee_works() { /// Test `limited_reserve_transfer_assets` with local asset reserve and teleported fee disallowed. #[test] fn reserve_transfer_assets_with_local_asset_reserve_and_teleported_fee_disallowed() { - let expected_result = Err(DispatchError::Module(ModuleError { - index: 4, - error: [23, 0, 0, 0], - message: Some("TooManyReserves"), - })); + let expected_result = Err(crate::Error::::TooManyReserves.into()); local_asset_reserve_and_teleported_fee_call( XcmPallet::limited_reserve_transfer_assets, expected_result, @@ -1716,11 +1630,7 @@ fn reserve_transfer_assets_with_local_asset_reserve_and_teleported_fee_disallowe /// Test `limited_teleport_assets` with local asset reserve and teleported fee disallowed. #[test] fn teleport_assets_with_local_asset_reserve_and_teleported_fee_disallowed() { - let expected_result = Err(DispatchError::Module(ModuleError { - index: 4, - error: [2, 0, 0, 0], - message: Some("Filtered"), - })); + let expected_result = Err(crate::Error::::Filtered.into()); local_asset_reserve_and_teleported_fee_call( XcmPallet::limited_teleport_assets, expected_result, @@ -1802,7 +1712,7 @@ fn destination_asset_reserve_and_teleported_fee_call( assert_eq!(result, expected_result); if expected_result.is_err() { // short-circuit here for tests where we expect failure - return + return; } let weight = BaseXcmWeight::get() * 4; @@ -1891,11 +1801,7 @@ fn transfer_assets_with_destination_asset_reserve_and_teleported_fee_works() { /// disallowed. #[test] fn reserve_transfer_assets_with_destination_asset_reserve_and_teleported_fee_disallowed() { - let expected_result = Err(DispatchError::Module(ModuleError { - index: 4, - error: [23, 0, 0, 0], - message: Some("TooManyReserves"), - })); + let expected_result = Err(crate::Error::::TooManyReserves.into()); destination_asset_reserve_and_teleported_fee_call( XcmPallet::limited_reserve_transfer_assets, expected_result, @@ -1905,11 +1811,7 @@ fn reserve_transfer_assets_with_destination_asset_reserve_and_teleported_fee_dis /// Test `limited_teleport_assets` with destination asset reserve and teleported fee disallowed. #[test] fn teleport_assets_with_destination_asset_reserve_and_teleported_fee_disallowed() { - let expected_result = Err(DispatchError::Module(ModuleError { - index: 4, - error: [2, 0, 0, 0], - message: Some("Filtered"), - })); + let expected_result = Err(crate::Error::::Filtered.into()); destination_asset_reserve_and_teleported_fee_call( XcmPallet::limited_teleport_assets, expected_result, @@ -2013,11 +1915,7 @@ fn remote_asset_reserve_and_teleported_fee_reserve_call_disallowed( /// Test `transfer_assets` with remote asset reserve and teleported fee is disallowed. #[test] fn transfer_assets_with_remote_asset_reserve_and_teleported_fee_disallowed() { - let expected_result = Err(DispatchError::Module(ModuleError { - index: 4, - error: [22, 0, 0, 0], - message: Some("InvalidAssetUnsupportedReserve"), - })); + let expected_result = Err(crate::Error::::InvalidAssetUnsupportedReserve.into()); remote_asset_reserve_and_teleported_fee_reserve_call_disallowed( XcmPallet::transfer_assets, expected_result, @@ -2028,11 +1926,7 @@ fn transfer_assets_with_remote_asset_reserve_and_teleported_fee_disallowed() { /// disallowed. #[test] fn reserve_transfer_assets_with_remote_asset_reserve_and_teleported_fee_disallowed() { - let expected_result = Err(DispatchError::Module(ModuleError { - index: 4, - error: [23, 0, 0, 0], - message: Some("TooManyReserves"), - })); + let expected_result = Err(crate::Error::::TooManyReserves.into()); remote_asset_reserve_and_teleported_fee_reserve_call_disallowed( XcmPallet::limited_reserve_transfer_assets, expected_result, @@ -2042,11 +1936,7 @@ fn reserve_transfer_assets_with_remote_asset_reserve_and_teleported_fee_disallow /// Test `limited_teleport_assets` with remote asset reserve and teleported fee is disallowed. #[test] fn teleport_assets_with_remote_asset_reserve_and_teleported_fee_disallowed() { - let expected_result = Err(DispatchError::Module(ModuleError { - index: 4, - error: [2, 0, 0, 0], - message: Some("Filtered"), - })); + let expected_result = Err(crate::Error::::Filtered.into()); remote_asset_reserve_and_teleported_fee_reserve_call_disallowed( XcmPallet::limited_teleport_assets, expected_result, @@ -2088,14 +1978,7 @@ fn reserve_transfer_assets_with_teleportable_asset_disallowed() { fee_index as u32, Unlimited, ); - assert_eq!( - res, - Err(DispatchError::Module(ModuleError { - index: 4, - error: [2, 0, 0, 0], - message: Some("Filtered") - })) - ); + assert_err!(res, crate::Error::::Filtered); // Alice native asset is still same assert_eq!(Balances::free_balance(ALICE), INITIAL_BALANCE); // Alice USDT balance is still same @@ -2136,14 +2019,7 @@ fn transfer_assets_with_filtered_teleported_fee_disallowed() { fee_index as u32, Unlimited, ); - assert_eq!( - result, - Err(DispatchError::Module(ModuleError { - index: 4, - error: [2, 0, 0, 0], - message: Some("Filtered") - })) - ); + assert_err!(result, crate::Error::::Filtered); }); } @@ -2350,11 +2226,7 @@ fn transfer_assets_with_teleportable_asset_and_local_fee_reserve_works() { /// Test `limited_reserve_transfer_assets` with teleportable asset and local fee reserve disallowed. #[test] fn reserve_transfer_assets_with_teleportable_asset_and_local_fee_reserve_disallowed() { - let expected_result = Err(DispatchError::Module(ModuleError { - index: 4, - error: [2, 0, 0, 0], - message: Some("Filtered"), - })); + let expected_result = Err(crate::Error::::Filtered.into()); teleport_asset_using_local_fee_reserve_call( XcmPallet::limited_reserve_transfer_assets, expected_result, @@ -2364,11 +2236,7 @@ fn reserve_transfer_assets_with_teleportable_asset_and_local_fee_reserve_disallo /// Test `limited_teleport_assets` with teleportable asset and local fee reserve disallowed. #[test] fn teleport_assets_with_teleportable_asset_and_local_fee_reserve_disallowed() { - let expected_result = Err(DispatchError::Module(ModuleError { - index: 4, - error: [2, 0, 0, 0], - message: Some("Filtered"), - })); + let expected_result = Err(crate::Error::::Filtered.into()); teleport_asset_using_local_fee_reserve_call( XcmPallet::limited_teleport_assets, expected_result, @@ -2541,11 +2409,7 @@ fn transfer_teleported_assets_using_destination_reserve_fee_works() { /// disallowed. #[test] fn reserve_transfer_teleported_assets_using_destination_reserve_fee_disallowed() { - let expected_result = Err(DispatchError::Module(ModuleError { - index: 4, - error: [2, 0, 0, 0], - message: Some("Filtered"), - })); + let expected_result = Err(crate::Error::::Filtered.into()); teleported_asset_using_destination_reserve_fee_call( XcmPallet::limited_reserve_transfer_assets, expected_result, @@ -2555,11 +2419,7 @@ fn reserve_transfer_teleported_assets_using_destination_reserve_fee_disallowed() /// Test `limited_teleport_assets` with teleported asset reserve and destination fee disallowed. #[test] fn teleport_assets_using_destination_reserve_fee_disallowed() { - let expected_result = Err(DispatchError::Module(ModuleError { - index: 4, - error: [2, 0, 0, 0], - message: Some("Filtered"), - })); + let expected_result = Err(crate::Error::::Filtered.into()); teleported_asset_using_destination_reserve_fee_call( XcmPallet::limited_teleport_assets, expected_result, diff --git a/polkadot/xcm/pallet-xcm/src/tests/mod.rs b/polkadot/xcm/pallet-xcm/src/tests/mod.rs index 1147635081a41db78927f5f1765210e315a0c92a..02aeafd68e83dffd01a7630ce357a4e9cd78cdf1 100644 --- a/polkadot/xcm/pallet-xcm/src/tests/mod.rs +++ b/polkadot/xcm/pallet-xcm/src/tests/mod.rs @@ -20,10 +20,10 @@ 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, + RecordedXcm, ShouldRecordXcm, VersionDiscoveryQueue, VersionMigrationStage, VersionNotifiers, + VersionNotifyTargets, WeightInfo, }; -use codec::Encode; use frame_support::{ assert_err_ignore_postinfo, assert_noop, assert_ok, traits::{Currency, Hooks}, @@ -305,12 +305,11 @@ fn send_works() { ]); let versioned_dest = Box::new(RelayLocation::get().into()); - let versioned_message = VersionedXcm::from(message.clone()); - let encoded_versioned_message = versioned_message.encode().try_into().unwrap(); - assert_ok!(XcmPallet::send_blob( + let versioned_message = Box::new(VersionedXcm::from(message.clone())); + assert_ok!(XcmPallet::send( RuntimeOrigin::signed(ALICE), versioned_dest, - encoded_versioned_message + versioned_message )); let sent_message = Xcm(Some(DescendOrigin(sender.clone().try_into().unwrap())) .into_iter() @@ -342,16 +341,16 @@ fn send_fails_when_xcm_router_blocks() { ]; new_test_ext_with_balances(balances).execute_with(|| { let sender: Location = Junction::AccountId32 { network: None, id: ALICE.into() }.into(); - let message = Xcm::<()>(vec![ + let message = Xcm(vec![ ReserveAssetDeposited((Parent, SEND_AMOUNT).into()), buy_execution((Parent, SEND_AMOUNT)), DepositAsset { assets: AllCounted(1).into(), beneficiary: sender }, ]); assert_noop!( - XcmPallet::send_blob( + XcmPallet::send( RuntimeOrigin::signed(ALICE), Box::new(Location::ancestor(8).into()), - VersionedXcm::from(message.clone()).encode().try_into().unwrap(), + Box::new(VersionedXcm::from(message.clone())), ), crate::Error::::SendFailure ); @@ -372,16 +371,13 @@ fn execute_withdraw_to_deposit_works() { let weight = BaseXcmWeight::get() * 3; let dest: Location = Junction::AccountId32 { network: None, id: BOB.into() }.into(); assert_eq!(Balances::total_balance(&ALICE), INITIAL_BALANCE); - assert_ok!(XcmPallet::execute_blob( + assert_ok!(XcmPallet::execute( RuntimeOrigin::signed(ALICE), - VersionedXcm::from(Xcm::(vec![ + Box::new(VersionedXcm::from(Xcm(vec![ WithdrawAsset((Here, SEND_AMOUNT).into()), buy_execution((Here, SEND_AMOUNT)), DepositAsset { assets: AllCounted(1).into(), beneficiary: dest }, - ])) - .encode() - .try_into() - .unwrap(), + ]))), weight )); assert_eq!(Balances::total_balance(&ALICE), INITIAL_BALANCE - SEND_AMOUNT); @@ -403,21 +399,18 @@ fn trapped_assets_can_be_claimed() { let weight = BaseXcmWeight::get() * 6; let dest: Location = Junction::AccountId32 { network: None, id: BOB.into() }.into(); - assert_ok!(XcmPallet::execute_blob( + assert_ok!(XcmPallet::execute( RuntimeOrigin::signed(ALICE), - VersionedXcm::from(Xcm(vec![ + Box::new(VersionedXcm::from(Xcm(vec![ WithdrawAsset((Here, SEND_AMOUNT).into()), buy_execution((Here, SEND_AMOUNT)), // Don't propagated the error into the result. - SetErrorHandler(Xcm::(vec![ClearError])), + SetErrorHandler(Xcm(vec![ClearError])), // This will make an error. Trap(0), // This would succeed, but we never get to it. DepositAsset { assets: AllCounted(1).into(), beneficiary: dest.clone() }, - ])) - .encode() - .try_into() - .unwrap(), + ]))), weight )); let source: Location = Junction::AccountId32 { network: None, id: ALICE.into() }.into(); @@ -444,16 +437,13 @@ fn trapped_assets_can_be_claimed() { assert_eq!(trapped, expected); let weight = BaseXcmWeight::get() * 3; - assert_ok!(XcmPallet::execute_blob( + assert_ok!(XcmPallet::execute( RuntimeOrigin::signed(ALICE), - VersionedXcm::from(Xcm::(vec![ + 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.clone() }, - ])) - .encode() - .try_into() - .unwrap(), + ]))), weight )); @@ -463,16 +453,13 @@ fn trapped_assets_can_be_claimed() { // Can't claim twice. assert_err_ignore_postinfo!( - XcmPallet::execute_blob( + XcmPallet::execute( RuntimeOrigin::signed(ALICE), - VersionedXcm::from(Xcm::(vec![ + 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 }, - ])) - .encode() - .try_into() - .unwrap(), + ]))), weight ), Error::::LocalExecutionIncomplete @@ -489,9 +476,9 @@ fn claim_assets_works() { let trapping_program = Xcm::::builder_unsafe().withdraw_asset((Here, SEND_AMOUNT)).build(); // Even though assets are trapped, the extrinsic returns success. - assert_ok!(XcmPallet::execute_blob( + assert_ok!(XcmPallet::execute( RuntimeOrigin::signed(ALICE), - VersionedXcm::V4(trapping_program).encode().try_into().unwrap(), + Box::new(VersionedXcm::V4(trapping_program)), BaseXcmWeight::get() * 2, )); assert_eq!(Balances::total_balance(&ALICE), INITIAL_BALANCE - SEND_AMOUNT); @@ -544,9 +531,9 @@ fn incomplete_execute_reverts_side_effects() { assert_eq!(Balances::total_balance(&ALICE), INITIAL_BALANCE); let amount_to_send = INITIAL_BALANCE - ExistentialDeposit::get(); let assets: Assets = (Here, amount_to_send).into(); - let result = XcmPallet::execute_blob( + let result = XcmPallet::execute( RuntimeOrigin::signed(ALICE), - VersionedXcm::from(Xcm::(vec![ + Box::new(VersionedXcm::from(Xcm(vec![ // Withdraw + BuyExec + Deposit should work WithdrawAsset(assets.clone()), buy_execution(assets.inner()[0].clone()), @@ -554,10 +541,7 @@ fn incomplete_execute_reverts_side_effects() { // Withdrawing once more will fail because of InsufficientBalance, and we expect to // revert the effects of the above instructions as well WithdrawAsset(assets), - ])) - .encode() - .try_into() - .unwrap(), + ]))), weight, ); // all effects are reverted and balances unchanged for either sender or receiver @@ -569,15 +553,11 @@ fn incomplete_execute_reverts_side_effects() { Err(sp_runtime::DispatchErrorWithPostInfo { post_info: frame_support::dispatch::PostDispatchInfo { actual_weight: Some( - <::WeightInfo>::execute_blob() + weight + as ExecuteControllerWeightInfo>::execute() + weight ), pays_fee: frame_support::dispatch::Pays::Yes, }, - error: sp_runtime::DispatchError::Module(sp_runtime::ModuleError { - index: 4, - error: [24, 0, 0, 0,], - message: Some("LocalExecutionIncomplete") - }) + error: sp_runtime::DispatchError::from(Error::::LocalExecutionIncomplete) }) ); }); @@ -1265,3 +1245,35 @@ fn multistage_migration_works() { assert!(Pallet::::do_try_state().is_ok()); }) } + +#[test] +fn record_xcm_works() { + let balances = vec![(ALICE, INITIAL_BALANCE)]; + new_test_ext_with_balances(balances).execute_with(|| { + let message = Xcm::::builder() + .withdraw_asset((Here, SEND_AMOUNT)) + .buy_execution((Here, SEND_AMOUNT), Unlimited) + .deposit_asset(AllCounted(1), Junction::AccountId32 { network: None, id: BOB.into() }) + .build(); + // Test default values. + assert_eq!(ShouldRecordXcm::::get(), false); + assert_eq!(RecordedXcm::::get(), None); + + // By default the message won't be recorded. + assert_ok!(XcmPallet::execute( + RuntimeOrigin::signed(ALICE), + Box::new(VersionedXcm::from(message.clone())), + BaseXcmWeight::get() * 3, + )); + assert_eq!(RecordedXcm::::get(), None); + + // We explicitly set the record flag to true so we record the XCM. + ShouldRecordXcm::::put(true); + assert_ok!(XcmPallet::execute( + RuntimeOrigin::signed(ALICE), + Box::new(VersionedXcm::from(message.clone())), + BaseXcmWeight::get() * 3, + )); + assert_eq!(RecordedXcm::::get(), Some(message.into())); + }); +} diff --git a/polkadot/xcm/src/lib.rs b/polkadot/xcm/src/lib.rs index e836486e86e3068b82c3f3a5905836c7704e09f7..513dfe5501ba6c6ee8c233717c86b7f24f6eeb5f 100644 --- a/polkadot/xcm/src/lib.rs +++ b/polkadot/xcm/src/lib.rs @@ -25,7 +25,7 @@ extern crate alloc; use derivative::Derivative; -use parity_scale_codec::{Decode, Encode, Error as CodecError, Input, MaxEncodedLen}; +use parity_scale_codec::{Decode, DecodeLimit, Encode, Error as CodecError, Input, MaxEncodedLen}; use scale_info::TypeInfo; pub mod v2; @@ -48,9 +48,6 @@ mod tests; /// Maximum nesting level for XCM decoding. pub const MAX_XCM_DECODE_DEPTH: u32 = 8; -/// Maximum encoded size. -/// See `decoding_respects_limit` test for more reasoning behind this value. -pub const MAX_XCM_ENCODED_SIZE: u32 = 12402; /// A version of XCM. pub type Version = u32; @@ -456,6 +453,23 @@ impl IdentifyVersion for VersionedXcm { } } +impl VersionedXcm { + /// Checks that the XCM is decodable with `MAX_XCM_DECODE_DEPTH`. Consequently, it also checks + /// all decode implementations and limits, such as MAX_ITEMS_IN_ASSETS or + /// MAX_INSTRUCTIONS_TO_DECODE. + /// + /// Note that this uses the limit of the sender - not the receiver. It is a best effort. + pub fn validate_xcm_nesting(&self) -> Result<(), ()> { + self.using_encoded(|mut enc| { + Self::decode_all_with_depth_limit(MAX_XCM_DECODE_DEPTH, &mut enc).map(|_| ()) + }) + .map_err(|e| { + log::error!(target: "xcm::validate_xcm_nesting", "Decode error: {e:?} for xcm: {self:?}!"); + () + }) + } +} + impl From> for VersionedXcm { fn from(x: v2::Xcm) -> Self { VersionedXcm::V2(x) @@ -704,3 +718,77 @@ fn size_limits() { } assert!(!test_failed); } + +#[test] +fn validate_xcm_nesting_works() { + use crate::latest::{ + prelude::{GeneralIndex, ReserveAssetDeposited, SetAppendix}, + Assets, Xcm, MAX_INSTRUCTIONS_TO_DECODE, MAX_ITEMS_IN_ASSETS, + }; + + // closure generates assets of `count` + let assets = |count| { + let mut assets = Assets::new(); + for i in 0..count { + assets.push((GeneralIndex(i as u128), 100).into()); + } + assets + }; + + // closer generates `Xcm` with nested instructions of `depth` + let with_instr = |depth| { + let mut xcm = Xcm::<()>(vec![]); + for _ in 0..depth - 1 { + xcm = Xcm::<()>(vec![SetAppendix(xcm)]); + } + xcm + }; + + // `MAX_INSTRUCTIONS_TO_DECODE` check + assert!(VersionedXcm::<()>::from(Xcm(vec![ + ReserveAssetDeposited(assets(1)); + (MAX_INSTRUCTIONS_TO_DECODE - 1) as usize + ])) + .validate_xcm_nesting() + .is_ok()); + assert!(VersionedXcm::<()>::from(Xcm(vec![ + ReserveAssetDeposited(assets(1)); + MAX_INSTRUCTIONS_TO_DECODE as usize + ])) + .validate_xcm_nesting() + .is_ok()); + assert!(VersionedXcm::<()>::from(Xcm(vec![ + ReserveAssetDeposited(assets(1)); + (MAX_INSTRUCTIONS_TO_DECODE + 1) as usize + ])) + .validate_xcm_nesting() + .is_err()); + + // `MAX_XCM_DECODE_DEPTH` check + assert!(VersionedXcm::<()>::from(with_instr(MAX_XCM_DECODE_DEPTH - 1)) + .validate_xcm_nesting() + .is_ok()); + assert!(VersionedXcm::<()>::from(with_instr(MAX_XCM_DECODE_DEPTH)) + .validate_xcm_nesting() + .is_ok()); + assert!(VersionedXcm::<()>::from(with_instr(MAX_XCM_DECODE_DEPTH + 1)) + .validate_xcm_nesting() + .is_err()); + + // `MAX_ITEMS_IN_ASSETS` check + assert!(VersionedXcm::<()>::from(Xcm(vec![ReserveAssetDeposited(assets( + MAX_ITEMS_IN_ASSETS + ))])) + .validate_xcm_nesting() + .is_ok()); + assert!(VersionedXcm::<()>::from(Xcm(vec![ReserveAssetDeposited(assets( + MAX_ITEMS_IN_ASSETS - 1 + ))])) + .validate_xcm_nesting() + .is_ok()); + assert!(VersionedXcm::<()>::from(Xcm(vec![ReserveAssetDeposited(assets( + MAX_ITEMS_IN_ASSETS + 1 + ))])) + .validate_xcm_nesting() + .is_err()); +} diff --git a/polkadot/xcm/src/v3/junction.rs b/polkadot/xcm/src/v3/junction.rs index e9e51941b1ac0c50130ad5501c4b6f374656152a..32ce352c5c02b0a7a3dd31fa02854767cf483efa 100644 --- a/polkadot/xcm/src/v3/junction.rs +++ b/polkadot/xcm/src/v3/junction.rs @@ -26,7 +26,6 @@ use crate::{ VersionedLocation, }; use bounded_collections::{BoundedSlice, BoundedVec, ConstU32}; -use core::convert::{TryFrom, TryInto}; use parity_scale_codec::{self, Decode, Encode, MaxEncodedLen}; use scale_info::TypeInfo; use serde::{Deserialize, Serialize}; diff --git a/polkadot/xcm/src/v3/junctions.rs b/polkadot/xcm/src/v3/junctions.rs index 9748e81fa55f53c90c8a78419fce410ea1adb82d..7b014304fdaf7826861ad9e8ea469390bc0513b9 100644 --- a/polkadot/xcm/src/v3/junctions.rs +++ b/polkadot/xcm/src/v3/junctions.rs @@ -17,7 +17,7 @@ //! XCM `Junctions`/`InteriorMultiLocation` datatype. use super::{Junction, MultiLocation, NetworkId}; -use core::{convert::TryFrom, mem, result}; +use core::{mem, result}; use parity_scale_codec::{Decode, Encode, MaxEncodedLen}; use scale_info::TypeInfo; diff --git a/polkadot/xcm/src/v3/mod.rs b/polkadot/xcm/src/v3/mod.rs index d4e2da07a25ac9dbf4ca7177ed09f0abd26b46d3..e7c57f414eb786a50f3689a3d3706632bdc4f902 100644 --- a/polkadot/xcm/src/v3/mod.rs +++ b/polkadot/xcm/src/v3/mod.rs @@ -29,11 +29,7 @@ use super::{ use crate::DoubleEncoded; use alloc::{vec, vec::Vec}; use bounded_collections::{parameter_types, BoundedVec}; -use core::{ - convert::{TryFrom, TryInto}, - fmt::Debug, - result, -}; +use core::{fmt::Debug, result}; use derivative::Derivative; use parity_scale_codec::{ self, decode_vec_with_len, Compact, Decode, Encode, Error as CodecError, Input as CodecInput, diff --git a/polkadot/xcm/src/v3/multiasset.rs b/polkadot/xcm/src/v3/multiasset.rs index f9041ecd81bac1b383b65ea8920920ff95e14419..9a67b0e4986caf1a52eaa108e77f9394537d7553 100644 --- a/polkadot/xcm/src/v3/multiasset.rs +++ b/polkadot/xcm/src/v3/multiasset.rs @@ -42,10 +42,7 @@ use crate::{ }; use alloc::{vec, vec::Vec}; use bounded_collections::{BoundedVec, ConstU32}; -use core::{ - cmp::Ordering, - convert::{TryFrom, TryInto}, -}; +use core::cmp::Ordering; use parity_scale_codec::{self as codec, Decode, Encode, MaxEncodedLen}; use scale_info::TypeInfo; @@ -825,7 +822,9 @@ impl MultiAssets { /// Prepend a `MultiLocation` to any concrete asset items, giving it a new root location. pub fn prepend_with(&mut self, prefix: &MultiLocation) -> Result<(), ()> { - self.0.iter_mut().try_for_each(|i| i.prepend_with(prefix)) + self.0.iter_mut().try_for_each(|i| i.prepend_with(prefix))?; + self.0.sort(); + Ok(()) } /// Mutate the location of the asset identifier if concrete, giving it the same location @@ -1213,8 +1212,73 @@ mod tests { vec![asset_1.clone(), asset_2.clone(), asset_3.clone()].into(); assert_eq!(assets.clone(), vec![asset_1.clone(), asset_2.clone(), asset_3.clone()].into()); + // decoding respects limits and sorting + assert!(assets + .using_encoded(|mut enc| MultiAssets::decode(&mut enc).map(|_| ())) + .is_ok()); + assert!(assets.reanchor(&dest, reanchor_context).is_ok()); - assert_eq!(assets, vec![asset_2_reanchored, asset_3_reanchored, asset_1_reanchored].into()); + assert_eq!(assets.0, vec![asset_2_reanchored, asset_3_reanchored, asset_1_reanchored]); + + // decoding respects limits and sorting + assert!(assets + .using_encoded(|mut enc| MultiAssets::decode(&mut enc).map(|_| ())) + .is_ok()); + } + + #[test] + fn prepend_preserves_sorting() { + use super::*; + use alloc::vec; + + let prefix = MultiLocation::new(0, X1(Parachain(1000))); + + let asset_1: MultiAsset = + (MultiLocation::new(0, X2(PalletInstance(50), GeneralIndex(1))), 10).into(); + let mut asset_1_prepended = asset_1.clone(); + assert!(asset_1_prepended.prepend_with(&prefix).is_ok()); + // changes interior X2->X3 + assert_eq!( + asset_1_prepended, + (MultiLocation::new(0, X3(Parachain(1000), PalletInstance(50), GeneralIndex(1))), 10) + .into() + ); + + let asset_2: MultiAsset = + (MultiLocation::new(1, X2(PalletInstance(50), GeneralIndex(1))), 10).into(); + let mut asset_2_prepended = asset_2.clone(); + assert!(asset_2_prepended.prepend_with(&prefix).is_ok()); + // changes parent + assert_eq!( + asset_2_prepended, + (MultiLocation::new(0, X2(PalletInstance(50), GeneralIndex(1))), 10).into() + ); + + let asset_3: MultiAsset = + (MultiLocation::new(2, X2(PalletInstance(50), GeneralIndex(1))), 10).into(); + let mut asset_3_prepended = asset_3.clone(); + assert!(asset_3_prepended.prepend_with(&prefix).is_ok()); + // changes parent + assert_eq!( + asset_3_prepended, + (MultiLocation::new(1, X2(PalletInstance(50), GeneralIndex(1))), 10).into() + ); + + // `From` impl does sorting. + let mut assets: MultiAssets = vec![asset_1, asset_2, asset_3].into(); + // decoding respects limits and sorting + assert!(assets + .using_encoded(|mut enc| MultiAssets::decode(&mut enc).map(|_| ())) + .is_ok()); + + // let's do `prepend_with` + assert!(assets.prepend_with(&prefix).is_ok()); + assert_eq!(assets.0, vec![asset_2_prepended, asset_1_prepended, asset_3_prepended]); + + // decoding respects limits and sorting + assert!(assets + .using_encoded(|mut enc| MultiAssets::decode(&mut enc).map(|_| ())) + .is_ok()); } #[test] diff --git a/polkadot/xcm/src/v3/multilocation.rs b/polkadot/xcm/src/v3/multilocation.rs index 18fe01ec8fa7da6eb1db44ce961098c00a2ac13b..731e277b29d8897d46406a1c7a8927461bcf889b 100644 --- a/polkadot/xcm/src/v3/multilocation.rs +++ b/polkadot/xcm/src/v3/multilocation.rs @@ -20,10 +20,7 @@ use super::{Junction, Junctions}; use crate::{ v2::MultiLocation as OldMultiLocation, v4::Location as NewMultiLocation, VersionedLocation, }; -use core::{ - convert::{TryFrom, TryInto}, - result, -}; +use core::result; use parity_scale_codec::{Decode, Encode, MaxEncodedLen}; use scale_info::TypeInfo; @@ -766,7 +763,6 @@ mod tests { #[test] fn conversion_from_other_types_works() { use crate::v2; - use core::convert::TryInto; fn takes_multilocation>(_arg: Arg) {} diff --git a/polkadot/xcm/src/v4/asset.rs b/polkadot/xcm/src/v4/asset.rs index bdff0c272306aced0fbf5f2372a70d66ac37e841..6b6d200f32febca6ef5cb208bfed95d50724e58b 100644 --- a/polkadot/xcm/src/v4/asset.rs +++ b/polkadot/xcm/src/v4/asset.rs @@ -34,10 +34,7 @@ use crate::v3::{ }; use alloc::{vec, vec::Vec}; use bounded_collections::{BoundedVec, ConstU32}; -use core::{ - cmp::Ordering, - convert::{TryFrom, TryInto}, -}; +use core::cmp::Ordering; use parity_scale_codec::{self as codec, Decode, Encode, MaxEncodedLen}; use scale_info::TypeInfo; @@ -723,7 +720,9 @@ impl Assets { /// Prepend a `Location` to any concrete asset items, giving it a new root location. pub fn prepend_with(&mut self, prefix: &Location) -> Result<(), ()> { - self.0.iter_mut().try_for_each(|i| i.prepend_with(prefix)) + self.0.iter_mut().try_for_each(|i| i.prepend_with(prefix))?; + self.0.sort(); + Ok(()) } /// Return a reference to an item at a specific index or `None` if it doesn't exist. @@ -1035,8 +1034,61 @@ mod tests { let mut assets: Assets = vec![asset_1.clone(), asset_2.clone(), asset_3.clone()].into(); assert_eq!(assets.clone(), vec![asset_1.clone(), asset_2.clone(), asset_3.clone()].into()); + // decoding respects limits and sorting + assert!(assets.using_encoded(|mut enc| Assets::decode(&mut enc).map(|_| ())).is_ok()); + assert!(assets.reanchor(&dest, &reanchor_context).is_ok()); - assert_eq!(assets, vec![asset_2_reanchored, asset_3_reanchored, asset_1_reanchored].into()); + assert_eq!(assets.0, vec![asset_2_reanchored, asset_3_reanchored, asset_1_reanchored]); + + // decoding respects limits and sorting + assert!(assets.using_encoded(|mut enc| Assets::decode(&mut enc).map(|_| ())).is_ok()); + } + + #[test] + fn prepend_preserves_sorting() { + use super::*; + use alloc::vec; + + let prefix = Location::new(0, [Parachain(1000)]); + + let asset_1: Asset = (Location::new(0, [PalletInstance(50), GeneralIndex(1)]), 10).into(); + let mut asset_1_prepended = asset_1.clone(); + assert!(asset_1_prepended.prepend_with(&prefix).is_ok()); + // changes interior X2->X3 + assert_eq!( + asset_1_prepended, + (Location::new(0, [Parachain(1000), PalletInstance(50), GeneralIndex(1)]), 10).into() + ); + + let asset_2: Asset = (Location::new(1, [PalletInstance(50), GeneralIndex(1)]), 10).into(); + let mut asset_2_prepended = asset_2.clone(); + assert!(asset_2_prepended.prepend_with(&prefix).is_ok()); + // changes parent + assert_eq!( + asset_2_prepended, + (Location::new(0, [PalletInstance(50), GeneralIndex(1)]), 10).into() + ); + + let asset_3: Asset = (Location::new(2, [PalletInstance(50), GeneralIndex(1)]), 10).into(); + let mut asset_3_prepended = asset_3.clone(); + assert!(asset_3_prepended.prepend_with(&prefix).is_ok()); + // changes parent + assert_eq!( + asset_3_prepended, + (Location::new(1, [PalletInstance(50), GeneralIndex(1)]), 10).into() + ); + + // `From` impl does sorting. + let mut assets: Assets = vec![asset_1, asset_2, asset_3].into(); + // decoding respects limits and sorting + assert!(assets.using_encoded(|mut enc| Assets::decode(&mut enc).map(|_| ())).is_ok()); + + // let's do `prepend_with` + assert!(assets.prepend_with(&prefix).is_ok()); + assert_eq!(assets.0, vec![asset_2_prepended, asset_1_prepended, asset_3_prepended]); + + // decoding respects limits and sorting + assert!(assets.using_encoded(|mut enc| Assets::decode(&mut enc).map(|_| ())).is_ok()); } #[test] diff --git a/polkadot/xcm/src/v4/junction.rs b/polkadot/xcm/src/v4/junction.rs index b5d10484aa021aebfc2324bf251564c6e54a111e..3ae97de5e9b83336c10e0c20e865ddbebfef8b50 100644 --- a/polkadot/xcm/src/v4/junction.rs +++ b/polkadot/xcm/src/v4/junction.rs @@ -23,7 +23,6 @@ use crate::{ VersionedLocation, }; use bounded_collections::{BoundedSlice, BoundedVec, ConstU32}; -use core::convert::TryFrom; use parity_scale_codec::{self, Decode, Encode, MaxEncodedLen}; use scale_info::TypeInfo; use serde::{Deserialize, Serialize}; diff --git a/polkadot/xcm/src/v4/junctions.rs b/polkadot/xcm/src/v4/junctions.rs index 48712dd74c6cdd57411409fda689ce22378b8a75..6d1af59e13dcb179399379010d037e1c5a112c3c 100644 --- a/polkadot/xcm/src/v4/junctions.rs +++ b/polkadot/xcm/src/v4/junctions.rs @@ -18,7 +18,7 @@ use super::{Junction, Location, NetworkId}; use alloc::sync::Arc; -use core::{convert::TryFrom, mem, ops::Range, result}; +use core::{mem, ops::Range, result}; use parity_scale_codec::{Decode, Encode, MaxEncodedLen}; use scale_info::TypeInfo; diff --git a/polkadot/xcm/src/v4/location.rs b/polkadot/xcm/src/v4/location.rs index 9275bfdb94923cd38de4d3690aafe70f3ab4b952..cee76b6894076cc1ba9ddf960b2ad68a0693351e 100644 --- a/polkadot/xcm/src/v4/location.rs +++ b/polkadot/xcm/src/v4/location.rs @@ -18,10 +18,7 @@ use super::{traits::Reanchorable, Junction, Junctions}; use crate::{v3::MultiLocation as OldLocation, VersionedLocation}; -use core::{ - convert::{TryFrom, TryInto}, - result, -}; +use core::result; use parity_scale_codec::{Decode, Encode, MaxEncodedLen}; use scale_info::TypeInfo; @@ -723,7 +720,6 @@ mod tests { #[test] fn conversion_from_other_types_works() { use crate::v3; - use core::convert::TryInto; fn takes_location>(_arg: Arg) {} diff --git a/polkadot/xcm/src/v4/mod.rs b/polkadot/xcm/src/v4/mod.rs index 6635408282e4849861a62be955e52d2fc4dd1b87..77b6d915fcb5fa902e5168e46b38cdb677f98cbf 100644 --- a/polkadot/xcm/src/v4/mod.rs +++ b/polkadot/xcm/src/v4/mod.rs @@ -24,11 +24,7 @@ use super::v3::{ use crate::DoubleEncoded; use alloc::{vec, vec::Vec}; use bounded_collections::{parameter_types, BoundedVec}; -use core::{ - convert::{TryFrom, TryInto}, - fmt::Debug, - result, -}; +use core::{fmt::Debug, result}; use derivative::Derivative; use parity_scale_codec::{ self, decode_vec_with_len, Compact, Decode, Encode, Error as CodecError, Input as CodecInput, @@ -1488,21 +1484,7 @@ mod tests { let encoded = big_xcm.encode(); assert!(Xcm::<()>::decode(&mut &encoded[..]).is_err()); - let mut many_assets = Assets::new(); - for index in 0..MAX_ITEMS_IN_ASSETS { - many_assets.push((GeneralIndex(index as u128), 1u128).into()); - } - - let full_xcm_pass = - Xcm::<()>(vec![ - TransferAsset { assets: many_assets, beneficiary: Here.into() }; - MAX_INSTRUCTIONS_TO_DECODE as usize - ]); - let encoded = full_xcm_pass.encode(); - assert_eq!(encoded.len(), 12402); - assert!(Xcm::<()>::decode(&mut &encoded[..]).is_ok()); - - let nested_xcm_fail = Xcm::<()>(vec![ + let nested_xcm = Xcm::<()>(vec![ DepositReserveAsset { assets: All.into(), dest: Here.into(), @@ -1510,10 +1492,10 @@ mod tests { }; (MAX_INSTRUCTIONS_TO_DECODE / 2) as usize ]); - let encoded = nested_xcm_fail.encode(); + let encoded = nested_xcm.encode(); assert!(Xcm::<()>::decode(&mut &encoded[..]).is_err()); - let even_more_nested_xcm = Xcm::<()>(vec![SetAppendix(nested_xcm_fail); 64]); + let even_more_nested_xcm = Xcm::<()>(vec![SetAppendix(nested_xcm); 64]); let encoded = even_more_nested_xcm.encode(); assert_eq!(encoded.len(), 342530); // This should not decode since the limit is 100 diff --git a/polkadot/xcm/xcm-builder/Cargo.toml b/polkadot/xcm/xcm-builder/Cargo.toml index 997ca99fb12c831ea63d7dbb199f2c029dabb495..707e4aac7968a3032f717e802122903014d669ef 100644 --- a/polkadot/xcm/xcm-builder/Cargo.toml +++ b/polkadot/xcm/xcm-builder/Cargo.toml @@ -11,7 +11,7 @@ workspace = true [dependencies] impl-trait-for-tuples = "0.2.1" -parity-scale-codec = { version = "3.6.1", default-features = false, features = ["derive"] } +parity-scale-codec = { version = "3.6.12", default-features = false, features = ["derive"] } scale-info = { version = "2.11.1", default-features = false, features = ["derive"] } xcm = { package = "staging-xcm", path = "..", default-features = false } xcm-executor = { package = "staging-xcm-executor", path = "../xcm-executor", default-features = false } diff --git a/polkadot/xcm/xcm-builder/src/barriers.rs b/polkadot/xcm/xcm-builder/src/barriers.rs index b8923a4d5c6e88d9034536fa4dacf21c47e9108b..11e9122f9a121b1b08db7a5aec2fd423d63c98cf 100644 --- a/polkadot/xcm/xcm-builder/src/barriers.rs +++ b/polkadot/xcm/xcm-builder/src/barriers.rs @@ -322,6 +322,29 @@ impl> Contains for IsChildSystemParachain } } +/// Matches if the given location is a system-level sibling parachain. +pub struct IsSiblingSystemParachain(PhantomData<(ParaId, SelfParaId)>); +impl + Eq, SelfParaId: Get> Contains + for IsSiblingSystemParachain +{ + fn contains(l: &Location) -> bool { + matches!( + l.unpack(), + (1, [Junction::Parachain(id)]) + if SelfParaId::get() != ParaId::from(*id) && ParaId::from(*id).is_system(), + ) + } +} + +/// Matches if the given location contains only the specified amount of parents and no interior +/// junctions. +pub struct IsParentsOnly(PhantomData); +impl> Contains for IsParentsOnly { + fn contains(t: &Location) -> bool { + t.contains_parents_only(Count::get()) + } +} + /// Allows only messages if the generic `ResponseHandler` expects them via `expecting_response`. pub struct AllowKnownQueryResponses(PhantomData); impl ShouldExecute for AllowKnownQueryResponses { @@ -376,6 +399,41 @@ impl> ShouldExecute for AllowSubscriptionsFrom { } } +/// Allows execution for the Relay Chain origin (represented as `Location::parent()`) if it is just +/// a straight `HrmpNewChannelOpenRequest`, `HrmpChannelAccepted`, or `HrmpChannelClosing` +/// instruction. +/// +/// Note: This barrier fulfills safety recommendations for the mentioned instructions - see their +/// documentation. +pub struct AllowHrmpNotificationsFromRelayChain; +impl ShouldExecute for AllowHrmpNotificationsFromRelayChain { + fn should_execute( + origin: &Location, + instructions: &mut [Instruction], + _max_weight: Weight, + _properties: &mut Properties, + ) -> Result<(), ProcessMessageError> { + log::trace!( + target: "xcm::barriers", + "AllowHrmpNotificationsFromRelayChain origin: {:?}, instructions: {:?}, max_weight: {:?}, properties: {:?}", + origin, instructions, _max_weight, _properties, + ); + // accept only the Relay Chain + ensure!(matches!(origin.unpack(), (1, [])), ProcessMessageError::Unsupported); + // accept only HRMP notifications and nothing else + instructions + .matcher() + .assert_remaining_insts(1)? + .match_next_inst(|inst| match inst { + HrmpNewChannelOpenRequest { .. } | + HrmpChannelAccepted { .. } | + HrmpChannelClosing { .. } => Ok(()), + _ => Err(ProcessMessageError::BadFormat), + })?; + Ok(()) + } +} + /// Deny executing the XCM if it matches any of the Deny filter regardless of anything else. /// If it passes the Deny, and matches one of the Allow cases then it is let through. pub struct DenyThenTry(PhantomData, PhantomData) diff --git a/polkadot/xcm/xcm-builder/src/controller.rs b/polkadot/xcm/xcm-builder/src/controller.rs index 6bdde2a967de9195f62fa59544fc3c254b51796b..04b19eaa587009aa118e7c7d51ce69b159e4d948 100644 --- a/polkadot/xcm/xcm-builder/src/controller.rs +++ b/polkadot/xcm/xcm-builder/src/controller.rs @@ -21,7 +21,6 @@ use frame_support::{ dispatch::{DispatchErrorWithPostInfo, WithPostDispatchInfo}, pallet_prelude::DispatchError, - parameter_types, BoundedVec, }; use sp_std::boxed::Box; use xcm::prelude::*; @@ -42,12 +41,8 @@ impl Controller f /// Weight functions needed for [`ExecuteController`]. pub trait ExecuteControllerWeightInfo { - /// Weight for [`ExecuteController::execute_blob`] - fn execute_blob() -> Weight; -} - -parameter_types! { - pub const MaxXcmEncodedSize: u32 = xcm::MAX_XCM_ENCODED_SIZE; + /// Weight for [`ExecuteController::execute`] + fn execute() -> Weight; } /// Execute an XCM locally, for a given origin. @@ -66,19 +61,19 @@ pub trait ExecuteController { /// # Parameters /// /// - `origin`: the origin of the call. - /// - `msg`: the encoded XCM to be executed, should be decodable as a [`VersionedXcm`] + /// - `message`: the XCM program to be executed. /// - `max_weight`: the maximum weight that can be consumed by the execution. - fn execute_blob( + fn execute( origin: Origin, - message: BoundedVec, + message: Box>, max_weight: Weight, ) -> Result; } /// Weight functions needed for [`SendController`]. pub trait SendControllerWeightInfo { - /// Weight for [`SendController::send_blob`] - fn send_blob() -> Weight; + /// Weight for [`SendController::send`] + fn send() -> Weight; } /// Send an XCM from a given origin. @@ -98,11 +93,11 @@ pub trait SendController { /// /// - `origin`: the origin of the call. /// - `dest`: the destination of the message. - /// - `msg`: the encoded XCM to be sent, should be decodable as a [`VersionedXcm`] - fn send_blob( + /// - `msg`: the XCM to be sent. + fn send( origin: Origin, dest: Box, - message: BoundedVec, + message: Box>, ) -> Result; } @@ -142,35 +137,35 @@ pub trait QueryController: QueryHandler { impl ExecuteController for () { type WeightInfo = (); - fn execute_blob( + fn execute( _origin: Origin, - _message: BoundedVec, + _message: Box>, _max_weight: Weight, ) -> Result { - Err(DispatchError::Other("ExecuteController::execute_blob not implemented") + Err(DispatchError::Other("ExecuteController::execute not implemented") .with_weight(Weight::zero())) } } impl ExecuteControllerWeightInfo for () { - fn execute_blob() -> Weight { + fn execute() -> Weight { Weight::zero() } } impl SendController for () { type WeightInfo = (); - fn send_blob( + fn send( _origin: Origin, _dest: Box, - _message: BoundedVec, + _message: Box>, ) -> Result { Ok(Default::default()) } } impl SendControllerWeightInfo for () { - fn send_blob() -> Weight { + fn send() -> Weight { Weight::zero() } } diff --git a/polkadot/xcm/xcm-builder/src/fungible_adapter.rs b/polkadot/xcm/xcm-builder/src/fungible_adapter.rs index 21c828922b333e85e9332d16c768aef0d34cbd9f..45a0e2bdca2862c2142f3ecae17ae19ac6ec1839 100644 --- a/polkadot/xcm/xcm-builder/src/fungible_adapter.rs +++ b/polkadot/xcm/xcm-builder/src/fungible_adapter.rs @@ -19,7 +19,11 @@ use super::MintLocation; use frame_support::traits::{ tokens::{ - fungible, Fortitude::Polite, Precision::Exact, Preservation::Preserve, Provenance::Minted, + fungible, + Fortitude::Polite, + Precision::Exact, + Preservation::{Expendable, Preserve}, + Provenance::Minted, }, Get, }; @@ -100,7 +104,7 @@ impl< } fn reduce_checked(checking_account: AccountId, amount: Fungible::Balance) { - let ok = Fungible::burn_from(&checking_account, amount, Exact, Polite).is_ok(); + let ok = Fungible::burn_from(&checking_account, amount, Expendable, Exact, Polite).is_ok(); debug_assert!(ok, "`can_reduce_checked` must have returned `true` immediately prior; qed"); } } @@ -210,7 +214,7 @@ impl< let amount = Matcher::matches_fungible(what).ok_or(MatchError::AssetNotHandled)?; let who = AccountIdConverter::convert_location(who) .ok_or(MatchError::AccountIdConversionFailed)?; - Fungible::burn_from(&who, amount, Exact, Polite) + Fungible::burn_from(&who, amount, Expendable, Exact, Polite) .map_err(|error| XcmError::FailedToTransactAsset(error.into()))?; Ok(what.clone().into()) } diff --git a/polkadot/xcm/xcm-builder/src/fungibles_adapter.rs b/polkadot/xcm/xcm-builder/src/fungibles_adapter.rs index b4c418ebf1c9cf7d9d26540e998f966665993585..88bbf01d9e1f8c35d2b884be6a0c5a43f24c1073 100644 --- a/polkadot/xcm/xcm-builder/src/fungibles_adapter.rs +++ b/polkadot/xcm/xcm-builder/src/fungibles_adapter.rs @@ -18,7 +18,11 @@ use frame_support::traits::{ tokens::{ - fungibles, Fortitude::Polite, Precision::Exact, Preservation::Preserve, Provenance::Minted, + fungibles, + Fortitude::Polite, + Precision::Exact, + Preservation::{Expendable, Preserve}, + Provenance::Minted, }, Contains, Get, }; @@ -176,7 +180,8 @@ impl< } fn reduce_checked(asset_id: Assets::AssetId, amount: Assets::Balance) { let checking_account = CheckingAccount::get(); - let ok = Assets::burn_from(asset_id, &checking_account, amount, Exact, Polite).is_ok(); + let ok = Assets::burn_from(asset_id, &checking_account, amount, Expendable, Exact, Polite) + .is_ok(); debug_assert!(ok, "`can_reduce_checked` must have returned `true` immediately prior; qed"); } } @@ -295,7 +300,7 @@ impl< let (asset_id, amount) = Matcher::matches_fungibles(what)?; let who = AccountIdConverter::convert_location(who) .ok_or(MatchError::AccountIdConversionFailed)?; - Assets::burn_from(asset_id, &who, amount, Exact, Polite) + Assets::burn_from(asset_id, &who, amount, Expendable, Exact, Polite) .map_err(|e| XcmError::FailedToTransactAsset(e.into()))?; Ok(what.clone().into()) } diff --git a/polkadot/xcm/xcm-builder/src/lib.rs b/polkadot/xcm/xcm-builder/src/lib.rs index c3400cc72b48e97cb2cdfd85a028b21b7c032963..cc06c298a418d56f6a70d58b5f24bf8ccb14db5d 100644 --- a/polkadot/xcm/xcm-builder/src/lib.rs +++ b/polkadot/xcm/xcm-builder/src/lib.rs @@ -35,15 +35,16 @@ pub use asset_conversion::{ mod barriers; pub use barriers::{ - AllowExplicitUnpaidExecutionFrom, AllowKnownQueryResponses, AllowSubscriptionsFrom, - AllowTopLevelPaidExecutionFrom, AllowUnpaidExecutionFrom, DenyReserveTransferToRelayChain, - DenyThenTry, IsChildSystemParachain, RespectSuspension, TakeWeightCredit, TrailingSetTopicAsId, - WithComputedOrigin, + AllowExplicitUnpaidExecutionFrom, AllowHrmpNotificationsFromRelayChain, + AllowKnownQueryResponses, AllowSubscriptionsFrom, AllowTopLevelPaidExecutionFrom, + AllowUnpaidExecutionFrom, DenyReserveTransferToRelayChain, DenyThenTry, IsChildSystemParachain, + IsParentsOnly, IsSiblingSystemParachain, RespectSuspension, TakeWeightCredit, + TrailingSetTopicAsId, WithComputedOrigin, }; mod controller; pub use controller::{ - Controller, ExecuteController, ExecuteControllerWeightInfo, MaxXcmEncodedSize, QueryController, + Controller, ExecuteController, ExecuteControllerWeightInfo, QueryController, QueryControllerWeightInfo, QueryHandler, SendController, SendControllerWeightInfo, }; @@ -119,7 +120,9 @@ mod process_xcm_message; pub use process_xcm_message::ProcessXcmMessage; mod routing; -pub use routing::{EnsureDelivery, WithTopicSource, WithUniqueTopic}; +pub use routing::{ + EnsureDecodableXcm, EnsureDelivery, InspectMessageQueues, WithTopicSource, WithUniqueTopic, +}; mod transactional; pub use transactional::FrameTransactionalProcessor; diff --git a/polkadot/xcm/xcm-builder/src/process_xcm_message.rs b/polkadot/xcm/xcm-builder/src/process_xcm_message.rs index bcf91d8e68c3389377c84ea85e23ec9835006186..7760274f6e2451f1b5f695884086a31cd36f3209 100644 --- a/polkadot/xcm/xcm-builder/src/process_xcm_message.rs +++ b/polkadot/xcm/xcm-builder/src/process_xcm_message.rs @@ -102,7 +102,12 @@ impl< target: LOG_TARGET, "XCM message execution error: {error:?}", ); - (required, Err(ProcessMessageError::Unsupported)) + let error = match error { + xcm::latest::Error::ExceedsStackLimit => ProcessMessageError::StackLimitReached, + _ => ProcessMessageError::Unsupported, + }; + + (required, Err(error)) }, }; meter.consume(consumed); @@ -148,6 +153,45 @@ mod tests { } } + #[test] + fn process_message_exceeds_limits_fails() { + struct MockedExecutor; + impl ExecuteXcm<()> for MockedExecutor { + type Prepared = xcm_executor::WeighedMessage<()>; + fn prepare( + message: xcm::latest::Xcm<()>, + ) -> core::result::Result> { + Ok(xcm_executor::WeighedMessage::new(Weight::zero(), message)) + } + fn execute( + _: impl Into, + _: Self::Prepared, + _: &mut XcmHash, + _: Weight, + ) -> Outcome { + Outcome::Error { error: xcm::latest::Error::ExceedsStackLimit } + } + fn charge_fees(_location: impl Into, _fees: Assets) -> xcm::latest::Result { + unreachable!() + } + } + + type Processor = ProcessXcmMessage; + + let xcm = VersionedXcm::V4(xcm::latest::Xcm::<()>(vec![ + xcm::latest::Instruction::<()>::ClearOrigin, + ])); + assert_err!( + Processor::process_message( + &xcm.encode(), + ORIGIN, + &mut WeightMeter::new(), + &mut [0; 32] + ), + ProcessMessageError::StackLimitReached, + ); + } + #[test] fn process_message_overweight_fails() { for msg in [v3_xcm(true), v3_xcm(false), v3_xcm(false), v2_xcm(false)] { diff --git a/polkadot/xcm/xcm-builder/src/routing.rs b/polkadot/xcm/xcm-builder/src/routing.rs index 529ef80c15ff11d3c0d2629aeb4fa9506cb37a28..5c284aaf1475fce0fba7e5cfa042428ceff8268d 100644 --- a/polkadot/xcm/xcm-builder/src/routing.rs +++ b/polkadot/xcm/xcm-builder/src/routing.rs @@ -18,7 +18,7 @@ use frame_system::unique; use parity_scale_codec::Encode; -use sp_std::{marker::PhantomData, result::Result}; +use sp_std::{marker::PhantomData, result::Result, vec::Vec}; use xcm::prelude::*; use xcm_executor::{traits::FeeReason, FeesMode}; @@ -60,6 +60,11 @@ impl SendXcm for WithUniqueTopic { Ok(unique_id) } } +impl InspectMessageQueues for WithUniqueTopic { + fn get_messages() -> Vec<(VersionedLocation, Vec>)> { + Inner::get_messages() + } +} pub trait SourceTopic { fn source_topic(entropy: impl Encode) -> XcmHash; @@ -139,3 +144,57 @@ impl EnsureDelivery for Tuple { (None, None) } } + +/// Inspects messages in queues. +/// Meant to be used in runtime APIs, not in runtimes. +pub trait InspectMessageQueues { + /// Get queued messages and their destinations. + fn get_messages() -> Vec<(VersionedLocation, Vec>)>; +} + +#[impl_trait_for_tuples::impl_for_tuples(30)] +impl InspectMessageQueues for Tuple { + fn get_messages() -> Vec<(VersionedLocation, Vec>)> { + let mut messages = Vec::new(); + + for_tuples!( #( + messages.append(&mut Tuple::get_messages()); + )* ); + + messages + } +} + +/// A wrapper router that attempts to *encode* and *decode* passed XCM `message` to ensure that the +/// receiving side will be able to decode, at least with the same XCM version. +/// +/// This is designed to be at the top-level of any routers which do the real delivery. While other +/// routers can manipulate the `message`, we cannot access the final XCM due to the generic +/// `Inner::Ticket`. Therefore, this router aims to validate at least the passed `message`. +/// +/// NOTE: For use in mock runtimes which don't have the DMP/UMP/HRMP XCM validations. +pub struct EnsureDecodableXcm(sp_std::marker::PhantomData); +impl SendXcm for EnsureDecodableXcm { + type Ticket = Inner::Ticket; + + fn validate( + destination: &mut Option, + message: &mut Option>, + ) -> SendResult { + if let Some(msg) = message { + let versioned_xcm = VersionedXcm::<()>::from(msg.clone()); + if versioned_xcm.validate_xcm_nesting().is_err() { + log::error!( + target: "xcm::validate_xcm_nesting", + "EnsureDecodableXcm validate_xcm_nesting error for \nversioned_xcm: {versioned_xcm:?}\nbased on xcm: {msg:?}" + ); + return Err(SendError::Transport("EnsureDecodableXcm validate_xcm_nesting error")) + } + } + Inner::validate(destination, message) + } + + fn deliver(ticket: Self::Ticket) -> Result { + Inner::deliver(ticket) + } +} diff --git a/polkadot/xcm/xcm-builder/src/tests/barriers.rs b/polkadot/xcm/xcm-builder/src/tests/barriers.rs index 6516263f57a0936b45171ca262f4001b4315ee95..665b5febc61fec2d549cf707af55e4ba872d21e2 100644 --- a/polkadot/xcm/xcm-builder/src/tests/barriers.rs +++ b/polkadot/xcm/xcm-builder/src/tests/barriers.rs @@ -315,56 +315,150 @@ fn allow_subscriptions_from_should_work() { // allow only parent AllowSubsFrom::set(vec![Location::parent()]); - let valid_xcm_1 = Xcm::(vec![SubscribeVersion { - query_id: 42, - max_response_weight: Weight::from_parts(5000, 5000), - }]); - let valid_xcm_2 = Xcm::(vec![UnsubscribeVersion]); - let invalid_xcm_1 = Xcm::(vec![ - SetAppendix(Xcm(vec![])), - SubscribeVersion { query_id: 42, max_response_weight: Weight::from_parts(5000, 5000) }, - ]); - let invalid_xcm_2 = Xcm::(vec![ - SubscribeVersion { query_id: 42, max_response_weight: Weight::from_parts(5000, 5000) }, - SetTopic([0; 32]), - ]); + // closure for (xcm, origin) testing with `AllowSubscriptionsFrom` + let assert_should_execute = |mut xcm: Vec>, origin, expected_result| { + assert_eq!( + AllowSubscriptionsFrom::>::should_execute( + &origin, + &mut xcm, + Weight::from_parts(10, 10), + &mut props(Weight::zero()), + ), + expected_result + ); + }; + + // invalid origin + assert_should_execute( + vec![SubscribeVersion { + query_id: Default::default(), + max_response_weight: Default::default(), + }], + Parachain(1).into_location(), + Err(ProcessMessageError::Unsupported), + ); + assert_should_execute( + vec![UnsubscribeVersion], + Parachain(1).into_location(), + Err(ProcessMessageError::Unsupported), + ); - let test_data = vec![ - ( - valid_xcm_1.clone(), - Parachain(1).into_location(), - // not allowed origin - Err(ProcessMessageError::Unsupported), - ), - (valid_xcm_1, Location::parent(), Ok(())), - ( - valid_xcm_2.clone(), - Parachain(1).into_location(), - // not allowed origin - Err(ProcessMessageError::Unsupported), - ), - (valid_xcm_2, Location::parent(), Ok(())), - ( - invalid_xcm_1, - Location::parent(), - // invalid XCM - Err(ProcessMessageError::BadFormat), - ), - ( - invalid_xcm_2, - Location::parent(), - // invalid XCM - Err(ProcessMessageError::BadFormat), - ), - ]; - - for (mut message, origin, expected_result) in test_data { - let r = AllowSubscriptionsFrom::>::should_execute( - &origin, - message.inner_mut(), - Weight::from_parts(10, 10), - &mut props(Weight::zero()), + // invalid XCM (unexpected instruction before) + assert_should_execute( + vec![ + SetAppendix(Xcm(vec![])), + SubscribeVersion { + query_id: Default::default(), + max_response_weight: Default::default(), + }, + ], + Location::parent(), + Err(ProcessMessageError::BadFormat), + ); + assert_should_execute( + vec![SetAppendix(Xcm(vec![])), UnsubscribeVersion], + Location::parent(), + Err(ProcessMessageError::BadFormat), + ); + // invalid XCM (unexpected instruction after) + assert_should_execute( + vec![ + SubscribeVersion { + query_id: Default::default(), + max_response_weight: Default::default(), + }, + SetTopic([0; 32]), + ], + Location::parent(), + Err(ProcessMessageError::BadFormat), + ); + assert_should_execute( + vec![UnsubscribeVersion, SetTopic([0; 32])], + Location::parent(), + Err(ProcessMessageError::BadFormat), + ); + // invalid XCM (unexpected instruction) + assert_should_execute( + vec![SetAppendix(Xcm(vec![]))], + Location::parent(), + Err(ProcessMessageError::BadFormat), + ); + + // ok + assert_should_execute( + vec![SubscribeVersion { + query_id: Default::default(), + max_response_weight: Default::default(), + }], + Location::parent(), + Ok(()), + ); + assert_should_execute(vec![UnsubscribeVersion], Location::parent(), Ok(())); +} + +#[test] +fn allow_hrmp_notifications_from_relay_chain_should_work() { + // closure for (xcm, origin) testing with `AllowHrmpNotificationsFromRelayChain` + let assert_should_execute = |mut xcm: Vec>, origin, expected_result| { + assert_eq!( + AllowHrmpNotificationsFromRelayChain::should_execute( + &origin, + &mut xcm, + Weight::from_parts(10, 10), + &mut props(Weight::zero()), + ), + expected_result ); - assert_eq!(r, expected_result, "Failed for origin: {origin:?} and message: {message:?}"); - } + }; + + // invalid origin + assert_should_execute( + vec![HrmpChannelAccepted { recipient: Default::default() }], + Location::new(1, [Parachain(1)]), + Err(ProcessMessageError::Unsupported), + ); + + // invalid XCM (unexpected instruction before) + assert_should_execute( + vec![SetAppendix(Xcm(vec![])), HrmpChannelAccepted { recipient: Default::default() }], + Location::parent(), + Err(ProcessMessageError::BadFormat), + ); + // invalid XCM (unexpected instruction after) + assert_should_execute( + vec![HrmpChannelAccepted { recipient: Default::default() }, SetTopic([0; 32])], + Location::parent(), + Err(ProcessMessageError::BadFormat), + ); + // invalid XCM (unexpected instruction) + assert_should_execute( + vec![SetAppendix(Xcm(vec![]))], + Location::parent(), + Err(ProcessMessageError::BadFormat), + ); + + // ok + assert_should_execute( + vec![HrmpChannelAccepted { recipient: Default::default() }], + Location::parent(), + Ok(()), + ); + assert_should_execute( + vec![HrmpNewChannelOpenRequest { + max_capacity: Default::default(), + sender: Default::default(), + max_message_size: Default::default(), + }], + Location::parent(), + Ok(()), + ); + assert_should_execute( + vec![HrmpChannelClosing { + recipient: Default::default(), + sender: Default::default(), + initiator: Default::default(), + }], + Location::parent(), + Ok(()), + ); } diff --git a/polkadot/xcm/xcm-builder/src/tests/mock.rs b/polkadot/xcm/xcm-builder/src/tests/mock.rs index 3d03ab054248d907c89fe0f7a9d2fbb21896ace2..f45650ec5404d14780a3bff3d9bbef0d72a57a25 100644 --- a/polkadot/xcm/xcm-builder/src/tests/mock.rs +++ b/polkadot/xcm/xcm-builder/src/tests/mock.rs @@ -19,6 +19,7 @@ use crate::{ barriers::{AllowSubscriptionsFrom, RespectSuspension, TrailingSetTopicAsId}, test_utils::*, + EnsureDecodableXcm, }; pub use crate::{ AliasForeignAccountId32, AllowExplicitUnpaidExecutionFrom, AllowKnownQueryResponses, @@ -165,8 +166,8 @@ pub fn set_exporter_override( pub fn clear_exporter_override() { EXPORTER_OVERRIDE.with(|x| x.replace(None)); } -pub struct TestMessageSender; -impl SendXcm for TestMessageSender { +pub struct TestMessageSenderImpl; +impl SendXcm for TestMessageSenderImpl { type Ticket = (Location, Xcm<()>, XcmHash); fn validate( dest: &mut Option, @@ -183,6 +184,8 @@ impl SendXcm for TestMessageSender { Ok(hash) } } +pub type TestMessageSender = EnsureDecodableXcm; + pub struct TestMessageExporter; impl ExportXcm for TestMessageExporter { type Ticket = (NetworkId, u32, InteriorLocation, InteriorLocation, Xcm<()>, XcmHash); @@ -745,6 +748,7 @@ impl Config for TestConfig { type HrmpNewChannelOpenRequestHandler = (); type HrmpChannelAcceptedHandler = (); type HrmpChannelClosingHandler = (); + type XcmRecorder = (); } pub fn fungible_multi_asset(location: Location, amount: u128) -> Asset { diff --git a/polkadot/xcm/xcm-builder/src/tests/mod.rs b/polkadot/xcm/xcm-builder/src/tests/mod.rs index 63d254a1067582d3359c6a7dc1b27102bd1e45e7..16ce3d2cf8ffef68d1f218fb1082cee8dc122b4b 100644 --- a/polkadot/xcm/xcm-builder/src/tests/mod.rs +++ b/polkadot/xcm/xcm-builder/src/tests/mod.rs @@ -15,7 +15,6 @@ // along with Polkadot. If not, see . use super::{test_utils::*, *}; -use core::convert::TryInto; use frame_support::{ assert_err, traits::{ConstU32, ContainsPair, ProcessMessageError}, diff --git a/polkadot/xcm/xcm-builder/src/tests/pay/mock.rs b/polkadot/xcm/xcm-builder/src/tests/pay/mock.rs index 019113a12b2fb127142c9e59d00ef0faca84b688..34b204b434d6e3e547a8b1f5ec48d787bb1fded5 100644 --- a/polkadot/xcm/xcm-builder/src/tests/pay/mock.rs +++ b/polkadot/xcm/xcm-builder/src/tests/pay/mock.rs @@ -221,6 +221,7 @@ impl xcm_executor::Config for XcmConfig { type HrmpNewChannelOpenRequestHandler = (); type HrmpChannelAcceptedHandler = (); type HrmpChannelClosingHandler = (); + type XcmRecorder = XcmPallet; } parameter_types! { diff --git a/polkadot/xcm/xcm-builder/src/universal_exports.rs b/polkadot/xcm/xcm-builder/src/universal_exports.rs index 6e031cdbc270d73c49fcd7960430473a9bb9c9d5..04ceb7e51688994b65701419020ffd5fd5bfdcd7 100644 --- a/polkadot/xcm/xcm-builder/src/universal_exports.rs +++ b/polkadot/xcm/xcm-builder/src/universal_exports.rs @@ -16,6 +16,7 @@ //! Traits and utilities to help with origin mutation and bridging. +use crate::InspectMessageQueues; use frame_support::{ensure, traits::Get}; use parity_scale_codec::{Decode, Encode}; use sp_std::{convert::TryInto, marker::PhantomData, prelude::*}; @@ -187,7 +188,7 @@ pub fn forward_id_for(original_id: &XcmHash) -> XcmHash { /// end with the `SetTopic` instruction. /// /// In the case that the message ends with a `SetTopic(T)` (as should be the case if the top-level -/// router is `EnsureUniqueTopic`), then the forwarding message (i.e. the one carrying the +/// router is `WithUniqueTopic`), then the forwarding message (i.e. the one carrying the /// export instruction *to* the bridge in local consensus) will also end with a `SetTopic` whose /// inner is `forward_id_for(T)`. If this is not the case then the onward message will not be given /// the `SetTopic` afterword. @@ -254,7 +255,7 @@ impl InspectMessageQueues + for SovereignPaidRemoteExporter +{ + fn get_messages() -> Vec<(VersionedLocation, Vec>)> { + Router::get_messages() + } +} + pub trait DispatchBlob { /// Takes an incoming blob from over some point-to-point link (usually from some sort of /// inter-consensus bridge) and then does what needs to be done with it. Usually this means diff --git a/polkadot/xcm/xcm-builder/tests/mock/mod.rs b/polkadot/xcm/xcm-builder/tests/mock/mod.rs index f3cf5ab264902df83a40948fa3ad28c40571cd3f..45bfba2355630e4e5b40d1bb9e00114c889811a1 100644 --- a/polkadot/xcm/xcm-builder/tests/mock/mod.rs +++ b/polkadot/xcm/xcm-builder/tests/mock/mod.rs @@ -35,9 +35,9 @@ use staging_xcm_builder as xcm_builder; use xcm_builder::{ AccountId32Aliases, AllowTopLevelPaidExecutionFrom, AllowUnpaidExecutionFrom, ChildParachainAsNative, ChildParachainConvertsVia, ChildSystemParachainAsSuperuser, - FixedRateOfFungible, FixedWeightBounds, FungibleAdapter, IsChildSystemParachain, IsConcrete, - MintLocation, RespectSuspension, SignedAccountId32AsNative, SignedToAccountId32, - SovereignSignedViaLocation, TakeWeightCredit, + EnsureDecodableXcm, FixedRateOfFungible, FixedWeightBounds, FungibleAdapter, + IsChildSystemParachain, IsConcrete, MintLocation, RespectSuspension, SignedAccountId32AsNative, + SignedToAccountId32, SovereignSignedViaLocation, TakeWeightCredit, }; pub type AccountId = AccountId32; @@ -68,6 +68,8 @@ impl SendXcm for TestSendXcm { } } +pub type TestXcmRouter = EnsureDecodableXcm; + // copied from kusama constants pub const UNITS: Balance = 1_000_000_000_000; pub const CENTS: Balance = UNITS / 30_000; @@ -137,7 +139,7 @@ impl configuration::Config for Runtime { parameter_types! { pub const KsmLocation: Location = Location::here(); pub const KusamaNetwork: NetworkId = NetworkId::Kusama; - pub UniversalLocation: InteriorLocation = Here; + pub UniversalLocation: InteriorLocation = KusamaNetwork::get().into(); pub CheckAccount: (AccountId, MintLocation) = (XcmPallet::check_account(), MintLocation::Local); } @@ -180,7 +182,7 @@ pub type TrustedTeleporters = (xcm_builder::Case,); pub struct XcmConfig; impl xcm_executor::Config for XcmConfig { type RuntimeCall = RuntimeCall; - type XcmSender = TestSendXcm; + type XcmSender = TestXcmRouter; type AssetTransactor = LocalAssetTransactor; type OriginConverter = LocalOriginConverter; type IsReserve = (); @@ -207,6 +209,7 @@ impl xcm_executor::Config for XcmConfig { type HrmpNewChannelOpenRequestHandler = (); type HrmpChannelAcceptedHandler = (); type HrmpChannelClosingHandler = (); + type XcmRecorder = XcmPallet; } pub type LocalOriginToLocation = SignedToAccountId32; @@ -215,7 +218,7 @@ impl pallet_xcm::Config for Runtime { type RuntimeEvent = RuntimeEvent; type UniversalLocation = UniversalLocation; type SendXcmOrigin = xcm_builder::EnsureXcmOrigin; - type XcmRouter = TestSendXcm; + type XcmRouter = TestXcmRouter; // Anyone can execute XCM messages locally... type ExecuteXcmOrigin = xcm_builder::EnsureXcmOrigin; type XcmExecuteFilter = Nothing; diff --git a/polkadot/xcm/xcm-executor/Cargo.toml b/polkadot/xcm/xcm-executor/Cargo.toml index aebc768bb906fd38d372d6d735a9e6bc0390ae9b..64b2d405b9068213d88582ec79ca2897d78dcc1f 100644 --- a/polkadot/xcm/xcm-executor/Cargo.toml +++ b/polkadot/xcm/xcm-executor/Cargo.toml @@ -12,7 +12,7 @@ workspace = true [dependencies] impl-trait-for-tuples = "0.2.2" environmental = { version = "1.1.4", default-features = false } -parity-scale-codec = { version = "3.6.1", default-features = false, features = ["derive"] } +parity-scale-codec = { version = "3.6.12", default-features = false, features = ["derive"] } scale-info = { version = "2.11.1", default-features = false, features = ["derive", "serde"] } xcm = { package = "staging-xcm", path = "..", default-features = false } sp-std = { path = "../../../substrate/primitives/std", default-features = false } diff --git a/polkadot/xcm/xcm-executor/integration-tests/Cargo.toml b/polkadot/xcm/xcm-executor/integration-tests/Cargo.toml index 9c9c53f0ee1ba497f044477ec857afb6774a1f05..37c2117e7b06fc62f33e71c3c57164caf26d4c9b 100644 --- a/polkadot/xcm/xcm-executor/integration-tests/Cargo.toml +++ b/polkadot/xcm/xcm-executor/integration-tests/Cargo.toml @@ -11,7 +11,7 @@ publish = false workspace = true [dependencies] -codec = { package = "parity-scale-codec", version = "3.6.1" } +codec = { package = "parity-scale-codec", version = "3.6.12" } frame-support = { path = "../../../../substrate/frame/support", default-features = false } frame-system = { path = "../../../../substrate/frame/system" } futures = "0.3.30" diff --git a/polkadot/xcm/xcm-executor/integration-tests/src/lib.rs b/polkadot/xcm/xcm-executor/integration-tests/src/lib.rs index 1d1ee40d092c6d251b200439971986b9e0d6abd7..279d7118f8cf90cd5b8666ada2c7a8fbc5d4c94a 100644 --- a/polkadot/xcm/xcm-executor/integration-tests/src/lib.rs +++ b/polkadot/xcm/xcm-executor/integration-tests/src/lib.rs @@ -14,7 +14,6 @@ // You should have received a copy of the GNU General Public License // along with Polkadot. If not, see . -#![cfg_attr(not(feature = "std"), no_std)] #![cfg(test)] use codec::Encode; diff --git a/polkadot/xcm/xcm-executor/src/config.rs b/polkadot/xcm/xcm-executor/src/config.rs index b296d32ca2adb6761f815aa74397211e3bc17d5f..63b113bc250fa34db10336f7575771bbdbf76b01 100644 --- a/polkadot/xcm/xcm-executor/src/config.rs +++ b/polkadot/xcm/xcm-executor/src/config.rs @@ -17,8 +17,8 @@ use crate::traits::{ AssetExchange, AssetLock, CallDispatcher, ClaimAssets, ConvertOrigin, DropAssets, ExportXcm, FeeManager, HandleHrmpChannelAccepted, HandleHrmpChannelClosing, - HandleHrmpNewChannelOpenRequest, OnResponse, ProcessTransaction, ShouldExecute, TransactAsset, - VersionChangeNotifier, WeightBounds, WeightTrader, + HandleHrmpNewChannelOpenRequest, OnResponse, ProcessTransaction, RecordXcm, ShouldExecute, + TransactAsset, VersionChangeNotifier, WeightBounds, WeightTrader, }; use frame_support::{ dispatch::{GetDispatchInfo, Parameter, PostDispatchInfo}, @@ -122,4 +122,6 @@ pub trait Config { type HrmpChannelAcceptedHandler: HandleHrmpChannelAccepted; /// Allows optional logic execution for the `HrmpChannelClosing` XCM notification. type HrmpChannelClosingHandler: HandleHrmpChannelClosing; + /// Allows recording the last executed XCM (used by dry-run runtime APIs). + type XcmRecorder: RecordXcm; } diff --git a/polkadot/xcm/xcm-executor/src/lib.rs b/polkadot/xcm/xcm-executor/src/lib.rs index e673a46c4ac683cfcdbb0e8197cebc96e35c33d7..e0b8a8a9c73e4aba1274993d23ac27a77c2a6c78 100644 --- a/polkadot/xcm/xcm-executor/src/lib.rs +++ b/polkadot/xcm/xcm-executor/src/lib.rs @@ -37,6 +37,8 @@ use traits::{ XcmAssetTransfers, }; +pub use traits::RecordXcm; + mod assets; pub use assets::AssetsInHolding; mod config; @@ -182,6 +184,13 @@ impl PreparedMessage for WeighedMessage { } } +#[cfg(any(test, feature = "std"))] +impl WeighedMessage { + pub fn new(weight: Weight, message: Xcm) -> Self { + Self(weight, message) + } +} + impl ExecuteXcm for XcmExecutor { type Prepared = WeighedMessage; fn prepare( @@ -204,6 +213,13 @@ impl ExecuteXcm for XcmExecutor. + +//! Trait for recording XCMs and a dummy implementation. + +use xcm::latest::Xcm; + +/// Trait for recording XCMs. +pub trait RecordXcm { + /// Whether or not we should record incoming XCMs. + fn should_record() -> bool; + /// Enable or disable recording. + fn set_record_xcm(enabled: bool); + /// Get recorded XCM. + /// Returns `None` if no message was sent, or if recording was off. + fn recorded_xcm() -> Option>; + /// Record `xcm`. + fn record(xcm: Xcm<()>); +} + +impl RecordXcm for () { + fn should_record() -> bool { + false + } + + fn set_record_xcm(_: bool) {} + + fn recorded_xcm() -> Option> { + None + } + + fn record(_: Xcm<()>) {} +} diff --git a/polkadot/xcm/xcm-fee-payment-runtime-api/Cargo.toml b/polkadot/xcm/xcm-fee-payment-runtime-api/Cargo.toml index 30c7c0bac14f7936d57ec5c86f94bc24ba17013f..6fa0236dfb41d5e2a4ec2749a402a8f73be60eb4 100644 --- a/polkadot/xcm/xcm-fee-payment-runtime-api/Cargo.toml +++ b/polkadot/xcm/xcm-fee-payment-runtime-api/Cargo.toml @@ -11,7 +11,7 @@ description = "XCM fee payment runtime API" targets = ["x86_64-unknown-linux-gnu"] [dependencies] -codec = { package = "parity-scale-codec", version = "3.6.1", default-features = false, features = [ +codec = { package = "parity-scale-codec", version = "3.6.12", default-features = false, features = [ "derive", ] } @@ -26,15 +26,46 @@ sp-weights = { path = "../../../substrate/primitives/weights", default-features xcm = { package = "staging-xcm", path = "../", default-features = false } frame-support = { path = "../../../substrate/frame/support", default-features = false } +[dev-dependencies] +frame-system = { path = "../../../substrate/frame/system", default-features = false } +pallet-xcm = { path = "../pallet-xcm", default-features = false } +xcm-builder = { package = "staging-xcm-builder", path = "../xcm-builder", default-features = false } +sp-io = { path = "../../../substrate/primitives/io", default-features = false } +pallet-balances = { path = "../../../substrate/frame/balances", default-features = false } +pallet-assets = { path = "../../../substrate/frame/assets", default-features = false } +xcm-executor = { package = "staging-xcm-executor", path = "../xcm-executor", default-features = false } +frame-executive = { path = "../../../substrate/frame/executive", default-features = false } +log = { workspace = true } +env_logger = "0.9.0" + [features] default = ["std"] std = [ "codec/std", + "frame-executive/std", "frame-support/std", + "frame-system/std", + "log/std", + "pallet-assets/std", + "pallet-balances/std", + "pallet-xcm/std", "scale-info/std", "sp-api/std", + "sp-io/std", "sp-runtime/std", "sp-std/std", "sp-weights/std", + "xcm-builder/std", + "xcm-executor/std", "xcm/std", ] +runtime-benchmarks = [ + "frame-support/runtime-benchmarks", + "frame-system/runtime-benchmarks", + "pallet-assets/runtime-benchmarks", + "pallet-balances/runtime-benchmarks", + "pallet-xcm/runtime-benchmarks", + "sp-runtime/runtime-benchmarks", + "xcm-builder/runtime-benchmarks", + "xcm-executor/runtime-benchmarks", +] diff --git a/polkadot/xcm/xcm-fee-payment-runtime-api/src/dry_run.rs b/polkadot/xcm/xcm-fee-payment-runtime-api/src/dry_run.rs new file mode 100644 index 0000000000000000000000000000000000000000..62a422d6efeb0928e4f279798382dd139d95ee0a --- /dev/null +++ b/polkadot/xcm/xcm-fee-payment-runtime-api/src/dry_run.rs @@ -0,0 +1,83 @@ +// Copyright (C) Parity Technologies (UK) Ltd. +// This file is part of Polkadot. + +// Substrate 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. + +// Substrate is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with Polkadot. If not, see . + +//! Runtime API definition for dry-running XCM-related extrinsics. +//! This API can be used to simulate XCMs and, for example, find the fees +//! that need to be paid. + +use codec::{Decode, Encode}; +use frame_support::pallet_prelude::{DispatchResult, TypeInfo}; +use sp_runtime::traits::Block as BlockT; +use sp_std::vec::Vec; +use xcm::prelude::*; + +/// Effects of dry-running an extrinsic. +#[derive(Encode, Decode, Debug, TypeInfo)] +pub struct ExtrinsicDryRunEffects { + /// The result of executing the extrinsic. + pub execution_result: DispatchResult, + /// The list of events fired by the extrinsic. + pub emitted_events: Vec, + /// The local XCM that was attempted to be executed, if any. + pub local_xcm: Option>, + /// The list of XCMs that were queued for sending. + pub forwarded_xcms: Vec<(VersionedLocation, Vec>)>, +} + +/// Effects of dry-running an XCM program. +#[derive(Encode, Decode, Debug, TypeInfo)] +pub struct XcmDryRunEffects { + /// The outcome of the XCM program execution. + pub execution_result: Outcome, + /// List of events fired by the XCM program execution. + pub emitted_events: Vec, + /// List of queued messages for sending. + pub forwarded_xcms: Vec<(VersionedLocation, Vec>)>, +} + +sp_api::decl_runtime_apis! { + /// API for dry-running extrinsics and XCM programs to get the programs that need to be passed to the fees API. + /// + /// All calls return a vector of tuples (location, xcm) where each "xcm" is executed in "location". + /// If there's local execution, the location will be "Here". + /// This vector can be used to calculate both execution and delivery fees. + /// + /// Extrinsics or XCMs might fail when executed, this doesn't mean the result of these calls will be an `Err`. + /// In those cases, there might still be a valid result, with the execution error inside it. + /// The only reasons why these calls might return an error are listed in the [`Error`] enum. + pub trait XcmDryRunApi { + /// Dry run extrinsic. + fn dry_run_extrinsic(extrinsic: ::Extrinsic) -> Result, Error>; + + /// Dry run XCM program + fn dry_run_xcm(origin_location: VersionedLocation, xcm: VersionedXcm) -> Result, Error>; + } +} + +#[derive(Copy, Clone, Encode, Decode, Eq, PartialEq, Debug, TypeInfo)] +pub enum Error { + /// An API call is unsupported. + #[codec(index = 0)] + Unimplemented, + + /// Converting a versioned data structure from one version to another failed. + #[codec(index = 1)] + VersionedConversionFailed, + + /// Extrinsic was invalid. + #[codec(index = 2)] + InvalidExtrinsic, +} diff --git a/polkadot/xcm/xcm-fee-payment-runtime-api/src/fees.rs b/polkadot/xcm/xcm-fee-payment-runtime-api/src/fees.rs new file mode 100644 index 0000000000000000000000000000000000000000..572d4edf533865e66299eba7bd0d22a890547603 --- /dev/null +++ b/polkadot/xcm/xcm-fee-payment-runtime-api/src/fees.rs @@ -0,0 +1,97 @@ +// Copyright (C) Parity Technologies (UK) Ltd. +// This file is part of Polkadot. + +// Substrate 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. + +// Substrate is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with Polkadot. If not, see . + +//! Runtime API definition for getting XCM fees. + +use codec::{Decode, Encode}; +use frame_support::pallet_prelude::TypeInfo; +use sp_std::vec::Vec; +use sp_weights::Weight; +use xcm::{Version, VersionedAssetId, VersionedAssets, VersionedLocation, VersionedXcm}; + +sp_api::decl_runtime_apis! { + /// A trait of XCM payment API. + /// + /// API provides functionality for obtaining: + /// + /// * the weight required to execute an XCM message, + /// * a list of acceptable `AssetId`s for message execution payment, + /// * the cost of the weight in the specified acceptable `AssetId`. + /// * the fees for an XCM message delivery. + /// + /// To determine the execution weight of the calls required for + /// [`xcm::latest::Instruction::Transact`] instruction, `TransactionPaymentCallApi` can be used. + pub trait XcmPaymentApi { + /// Returns a list of acceptable payment assets. + /// + /// # Arguments + /// + /// * `xcm_version`: Version. + fn query_acceptable_payment_assets(xcm_version: Version) -> Result, Error>; + + /// Returns a weight needed to execute a XCM. + /// + /// # Arguments + /// + /// * `message`: `VersionedXcm`. + fn query_xcm_weight(message: VersionedXcm<()>) -> Result; + + /// Converts a weight into a fee for the specified `AssetId`. + /// + /// # Arguments + /// + /// * `weight`: convertible `Weight`. + /// * `asset`: `VersionedAssetId`. + fn query_weight_to_asset_fee(weight: Weight, asset: VersionedAssetId) -> Result; + + /// Get delivery fees for sending a specific `message` to a `destination`. + /// These always come in a specific asset, defined by the chain. + /// + /// # Arguments + /// * `message`: The message that'll be sent, necessary because most delivery fees are based on the + /// size of the message. + /// * `destination`: The destination to send the message to. Different destinations may use + /// different senders that charge different fees. + fn query_delivery_fees(destination: VersionedLocation, message: VersionedXcm<()>) -> Result; + } +} + +#[derive(Copy, Clone, Encode, Decode, Eq, PartialEq, Debug, TypeInfo)] +pub enum Error { + /// An API part is unsupported. + #[codec(index = 0)] + Unimplemented, + + /// Converting a versioned data structure from one version to another failed. + #[codec(index = 1)] + VersionedConversionFailed, + + /// XCM message weight calculation failed. + #[codec(index = 2)] + WeightNotComputable, + + /// XCM version not able to be handled. + #[codec(index = 3)] + UnhandledXcmVersion, + + /// The given asset is not handled as a fee asset. + #[codec(index = 4)] + AssetNotFound, + + /// Destination is known to be unroutable. + #[codec(index = 5)] + Unroutable, +} diff --git a/polkadot/xcm/xcm-fee-payment-runtime-api/src/lib.rs b/polkadot/xcm/xcm-fee-payment-runtime-api/src/lib.rs index 20bf9236f1fbbb46ca50a1b42d6dc4e519a5ae1a..616ee4c2eccb0aeed1cdb5e2aa524855d8b2df82 100644 --- a/polkadot/xcm/xcm-fee-payment-runtime-api/src/lib.rs +++ b/polkadot/xcm/xcm-fee-payment-runtime-api/src/lib.rs @@ -14,86 +14,19 @@ // You should have received a copy of the GNU General Public License // along with Polkadot. If not, see . -//! Runtime API definition for xcm transaction payment. +//! Runtime APIs for estimating xcm fee payment. +//! This crate offers two APIs, one for estimating fees, +//! which can be used for any type of message, and another one +//! for returning the specific messages used for transfers, a common +//! feature. +//! Users of these APIs should call the transfers API and pass the result to the +//! fees API. #![cfg_attr(not(feature = "std"), no_std)] -use codec::{Decode, Encode}; -use frame_support::pallet_prelude::TypeInfo; -use sp_std::vec::Vec; -use sp_weights::Weight; -use xcm::{Version, VersionedAssetId, VersionedAssets, VersionedLocation, VersionedXcm}; - -sp_api::decl_runtime_apis! { - /// A trait of XCM payment API. - /// - /// API provides functionality for obtaining: - /// - /// * the weight required to execute an XCM message, - /// * a list of acceptable `AssetId`s for message execution payment, - /// * the cost of the weight in the specified acceptable `AssetId`. - /// * the fees for an XCM message delivery. - /// - /// To determine the execution weight of the calls required for - /// [`xcm::latest::Instruction::Transact`] instruction, `TransactionPaymentCallApi` can be used. - pub trait XcmPaymentApi { - /// Returns a list of acceptable payment assets. - /// - /// # Arguments - /// - /// * `xcm_version`: Version. - fn query_acceptable_payment_assets(xcm_version: Version) -> Result, Error>; - - /// Returns a weight needed to execute a XCM. - /// - /// # Arguments - /// - /// * `message`: `VersionedXcm`. - fn query_xcm_weight(message: VersionedXcm<()>) -> Result; - - /// Converts a weight into a fee for the specified `AssetId`. - /// - /// # Arguments - /// - /// * `weight`: convertible `Weight`. - /// * `asset`: `VersionedAssetId`. - fn query_weight_to_asset_fee(weight: Weight, asset: VersionedAssetId) -> Result; - - /// Get delivery fees for sending a specific `message` to a `destination`. - /// These always come in a specific asset, defined by the chain. - /// - /// # Arguments - /// * `message`: The message that'll be sent, necessary because most delivery fees are based on the - /// size of the message. - /// * `destination`: The destination to send the message to. Different destinations may use - /// different senders that charge different fees. - fn query_delivery_fees(destination: VersionedLocation, message: VersionedXcm<()>) -> Result; - } -} - -#[derive(Copy, Clone, Encode, Decode, Eq, PartialEq, Debug, TypeInfo)] -pub enum Error { - /// An API part is unsupported. - #[codec(index = 0)] - Unimplemented, - - /// Converting a versioned data structure from one version to another failed. - #[codec(index = 1)] - VersionedConversionFailed, - - /// XCM message weight calculation failed. - #[codec(index = 2)] - WeightNotComputable, - - /// XCM version not able to be handled. - #[codec(index = 3)] - UnhandledXcmVersion, - - /// The given asset is not handled as a fee asset. - #[codec(index = 4)] - AssetNotFound, - - /// Destination is known to be unroutable. - #[codec(index = 5)] - Unroutable, -} +/// Dry-run API. +/// Given an extrinsic or an XCM program, it returns the outcome of its execution. +pub mod dry_run; +/// Fee estimation API. +/// Given an XCM program, it will return the fees needed to execute it properly or send it. +pub mod fees; diff --git a/polkadot/xcm/xcm-fee-payment-runtime-api/tests/fee_estimation.rs b/polkadot/xcm/xcm-fee-payment-runtime-api/tests/fee_estimation.rs new file mode 100644 index 0000000000000000000000000000000000000000..7a9bfa4a7968129a13395f2520b6ca1a7b14ff69 --- /dev/null +++ b/polkadot/xcm/xcm-fee-payment-runtime-api/tests/fee_estimation.rs @@ -0,0 +1,370 @@ +// Copyright (C) Parity Technologies (UK) Ltd. +// This file is part of Polkadot. + +// Substrate 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. + +// Substrate is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with Polkadot. If not, see . + +//! Tests for using both the XCM fee payment API and the dry-run API. + +use frame_support::{ + dispatch::DispatchInfo, + pallet_prelude::{DispatchClass, Pays}, +}; +use sp_api::ProvideRuntimeApi; +use sp_runtime::testing::H256; +use xcm::prelude::*; +use xcm_fee_payment_runtime_api::{dry_run::XcmDryRunApi, fees::XcmPaymentApi}; + +mod mock; +use mock::{ + extra, fake_message_hash, new_test_ext_with_balances, new_test_ext_with_balances_and_assets, + DeliveryFees, ExistentialDeposit, HereLocation, RuntimeCall, RuntimeEvent, TestClient, TestXt, +}; + +// Scenario: User `1` in the local chain (id 2000) wants to transfer assets to account `[0u8; 32]` +// on "AssetHub". He wants to make sure he has enough for fees, so before he calls the +// `transfer_asset` extrinsic to do the transfer, he decides to use the `XcmDryRunApi` and +// `XcmPaymentApi` runtime APIs to estimate fees. This uses a teleport because we're dealing with +// the native token of the chain, which is registered on "AssetHub". The fees are sent as a reserve +// asset transfer, since they're paid in the relay token. +// +// Teleport Parachain(2000) Token +// Reserve Asset Transfer Relay Token for fees +// Parachain(2000) -------------------------------------------> Parachain(1000) +#[test] +fn fee_estimation_for_teleport() { + let _ = env_logger::builder().is_test(true).try_init(); + let who = 1; // AccountId = u64. + let balances = vec![(who, 100 + DeliveryFees::get() + ExistentialDeposit::get())]; + let assets = vec![(1, who, 50)]; + new_test_ext_with_balances_and_assets(balances, assets).execute_with(|| { + let client = TestClient; + let runtime_api = client.runtime_api(); + let extrinsic = TestXt::new( + RuntimeCall::XcmPallet(pallet_xcm::Call::transfer_assets { + dest: Box::new(VersionedLocation::V4((Parent, Parachain(1000)).into())), + beneficiary: Box::new(VersionedLocation::V4( + AccountId32 { id: [0u8; 32], network: None }.into(), + )), + assets: Box::new(VersionedAssets::V4( + vec![(Here, 100u128).into(), (Parent, 20u128).into()].into(), + )), + fee_asset_item: 1, // Fees are paid with the RelayToken + weight_limit: Unlimited, + }), + Some((who, extra())), + ); + let dry_run_effects = + runtime_api.dry_run_extrinsic(H256::zero(), extrinsic).unwrap().unwrap(); + + assert_eq!( + dry_run_effects.local_xcm, + Some(VersionedXcm::V4( + Xcm::builder_unsafe() + .withdraw_asset((Parent, 20u128)) + .burn_asset((Parent, 20u128)) + .withdraw_asset((Here, 100u128)) + .burn_asset((Here, 100u128)) + .build() + )), + ); + let send_destination = Location::new(1, [Parachain(1000)]); + let send_message = Xcm::<()>::builder_unsafe() + .withdraw_asset((Parent, 20u128)) + .buy_execution((Parent, 20u128), Unlimited) + .receive_teleported_asset(((Parent, Parachain(2000)), 100u128)) + .clear_origin() + .deposit_asset(AllCounted(2), [0u8; 32]) + .build(); + assert_eq!( + dry_run_effects.forwarded_xcms, + vec![( + VersionedLocation::V4(send_destination.clone()), + vec![VersionedXcm::V4(send_message.clone())], + ),], + ); + + assert_eq!( + dry_run_effects.emitted_events, + vec![ + RuntimeEvent::System(frame_system::Event::NewAccount { + account: 8660274132218572653 // TODO: Why is this not `1`? + }), + RuntimeEvent::Balances(pallet_balances::Event::Endowed { + account: 8660274132218572653, + free_balance: 100 + }), + RuntimeEvent::Balances(pallet_balances::Event::Minted { + who: 8660274132218572653, + amount: 100 + }), + RuntimeEvent::AssetsPallet(pallet_assets::Event::Burned { + asset_id: 1, + owner: 1, + balance: 20 + }), + RuntimeEvent::Balances(pallet_balances::Event::Burned { who: 1, amount: 100 }), + RuntimeEvent::XcmPallet(pallet_xcm::Event::Attempted { + outcome: Outcome::Complete { used: Weight::from_parts(400, 40) }, + }), + RuntimeEvent::Balances(pallet_balances::Event::Burned { who: 1, amount: 20 }), + RuntimeEvent::XcmPallet(pallet_xcm::Event::FeesPaid { + paying: AccountIndex64 { index: 1, network: None }.into(), + fees: (Here, 20u128).into(), + }), + RuntimeEvent::XcmPallet(pallet_xcm::Event::Sent { + origin: AccountIndex64 { index: 1, network: None }.into(), + destination: (Parent, Parachain(1000)).into(), + message: send_message.clone(), + message_id: fake_message_hash(&send_message), + }), + RuntimeEvent::System(frame_system::Event::ExtrinsicSuccess { + dispatch_info: DispatchInfo { + weight: Weight::from_parts(107074070, 0), /* Will break if weights get + * updated. */ + class: DispatchClass::Normal, + pays_fee: Pays::Yes, + } + }), + ] + ); + + // Weighing the local program is not relevant for extrinsics that already + // take this weight into account. + // In this case, we really only care about delivery fees. + let local_xcm = dry_run_effects.local_xcm.unwrap(); + + // We get a double result since the actual call returns a result and the runtime api returns + // results. + let weight = + runtime_api.query_xcm_weight(H256::zero(), local_xcm.clone()).unwrap().unwrap(); + assert_eq!(weight, Weight::from_parts(400, 40)); + let execution_fees = runtime_api + .query_weight_to_asset_fee( + H256::zero(), + weight, + VersionedAssetId::V4(HereLocation::get().into()), + ) + .unwrap() + .unwrap(); + assert_eq!(execution_fees, 440); + + let mut forwarded_xcms_iter = dry_run_effects.forwarded_xcms.into_iter(); + + let (destination, remote_messages) = forwarded_xcms_iter.next().unwrap(); + let remote_message = &remote_messages[0]; + + let delivery_fees = runtime_api + .query_delivery_fees(H256::zero(), destination.clone(), remote_message.clone()) + .unwrap() + .unwrap(); + assert_eq!(delivery_fees, VersionedAssets::V4((Here, 20u128).into())); + + // This would have to be the runtime API of the destination, + // which we have the location for. + // If I had a mock runtime configured for "AssetHub" then I would use the + // runtime APIs from that. + let remote_execution_weight = runtime_api + .query_xcm_weight(H256::zero(), remote_message.clone()) + .unwrap() + .unwrap(); + let remote_execution_fees = runtime_api + .query_weight_to_asset_fee( + H256::zero(), + remote_execution_weight, + VersionedAssetId::V4(HereLocation::get().into()), + ) + .unwrap() + .unwrap(); + assert_eq!(remote_execution_fees, 550); + + // Now we know that locally we need to use `execution_fees` and + // `delivery_fees`. + // On the message we forward to the destination, we need to + // put `remote_execution_fees` in `BuyExecution`. + // For the `transfer_assets` extrinsic, it just means passing the correct amount + // of fees in the parameters. + }); +} + +// Same scenario as in `fee_estimation_for_teleport`, but the user in parachain 2000 wants +// to send relay tokens over to parachain 1000. +// +// Reserve Asset Transfer Relay Token +// Reserve Asset Transfer Relay Token for fees +// Parachain(2000) -------------------------------------------> Parachain(1000) +#[test] +fn dry_run_reserve_asset_transfer() { + let _ = env_logger::builder().is_test(true).try_init(); + let who = 1; // AccountId = u64. + // Native token used for fees. + let balances = vec![(who, DeliveryFees::get() + ExistentialDeposit::get())]; + // Relay token is the one we want to transfer. + let assets = vec![(1, who, 100)]; // id, account_id, balance. + new_test_ext_with_balances_and_assets(balances, assets).execute_with(|| { + let client = TestClient; + let runtime_api = client.runtime_api(); + let extrinsic = TestXt::new( + RuntimeCall::XcmPallet(pallet_xcm::Call::transfer_assets { + dest: Box::new(VersionedLocation::V4((Parent, Parachain(1000)).into())), + beneficiary: Box::new(VersionedLocation::V4( + AccountId32 { id: [0u8; 32], network: None }.into(), + )), + assets: Box::new(VersionedAssets::V4((Parent, 100u128).into())), + fee_asset_item: 0, + weight_limit: Unlimited, + }), + Some((who, extra())), + ); + let dry_run_effects = + runtime_api.dry_run_extrinsic(H256::zero(), extrinsic).unwrap().unwrap(); + + assert_eq!( + dry_run_effects.local_xcm, + Some(VersionedXcm::V4( + Xcm::builder_unsafe() + .withdraw_asset((Parent, 100u128)) + .burn_asset((Parent, 100u128)) + .build() + )), + ); + + // In this case, the transfer type is `DestinationReserve`, so the remote xcm just withdraws + // the assets. + let send_destination = Location::new(1, Parachain(1000)); + let send_message = Xcm::<()>::builder_unsafe() + .withdraw_asset((Parent, 100u128)) + .clear_origin() + .buy_execution((Parent, 100u128), Unlimited) + .deposit_asset(AllCounted(1), [0u8; 32]) + .build(); + assert_eq!( + dry_run_effects.forwarded_xcms, + vec![( + VersionedLocation::V4(send_destination.clone()), + vec![VersionedXcm::V4(send_message.clone())], + ),], + ); + + assert_eq!( + dry_run_effects.emitted_events, + vec![ + RuntimeEvent::AssetsPallet(pallet_assets::Event::Burned { + asset_id: 1, + owner: 1, + balance: 100 + }), + RuntimeEvent::XcmPallet(pallet_xcm::Event::Attempted { + outcome: Outcome::Complete { used: Weight::from_parts(200, 20) } + }), + RuntimeEvent::Balances(pallet_balances::Event::Burned { who: 1, amount: 20 }), + RuntimeEvent::XcmPallet(pallet_xcm::Event::FeesPaid { + paying: AccountIndex64 { index: 1, network: None }.into(), + fees: (Here, 20u128).into() + }), + RuntimeEvent::XcmPallet(pallet_xcm::Event::Sent { + origin: AccountIndex64 { index: 1, network: None }.into(), + destination: send_destination.clone(), + message: send_message.clone(), + message_id: fake_message_hash(&send_message), + }), + RuntimeEvent::System(frame_system::Event::ExtrinsicSuccess { + dispatch_info: DispatchInfo { + weight: Weight::from_parts(107074066, 0), /* Will break if weights get + * updated. */ + class: DispatchClass::Normal, + pays_fee: Pays::Yes, + } + }), + ] + ); + }); +} + +#[test] +fn dry_run_xcm() { + let _ = env_logger::builder().is_test(true).try_init(); + let who = 1; // AccountId = u64. + let transfer_amount = 100u128; + // We need to build the XCM to weigh it and then build the real XCM that can pay for fees. + let inner_xcm = Xcm::<()>::builder_unsafe() + .buy_execution((Here, 1u128), Unlimited) // We'd need to query the destination chain for fees. + .deposit_asset(AllCounted(1), [0u8; 32]) + .build(); + let xcm_to_weigh = Xcm::::builder_unsafe() + .withdraw_asset((Here, transfer_amount)) + .clear_origin() + .buy_execution((Here, transfer_amount), Unlimited) + .deposit_reserve_asset(AllCounted(1), (Parent, Parachain(2100)), inner_xcm.clone()) + .build(); + let client = TestClient; + let runtime_api = client.runtime_api(); + let xcm_weight = runtime_api + .query_xcm_weight(H256::zero(), VersionedXcm::V4(xcm_to_weigh.clone().into())) + .unwrap() + .unwrap(); + let execution_fees = runtime_api + .query_weight_to_asset_fee(H256::zero(), xcm_weight, VersionedAssetId::V4(Here.into())) + .unwrap() + .unwrap(); + let xcm = Xcm::::builder_unsafe() + .withdraw_asset((Here, transfer_amount + execution_fees)) + .clear_origin() + .buy_execution((Here, execution_fees), Unlimited) + .deposit_reserve_asset(AllCounted(1), (Parent, Parachain(2100)), inner_xcm.clone()) + .build(); + let balances = vec![( + who, + transfer_amount + execution_fees + DeliveryFees::get() + ExistentialDeposit::get(), + )]; + new_test_ext_with_balances(balances).execute_with(|| { + let dry_run_effects = runtime_api + .dry_run_xcm( + H256::zero(), + VersionedLocation::V4(AccountIndex64 { index: 1, network: None }.into()), + VersionedXcm::V4(xcm), + ) + .unwrap() + .unwrap(); + assert_eq!( + dry_run_effects.forwarded_xcms, + vec![( + VersionedLocation::V4((Parent, Parachain(2100)).into()), + vec![VersionedXcm::V4( + Xcm::<()>::builder_unsafe() + .reserve_asset_deposited(( + (Parent, Parachain(2000)), + transfer_amount + execution_fees - DeliveryFees::get() + )) + .clear_origin() + .buy_execution((Here, 1u128), Unlimited) + .deposit_asset(AllCounted(1), [0u8; 32]) + .build() + )], + ),] + ); + + assert_eq!( + dry_run_effects.emitted_events, + vec![ + RuntimeEvent::Balances(pallet_balances::Event::Burned { who: 1, amount: 540 }), + RuntimeEvent::System(frame_system::Event::NewAccount { account: 2100 }), + RuntimeEvent::Balances(pallet_balances::Event::Endowed { + account: 2100, + free_balance: 520 + }), + RuntimeEvent::Balances(pallet_balances::Event::Minted { who: 2100, amount: 520 }), + ] + ); + }); +} diff --git a/polkadot/xcm/xcm-fee-payment-runtime-api/tests/mock.rs b/polkadot/xcm/xcm-fee-payment-runtime-api/tests/mock.rs new file mode 100644 index 0000000000000000000000000000000000000000..d7b18d90a501815018fde21e25481872e33753a6 --- /dev/null +++ b/polkadot/xcm/xcm-fee-payment-runtime-api/tests/mock.rs @@ -0,0 +1,525 @@ +// Copyright (C) Parity Technologies (UK) Ltd. +// This file is part of Polkadot. + +// Substrate 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. + +// Substrate is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with Polkadot. If not, see . + +//! Mock runtime for tests. +//! Implements both runtime APIs for fee estimation and getting the messages for transfers. + +use codec::Encode; +use frame_support::{ + construct_runtime, derive_impl, parameter_types, + traits::{ + AsEnsureOriginWithArg, ConstU128, ConstU32, Contains, ContainsPair, Everything, Nothing, + OriginTrait, + }, + weights::WeightToFee as WeightToFeeT, +}; +use frame_system::{EnsureRoot, RawOrigin as SystemRawOrigin}; +use pallet_xcm::TestWeightInfo; +use sp_runtime::{ + traits::{Block as BlockT, Get, IdentityLookup, MaybeEquivalence, TryConvert}, + BuildStorage, SaturatedConversion, +}; +use sp_std::{cell::RefCell, marker::PhantomData}; +use xcm::{prelude::*, Version as XcmVersion}; +use xcm_builder::{ + AllowTopLevelPaidExecutionFrom, ConvertedConcreteId, EnsureXcmOrigin, FixedRateOfFungible, + FixedWeightBounds, FungibleAdapter, FungiblesAdapter, IsConcrete, MintLocation, NoChecking, + TakeWeightCredit, +}; +use xcm_executor::{ + traits::{ConvertLocation, JustTry}, + XcmExecutor, +}; + +use xcm_fee_payment_runtime_api::{ + dry_run::{Error as XcmDryRunApiError, ExtrinsicDryRunEffects, XcmDryRunApi, XcmDryRunEffects}, + fees::{Error as XcmPaymentApiError, XcmPaymentApi}, +}; + +construct_runtime! { + pub enum TestRuntime { + System: frame_system, + Balances: pallet_balances, + AssetsPallet: pallet_assets, + XcmPallet: pallet_xcm, + } +} + +pub type SignedExtra = ( + // frame_system::CheckEra, + // frame_system::CheckNonce, + frame_system::CheckWeight, +); +pub type TestXt = sp_runtime::testing::TestXt; +type Block = sp_runtime::testing::Block; +type Balance = u128; +type AssetIdForAssetsPallet = u32; +type AccountId = u64; + +pub fn extra() -> SignedExtra { + (frame_system::CheckWeight::new(),) +} + +type Executive = frame_executive::Executive< + TestRuntime, + Block, + frame_system::ChainContext, + TestRuntime, + AllPalletsWithSystem, + (), +>; + +#[derive_impl(frame_system::config_preludes::TestDefaultConfig)] +impl frame_system::Config for TestRuntime { + type Block = Block; + type AccountId = AccountId; + type AccountData = pallet_balances::AccountData; + type Lookup = IdentityLookup; +} + +#[derive_impl(pallet_balances::config_preludes::TestDefaultConfig)] +impl pallet_balances::Config for TestRuntime { + type AccountStore = System; + type Balance = Balance; + type ExistentialDeposit = ExistentialDeposit; +} + +#[derive_impl(pallet_assets::config_preludes::TestDefaultConfig)] +impl pallet_assets::Config for TestRuntime { + type AssetId = AssetIdForAssetsPallet; + type Balance = Balance; + type Currency = Balances; + type CreateOrigin = AsEnsureOriginWithArg>; + type ForceOrigin = frame_system::EnsureRoot; + type Freezer = (); + type AssetDeposit = ConstU128<1>; + type AssetAccountDeposit = ConstU128<10>; + type MetadataDepositBase = ConstU128<1>; + type MetadataDepositPerByte = ConstU128<1>; + type ApprovalDeposit = ConstU128<1>; + #[cfg(feature = "runtime-benchmarks")] + type BenchmarkHelper = (); +} + +thread_local! { + pub static SENT_XCM: RefCell)>> = const { RefCell::new(Vec::new()) }; +} + +pub(crate) fn sent_xcm() -> Vec<(Location, Xcm<()>)> { + SENT_XCM.with(|q| (*q.borrow()).clone()) +} + +pub struct TestXcmSender; +impl SendXcm for TestXcmSender { + type Ticket = (Location, Xcm<()>); + fn validate( + dest: &mut Option, + msg: &mut Option>, + ) -> SendResult { + let ticket = (dest.take().unwrap(), msg.take().unwrap()); + let fees: Assets = (HereLocation::get(), DeliveryFees::get()).into(); + Ok((ticket, fees)) + } + fn deliver(ticket: Self::Ticket) -> Result { + let hash = fake_message_hash(&ticket.1); + SENT_XCM.with(|q| q.borrow_mut().push(ticket)); + Ok(hash) + } +} + +pub(crate) fn fake_message_hash(message: &Xcm) -> XcmHash { + message.using_encoded(sp_io::hashing::blake2_256) +} + +pub type XcmRouter = TestXcmSender; + +parameter_types! { + pub const DeliveryFees: u128 = 20; // Random value. + pub const ExistentialDeposit: u128 = 1; // Random value. + pub const BaseXcmWeight: Weight = Weight::from_parts(100, 10); // Random value. + pub const MaxInstructions: u32 = 100; + pub const NativeTokenPerSecondPerByte: (AssetId, u128, u128) = (AssetId(HereLocation::get()), 1, 1); + pub UniversalLocation: InteriorLocation = [GlobalConsensus(NetworkId::Westend), Parachain(2000)].into(); + pub static AdvertisedXcmVersion: XcmVersion = 4; + pub const HereLocation: Location = Location::here(); + pub const RelayLocation: Location = Location::parent(); + pub const MaxAssetsIntoHolding: u32 = 64; + pub CheckAccount: AccountId = XcmPallet::check_account(); + pub LocalCheckAccount: (AccountId, MintLocation) = (CheckAccount::get(), MintLocation::Local); + pub const AnyNetwork: Option = None; +} + +/// Simple `WeightToFee` implementation that adds the ref_time by the proof_size. +pub struct WeightToFee; +impl WeightToFeeT for WeightToFee { + type Balance = Balance; + fn weight_to_fee(weight: &Weight) -> Self::Balance { + Self::Balance::saturated_from(weight.ref_time()) + .saturating_add(Self::Balance::saturated_from(weight.proof_size())) + } +} + +type Weigher = FixedWeightBounds; + +/// Matches the pair (NativeToken, AssetHub). +/// This is used in the `IsTeleporter` configuration item, meaning we accept our native token +/// coming from AssetHub as a teleport. +pub struct NativeTokenToAssetHub; +impl ContainsPair for NativeTokenToAssetHub { + fn contains(asset: &Asset, origin: &Location) -> bool { + matches!(asset.id.0.unpack(), (0, [])) && matches!(origin.unpack(), (1, [Parachain(1000)])) + } +} + +/// Matches the pair (RelayToken, AssetHub). +/// This is used in the `IsReserve` configuration item, meaning we accept the relay token +/// coming from AssetHub as a reserve asset transfer. +pub struct RelayTokenToAssetHub; +impl ContainsPair for RelayTokenToAssetHub { + fn contains(asset: &Asset, origin: &Location) -> bool { + matches!(asset.id.0.unpack(), (1, [])) && matches!(origin.unpack(), (1, [Parachain(1000)])) + } +} + +/// Converts locations that are only the `AccountIndex64` junction into local u64 accounts. +pub struct AccountIndex64Aliases(PhantomData<(Network, AccountId)>); +impl>, AccountId: From> ConvertLocation + for AccountIndex64Aliases +{ + fn convert_location(location: &Location) -> Option { + let index = match location.unpack() { + (0, [AccountIndex64 { index, network: None }]) => index, + (0, [AccountIndex64 { index, network }]) if *network == Network::get() => index, + _ => return None, + }; + Some((*index).into()) + } +} + +/// Custom location converter to turn sibling chains into u64 accounts. +pub struct SiblingChainToIndex64; +impl ConvertLocation for SiblingChainToIndex64 { + fn convert_location(location: &Location) -> Option { + let index = match location.unpack() { + (1, [Parachain(id)]) => id, + _ => return None, + }; + Some((*index).into()) + } +} + +/// We alias local account locations to actual local accounts. +/// We also allow sovereign accounts for other sibling chains. +pub type LocationToAccountId = (AccountIndex64Aliases, SiblingChainToIndex64); + +pub type NativeTokenTransactor = FungibleAdapter< + // We use pallet-balances for handling this fungible asset. + Balances, + // The fungible asset handled by this transactor is the native token of the chain. + IsConcrete, + // How we convert locations to accounts. + LocationToAccountId, + // We need to specify the AccountId type. + AccountId, + // We mint the native tokens locally, so we track how many we've sent away via teleports. + LocalCheckAccount, +>; + +pub struct LocationToAssetIdForAssetsPallet; +impl MaybeEquivalence for LocationToAssetIdForAssetsPallet { + fn convert(location: &Location) -> Option { + match location.unpack() { + (1, []) => Some(1 as AssetIdForAssetsPallet), + _ => None, + } + } + + fn convert_back(id: &AssetIdForAssetsPallet) -> Option { + match id { + 1 => Some(Location::new(1, [])), + _ => None, + } + } +} + +/// AssetTransactor for handling the relay chain token. +pub type RelayTokenTransactor = FungiblesAdapter< + // We use pallet-assets for handling the relay token. + AssetsPallet, + // Matches the relay token. + ConvertedConcreteId, + // How we convert locations to accounts. + LocationToAccountId, + // We need to specify the AccountId type. + AccountId, + // We don't track teleports. + NoChecking, + (), +>; + +pub type AssetTransactors = (NativeTokenTransactor, RelayTokenTransactor); + +pub struct HereAndInnerLocations; +impl Contains for HereAndInnerLocations { + fn contains(location: &Location) -> bool { + matches!(location.unpack(), (0, []) | (0, _)) + } +} + +pub type Barrier = ( + TakeWeightCredit, // We need this for pallet-xcm's extrinsics to work. + AllowTopLevelPaidExecutionFrom, /* TODO: Technically, we should allow + * messages from "AssetHub". */ +); + +pub type Trader = FixedRateOfFungible; + +pub struct XcmConfig; +impl xcm_executor::Config for XcmConfig { + type RuntimeCall = RuntimeCall; + type XcmSender = XcmRouter; + type AssetTransactor = AssetTransactors; + type OriginConverter = (); + type IsReserve = RelayTokenToAssetHub; + type IsTeleporter = NativeTokenToAssetHub; + type UniversalLocation = UniversalLocation; + type Barrier = Barrier; + type Weigher = Weigher; + type Trader = Trader; + type ResponseHandler = (); + type AssetTrap = (); + type AssetLocker = (); + type AssetExchanger = (); + type AssetClaims = (); + type SubscriptionService = (); + type PalletInstancesInfo = AllPalletsWithSystem; + type MaxAssetsIntoHolding = MaxAssetsIntoHolding; + type FeeManager = (); + type MessageExporter = (); + type UniversalAliases = (); + type CallDispatcher = RuntimeCall; + type SafeCallFilter = Nothing; + type Aliasers = Nothing; + type TransactionalProcessor = (); + type HrmpNewChannelOpenRequestHandler = (); + type HrmpChannelAcceptedHandler = (); + type HrmpChannelClosingHandler = (); + type XcmRecorder = XcmPallet; +} + +/// Converts a signed origin of a u64 account into a location with only the `AccountIndex64` +/// junction. +pub struct SignedToAccountIndex64( + PhantomData<(RuntimeOrigin, AccountId)>, +); +impl> TryConvert + for SignedToAccountIndex64 +where + RuntimeOrigin::PalletsOrigin: From> + + TryInto, Error = RuntimeOrigin::PalletsOrigin>, +{ + fn try_convert(origin: RuntimeOrigin) -> Result { + origin.try_with_caller(|caller| match caller.try_into() { + Ok(SystemRawOrigin::Signed(who)) => + Ok(Junction::AccountIndex64 { network: None, index: who.into() }.into()), + Ok(other) => Err(other.into()), + Err(other) => Err(other), + }) + } +} + +pub type LocalOriginToLocation = SignedToAccountIndex64; + +impl pallet_xcm::Config for TestRuntime { + type RuntimeEvent = RuntimeEvent; + type SendXcmOrigin = EnsureXcmOrigin; + type XcmRouter = XcmRouter; + type ExecuteXcmOrigin = EnsureXcmOrigin; + type XcmExecuteFilter = Nothing; + type XcmExecutor = XcmExecutor; + type XcmTeleportFilter = Everything; // Put everything instead of something more restricted. + type XcmReserveTransferFilter = Everything; // Same. + type Weigher = Weigher; + type UniversalLocation = UniversalLocation; + type RuntimeOrigin = RuntimeOrigin; + type RuntimeCall = RuntimeCall; + const VERSION_DISCOVERY_QUEUE_SIZE: u32 = 100; + type AdvertisedXcmVersion = AdvertisedXcmVersion; + type AdminOrigin = EnsureRoot; + type TrustedLockers = (); + type SovereignAccountOf = (); + type Currency = Balances; + type CurrencyMatcher = IsConcrete; + type MaxLockers = ConstU32<0>; + type MaxRemoteLockConsumers = ConstU32<0>; + type RemoteLockConsumerIdentifier = (); + type WeightInfo = TestWeightInfo; +} + +pub fn new_test_ext_with_balances(balances: Vec<(AccountId, Balance)>) -> sp_io::TestExternalities { + let mut t = frame_system::GenesisConfig::::default().build_storage().unwrap(); + + pallet_balances::GenesisConfig:: { balances } + .assimilate_storage(&mut t) + .unwrap(); + + let mut ext = sp_io::TestExternalities::new(t); + ext.execute_with(|| System::set_block_number(1)); + ext +} + +pub fn new_test_ext_with_balances_and_assets( + balances: Vec<(AccountId, Balance)>, + assets: Vec<(AssetIdForAssetsPallet, AccountId, Balance)>, +) -> sp_io::TestExternalities { + let mut t = frame_system::GenesisConfig::::default().build_storage().unwrap(); + + pallet_balances::GenesisConfig:: { balances } + .assimilate_storage(&mut t) + .unwrap(); + + pallet_assets::GenesisConfig:: { + assets: vec![ + // id, owner, is_sufficient, min_balance. + // We don't actually need this to be sufficient, since we use the native assets in + // tests for the existential deposit. + (1, 0, true, 1), + ], + metadata: vec![ + // id, name, symbol, decimals. + (1, "Relay Token".into(), "RLY".into(), 12), + ], + accounts: assets, + } + .assimilate_storage(&mut t) + .unwrap(); + + let mut ext = sp_io::TestExternalities::new(t); + ext.execute_with(|| System::set_block_number(1)); + ext +} + +#[derive(Clone)] +pub(crate) struct TestClient; + +pub(crate) struct RuntimeApi { + _inner: TestClient, +} + +impl sp_api::ProvideRuntimeApi for TestClient { + type Api = RuntimeApi; + fn runtime_api(&self) -> sp_api::ApiRef { + RuntimeApi { _inner: self.clone() }.into() + } +} + +sp_api::mock_impl_runtime_apis! { + impl XcmPaymentApi for RuntimeApi { + fn query_acceptable_payment_assets(xcm_version: XcmVersion) -> Result, XcmPaymentApiError> { + if xcm_version != 4 { return Err(XcmPaymentApiError::UnhandledXcmVersion) }; + Ok(vec![VersionedAssetId::V4(HereLocation::get().into())]) + } + + fn query_xcm_weight(message: VersionedXcm<()>) -> Result { + XcmPallet::query_xcm_weight(message) + } + + fn query_weight_to_asset_fee(weight: Weight, asset: VersionedAssetId) -> Result { + let local_asset = VersionedAssetId::V4(HereLocation::get().into()); + let asset = asset + .into_version(4) + .map_err(|_| XcmPaymentApiError::VersionedConversionFailed)?; + + if asset != local_asset { return Err(XcmPaymentApiError::AssetNotFound); } + + Ok(WeightToFee::weight_to_fee(&weight)) + } + + fn query_delivery_fees(destination: VersionedLocation, message: VersionedXcm<()>) -> Result { + XcmPallet::query_delivery_fees(destination, message) + } + } + + impl XcmDryRunApi for RuntimeApi { + fn dry_run_extrinsic(extrinsic: ::Extrinsic) -> Result, XcmDryRunApiError> { + use xcm_executor::RecordXcm; + // We want to record the XCM that's executed, so we can return it. + pallet_xcm::Pallet::::set_record_xcm(true); + let result = Executive::apply_extrinsic(extrinsic).map_err(|error| { + log::error!( + target: "xcm::XcmDryRunApi::dry_run_extrinsic", + "Applying extrinsic failed with error {:?}", + error, + ); + XcmDryRunApiError::InvalidExtrinsic + })?; + // Nothing gets committed to storage in runtime APIs, so there's no harm in leaving the flag as true. + let local_xcm = pallet_xcm::Pallet::::recorded_xcm(); + let forwarded_xcms = sent_xcm() + .into_iter() + .map(|(location, message)| ( + VersionedLocation::V4(location), + vec![VersionedXcm::V4(message)], + )).collect(); + let events: Vec = System::events().iter().map(|record| record.event.clone()).collect(); + Ok(ExtrinsicDryRunEffects { + local_xcm: local_xcm.map(VersionedXcm::<()>::V4), + forwarded_xcms, + emitted_events: events, + execution_result: result, + }) + } + + fn dry_run_xcm(origin_location: VersionedLocation, xcm: VersionedXcm) -> Result, XcmDryRunApiError> { + let origin_location: Location = origin_location.try_into().map_err(|error| { + log::error!( + target: "xcm::XcmDryRunApi::dry_run_xcm", + "Location version conversion failed with error: {:?}", + error, + ); + XcmDryRunApiError::VersionedConversionFailed + })?; + let xcm: Xcm = xcm.try_into().map_err(|error| { + log::error!( + target: "xcm::XcmDryRunApi::dry_run_xcm", + "Xcm version conversion failed with error {:?}", + error, + ); + XcmDryRunApiError::VersionedConversionFailed + })?; + let mut hash = fake_message_hash(&xcm); + let result = XcmExecutor::::prepare_and_execute( + origin_location, + xcm, + &mut hash, + Weight::MAX, // Max limit available for execution. + Weight::zero(), + ); + let forwarded_xcms = sent_xcm() + .into_iter() + .map(|(location, message)| ( + VersionedLocation::V4(location), + vec![VersionedXcm::V4(message)], + )).collect(); + let events: Vec = System::events().iter().map(|record| record.event.clone()).collect(); + Ok(XcmDryRunEffects { + forwarded_xcms, + emitted_events: events, + execution_result: result, + }) + } + } +} diff --git a/polkadot/xcm/xcm-simulator/Cargo.toml b/polkadot/xcm/xcm-simulator/Cargo.toml index c1c48b6d4c5eb6195a60152f29bdb61e2ad80a79..fc09b5e31861c0cb6470e7d7c121e8c94e1f60f8 100644 --- a/polkadot/xcm/xcm-simulator/Cargo.toml +++ b/polkadot/xcm/xcm-simulator/Cargo.toml @@ -10,16 +10,20 @@ license.workspace = true workspace = true [dependencies] -codec = { package = "parity-scale-codec", version = "3.6.1" } +codec = { package = "parity-scale-codec", version = "3.6.12" } +scale-info = { version = "2.6.0", default-features = false } paste = "1.0.7" frame-support = { path = "../../../substrate/frame/support" } +frame-system = { path = "../../../substrate/frame/system" } sp-io = { path = "../../../substrate/primitives/io" } sp-std = { path = "../../../substrate/primitives/std" } +sp-runtime = { path = "../../../substrate/primitives/runtime" } xcm = { package = "staging-xcm", path = ".." } xcm-executor = { package = "staging-xcm-executor", path = "../xcm-executor" } xcm-builder = { package = "staging-xcm-builder", path = "../xcm-builder" } +polkadot-primitives = { path = "../../primitives" } polkadot-core-primitives = { path = "../../core-primitives" } polkadot-parachain-primitives = { path = "../../parachain" } polkadot-runtime-parachains = { path = "../../runtime/parachains" } diff --git a/polkadot/xcm/xcm-simulator/example/Cargo.toml b/polkadot/xcm/xcm-simulator/example/Cargo.toml index 0e13a10a14106c92d56d288d210b57f3888068b2..8b04170e3032f90adb6f4c3c5d3954729e009b20 100644 --- a/polkadot/xcm/xcm-simulator/example/Cargo.toml +++ b/polkadot/xcm/xcm-simulator/example/Cargo.toml @@ -10,7 +10,7 @@ version = "7.0.0" workspace = true [dependencies] -codec = { package = "parity-scale-codec", version = "3.6.1" } +codec = { package = "parity-scale-codec", version = "3.6.12" } scale-info = { version = "2.11.1", features = ["derive"] } log = { workspace = true } diff --git a/polkadot/xcm/xcm-simulator/example/src/lib.rs b/polkadot/xcm/xcm-simulator/example/src/lib.rs index 56e204bf5718164385e3da924f75ae98c2fcb075..6fb9a69770ea8f74860f528bce56ecd44cc2fc9f 100644 --- a/polkadot/xcm/xcm-simulator/example/src/lib.rs +++ b/polkadot/xcm/xcm-simulator/example/src/lib.rs @@ -17,13 +17,16 @@ mod parachain; mod relay_chain; +#[cfg(test)] +mod tests; + use sp_runtime::BuildStorage; use sp_tracing; use xcm::prelude::*; use xcm_executor::traits::ConvertLocation; use xcm_simulator::{decl_test_network, decl_test_parachain, decl_test_relay_chain, TestExt}; -pub const ALICE: sp_runtime::AccountId32 = sp_runtime::AccountId32::new([0u8; 32]); +pub const ALICE: sp_runtime::AccountId32 = sp_runtime::AccountId32::new([1u8; 32]); pub const INITIAL_BALANCE: u128 = 1_000_000_000; decl_test_parachain! { @@ -68,27 +71,27 @@ decl_test_network! { pub fn parent_account_id() -> parachain::AccountId { let location = (Parent,); - parachain::LocationToAccountId::convert_location(&location.into()).unwrap() + parachain::location_converter::LocationConverter::convert_location(&location.into()).unwrap() } pub fn child_account_id(para: u32) -> relay_chain::AccountId { let location = (Parachain(para),); - relay_chain::LocationToAccountId::convert_location(&location.into()).unwrap() + relay_chain::location_converter::LocationConverter::convert_location(&location.into()).unwrap() } pub fn child_account_account_id(para: u32, who: sp_runtime::AccountId32) -> relay_chain::AccountId { let location = (Parachain(para), AccountId32 { network: None, id: who.into() }); - relay_chain::LocationToAccountId::convert_location(&location.into()).unwrap() + relay_chain::location_converter::LocationConverter::convert_location(&location.into()).unwrap() } pub fn sibling_account_account_id(para: u32, who: sp_runtime::AccountId32) -> parachain::AccountId { let location = (Parent, Parachain(para), AccountId32 { network: None, id: who.into() }); - parachain::LocationToAccountId::convert_location(&location.into()).unwrap() + parachain::location_converter::LocationConverter::convert_location(&location.into()).unwrap() } pub fn parent_account_account_id(who: sp_runtime::AccountId32) -> parachain::AccountId { let location = (Parent, AccountId32 { network: None, id: who.into() }); - parachain::LocationToAccountId::convert_location(&location.into()).unwrap() + parachain::location_converter::LocationConverter::convert_location(&location.into()).unwrap() } pub fn para_ext(para_id: u32) -> sp_io::TestExternalities { @@ -137,517 +140,3 @@ pub fn relay_ext() -> sp_io::TestExternalities { pub type RelayChainPalletXcm = pallet_xcm::Pallet; pub type ParachainPalletXcm = pallet_xcm::Pallet; - -#[cfg(test)] -mod tests { - use super::*; - - use codec::Encode; - use frame_support::{assert_ok, weights::Weight}; - use xcm::latest::QueryResponseInfo; - use xcm_simulator::TestExt; - - // Helper function for forming buy execution message - fn buy_execution(fees: impl Into) -> Instruction { - BuyExecution { fees: fees.into(), weight_limit: Unlimited } - } - - #[test] - fn remote_account_ids_work() { - child_account_account_id(1, ALICE); - sibling_account_account_id(1, ALICE); - parent_account_account_id(ALICE); - } - - #[test] - fn dmp() { - MockNet::reset(); - - let remark = parachain::RuntimeCall::System( - frame_system::Call::::remark_with_event { remark: vec![1, 2, 3] }, - ); - Relay::execute_with(|| { - assert_ok!(RelayChainPalletXcm::send_xcm( - Here, - Parachain(1), - Xcm(vec![Transact { - origin_kind: OriginKind::SovereignAccount, - require_weight_at_most: Weight::from_parts(INITIAL_BALANCE as u64, 1024 * 1024), - call: remark.encode().into(), - }]), - )); - }); - - ParaA::execute_with(|| { - use parachain::{RuntimeEvent, System}; - assert!(System::events().iter().any(|r| matches!( - r.event, - RuntimeEvent::System(frame_system::Event::Remarked { .. }) - ))); - }); - } - - #[test] - fn ump() { - MockNet::reset(); - - let remark = relay_chain::RuntimeCall::System( - frame_system::Call::::remark_with_event { remark: vec![1, 2, 3] }, - ); - ParaA::execute_with(|| { - assert_ok!(ParachainPalletXcm::send_xcm( - Here, - Parent, - Xcm(vec![Transact { - origin_kind: OriginKind::SovereignAccount, - require_weight_at_most: Weight::from_parts(INITIAL_BALANCE as u64, 1024 * 1024), - call: remark.encode().into(), - }]), - )); - }); - - Relay::execute_with(|| { - use relay_chain::{RuntimeEvent, System}; - assert!(System::events().iter().any(|r| matches!( - r.event, - RuntimeEvent::System(frame_system::Event::Remarked { .. }) - ))); - }); - } - - #[test] - fn xcmp() { - MockNet::reset(); - - let remark = parachain::RuntimeCall::System( - frame_system::Call::::remark_with_event { remark: vec![1, 2, 3] }, - ); - ParaA::execute_with(|| { - assert_ok!(ParachainPalletXcm::send_xcm( - Here, - (Parent, Parachain(2)), - Xcm(vec![Transact { - origin_kind: OriginKind::SovereignAccount, - require_weight_at_most: Weight::from_parts(INITIAL_BALANCE as u64, 1024 * 1024), - call: remark.encode().into(), - }]), - )); - }); - - ParaB::execute_with(|| { - use parachain::{RuntimeEvent, System}; - assert!(System::events().iter().any(|r| matches!( - r.event, - RuntimeEvent::System(frame_system::Event::Remarked { .. }) - ))); - }); - } - - #[test] - fn reserve_transfer() { - MockNet::reset(); - - let withdraw_amount = 123; - - Relay::execute_with(|| { - assert_ok!(RelayChainPalletXcm::limited_reserve_transfer_assets( - relay_chain::RuntimeOrigin::signed(ALICE), - Box::new(Parachain(1).into()), - Box::new(AccountId32 { network: None, id: ALICE.into() }.into()), - Box::new((Here, withdraw_amount).into()), - 0, - Unlimited, - )); - assert_eq!( - relay_chain::Balances::free_balance(&child_account_id(1)), - INITIAL_BALANCE + withdraw_amount - ); - }); - - ParaA::execute_with(|| { - // free execution, full amount received - assert_eq!( - pallet_balances::Pallet::::free_balance(&ALICE), - INITIAL_BALANCE + withdraw_amount - ); - }); - } - - #[test] - fn remote_locking_and_unlocking() { - MockNet::reset(); - - let locked_amount = 100; - - ParaB::execute_with(|| { - let message = Xcm(vec![LockAsset { - asset: (Here, locked_amount).into(), - unlocker: Parachain(1).into(), - }]); - assert_ok!(ParachainPalletXcm::send_xcm(Here, Parent, message.clone())); - }); - - Relay::execute_with(|| { - use pallet_balances::{BalanceLock, Reasons}; - assert_eq!( - relay_chain::Balances::locks(&child_account_id(2)), - vec![BalanceLock { - id: *b"py/xcmlk", - amount: locked_amount, - reasons: Reasons::All - }] - ); - }); - - ParaA::execute_with(|| { - assert_eq!( - parachain::MsgQueue::received_dmp(), - vec![Xcm(vec![NoteUnlockable { - owner: (Parent, Parachain(2)).into(), - asset: (Parent, locked_amount).into() - }])] - ); - }); - - ParaB::execute_with(|| { - // Request unlocking part of the funds on the relay chain - let message = Xcm(vec![RequestUnlock { - asset: (Parent, locked_amount - 50).into(), - locker: Parent.into(), - }]); - assert_ok!(ParachainPalletXcm::send_xcm(Here, (Parent, Parachain(1)), message)); - }); - - Relay::execute_with(|| { - use pallet_balances::{BalanceLock, Reasons}; - // Lock is reduced - assert_eq!( - relay_chain::Balances::locks(&child_account_id(2)), - vec![BalanceLock { - id: *b"py/xcmlk", - amount: locked_amount - 50, - reasons: Reasons::All - }] - ); - }); - } - - /// Scenario: - /// A parachain transfers an NFT resident on the relay chain to another parachain account. - /// - /// Asserts that the parachain accounts are updated as expected. - #[test] - fn withdraw_and_deposit_nft() { - MockNet::reset(); - - Relay::execute_with(|| { - assert_eq!(relay_chain::Uniques::owner(1, 42), Some(child_account_id(1))); - }); - - ParaA::execute_with(|| { - let message = Xcm(vec![TransferAsset { - assets: (GeneralIndex(1), 42u32).into(), - beneficiary: Parachain(2).into(), - }]); - // Send withdraw and deposit - assert_ok!(ParachainPalletXcm::send_xcm(Here, Parent, message)); - }); - - Relay::execute_with(|| { - assert_eq!(relay_chain::Uniques::owner(1, 42), Some(child_account_id(2))); - }); - } - - /// Scenario: - /// The relay-chain teleports an NFT to a parachain. - /// - /// Asserts that the parachain accounts are updated as expected. - #[test] - fn teleport_nft() { - MockNet::reset(); - - Relay::execute_with(|| { - // Mint the NFT (1, 69) and give it to our "parachain#1 alias". - assert_ok!(relay_chain::Uniques::mint( - relay_chain::RuntimeOrigin::signed(ALICE), - 1, - 69, - child_account_account_id(1, ALICE), - )); - // The parachain#1 alias of Alice is what must hold it on the Relay-chain for it to be - // withdrawable by Alice on the parachain. - assert_eq!( - relay_chain::Uniques::owner(1, 69), - Some(child_account_account_id(1, ALICE)) - ); - }); - ParaA::execute_with(|| { - assert_ok!(parachain::ForeignUniques::force_create( - parachain::RuntimeOrigin::root(), - (Parent, GeneralIndex(1)).into(), - ALICE, - false, - )); - assert_eq!( - parachain::ForeignUniques::owner((Parent, GeneralIndex(1)).into(), 69u32.into()), - None, - ); - assert_eq!(parachain::Balances::reserved_balance(&ALICE), 0); - - // IRL Alice would probably just execute this locally on the Relay-chain, but we can't - // easily do that here since we only send between chains. - let message = Xcm(vec![ - WithdrawAsset((GeneralIndex(1), 69u32).into()), - InitiateTeleport { - assets: AllCounted(1).into(), - dest: Parachain(1).into(), - xcm: Xcm(vec![DepositAsset { - assets: AllCounted(1).into(), - beneficiary: (AccountId32 { id: ALICE.into(), network: None },).into(), - }]), - }, - ]); - // Send teleport - let alice = AccountId32 { id: ALICE.into(), network: None }; - assert_ok!(ParachainPalletXcm::send_xcm(alice, Parent, message)); - }); - ParaA::execute_with(|| { - assert_eq!( - parachain::ForeignUniques::owner((Parent, GeneralIndex(1)).into(), 69u32.into()), - Some(ALICE), - ); - assert_eq!(parachain::Balances::reserved_balance(&ALICE), 1000); - }); - Relay::execute_with(|| { - assert_eq!(relay_chain::Uniques::owner(1, 69), None); - }); - } - - /// Scenario: - /// The relay-chain transfers an NFT into a parachain's sovereign account, who then mints a - /// trustless-backed-derived locally. - /// - /// Asserts that the parachain accounts are updated as expected. - #[test] - fn reserve_asset_transfer_nft() { - sp_tracing::init_for_tests(); - MockNet::reset(); - - Relay::execute_with(|| { - assert_ok!(relay_chain::Uniques::force_create( - relay_chain::RuntimeOrigin::root(), - 2, - ALICE, - false - )); - assert_ok!(relay_chain::Uniques::mint( - relay_chain::RuntimeOrigin::signed(ALICE), - 2, - 69, - child_account_account_id(1, ALICE) - )); - assert_eq!( - relay_chain::Uniques::owner(2, 69), - Some(child_account_account_id(1, ALICE)) - ); - }); - ParaA::execute_with(|| { - assert_ok!(parachain::ForeignUniques::force_create( - parachain::RuntimeOrigin::root(), - (Parent, GeneralIndex(2)).into(), - ALICE, - false, - )); - assert_eq!( - parachain::ForeignUniques::owner((Parent, GeneralIndex(2)).into(), 69u32.into()), - None, - ); - assert_eq!(parachain::Balances::reserved_balance(&ALICE), 0); - - let message = Xcm(vec![ - WithdrawAsset((GeneralIndex(2), 69u32).into()), - DepositReserveAsset { - assets: AllCounted(1).into(), - dest: Parachain(1).into(), - xcm: Xcm(vec![DepositAsset { - assets: AllCounted(1).into(), - beneficiary: (AccountId32 { id: ALICE.into(), network: None },).into(), - }]), - }, - ]); - // Send transfer - let alice = AccountId32 { id: ALICE.into(), network: None }; - assert_ok!(ParachainPalletXcm::send_xcm(alice, Parent, message)); - }); - ParaA::execute_with(|| { - log::debug!(target: "xcm-executor", "Hello"); - assert_eq!( - parachain::ForeignUniques::owner((Parent, GeneralIndex(2)).into(), 69u32.into()), - Some(ALICE), - ); - assert_eq!(parachain::Balances::reserved_balance(&ALICE), 1000); - }); - - Relay::execute_with(|| { - assert_eq!(relay_chain::Uniques::owner(2, 69), Some(child_account_id(1))); - }); - } - - /// Scenario: - /// The relay-chain creates an asset class on a parachain and then Alice transfers her NFT into - /// that parachain's sovereign account, who then mints a trustless-backed-derivative locally. - /// - /// Asserts that the parachain accounts are updated as expected. - #[test] - fn reserve_asset_class_create_and_reserve_transfer() { - MockNet::reset(); - - Relay::execute_with(|| { - assert_ok!(relay_chain::Uniques::force_create( - relay_chain::RuntimeOrigin::root(), - 2, - ALICE, - false - )); - assert_ok!(relay_chain::Uniques::mint( - relay_chain::RuntimeOrigin::signed(ALICE), - 2, - 69, - child_account_account_id(1, ALICE) - )); - assert_eq!( - relay_chain::Uniques::owner(2, 69), - Some(child_account_account_id(1, ALICE)) - ); - - let message = Xcm(vec![Transact { - origin_kind: OriginKind::Xcm, - require_weight_at_most: Weight::from_parts(1_000_000_000, 1024 * 1024), - call: parachain::RuntimeCall::from( - pallet_uniques::Call::::create { - collection: (Parent, 2u64).into(), - admin: parent_account_id(), - }, - ) - .encode() - .into(), - }]); - // Send creation. - assert_ok!(RelayChainPalletXcm::send_xcm(Here, Parachain(1), message)); - }); - ParaA::execute_with(|| { - // Then transfer - let message = Xcm(vec![ - WithdrawAsset((GeneralIndex(2), 69u32).into()), - DepositReserveAsset { - assets: AllCounted(1).into(), - dest: Parachain(1).into(), - xcm: Xcm(vec![DepositAsset { - assets: AllCounted(1).into(), - beneficiary: (AccountId32 { id: ALICE.into(), network: None },).into(), - }]), - }, - ]); - let alice = AccountId32 { id: ALICE.into(), network: None }; - assert_ok!(ParachainPalletXcm::send_xcm(alice, Parent, message)); - }); - ParaA::execute_with(|| { - assert_eq!(parachain::Balances::reserved_balance(&parent_account_id()), 1000); - assert_eq!( - parachain::ForeignUniques::collection_owner((Parent, 2u64).into()), - Some(parent_account_id()) - ); - }); - } - - /// Scenario: - /// A parachain transfers funds on the relay chain to another parachain account. - /// - /// Asserts that the parachain accounts are updated as expected. - #[test] - fn withdraw_and_deposit() { - MockNet::reset(); - - let send_amount = 10; - - ParaA::execute_with(|| { - let message = Xcm(vec![ - WithdrawAsset((Here, send_amount).into()), - buy_execution((Here, send_amount)), - DepositAsset { assets: AllCounted(1).into(), beneficiary: Parachain(2).into() }, - ]); - // Send withdraw and deposit - assert_ok!(ParachainPalletXcm::send_xcm(Here, Parent, message.clone())); - }); - - Relay::execute_with(|| { - assert_eq!( - relay_chain::Balances::free_balance(child_account_id(1)), - INITIAL_BALANCE - send_amount - ); - assert_eq!( - relay_chain::Balances::free_balance(child_account_id(2)), - INITIAL_BALANCE + send_amount - ); - }); - } - - /// Scenario: - /// A parachain wants to be notified that a transfer worked correctly. - /// It sends a `QueryHolding` after the deposit to get notified on success. - /// - /// Asserts that the balances are updated correctly and the expected XCM is sent. - #[test] - fn query_holding() { - MockNet::reset(); - - let send_amount = 10; - let query_id_set = 1234; - - // Send a message which fully succeeds on the relay chain - ParaA::execute_with(|| { - let message = Xcm(vec![ - WithdrawAsset((Here, send_amount).into()), - buy_execution((Here, send_amount)), - DepositAsset { assets: AllCounted(1).into(), beneficiary: Parachain(2).into() }, - ReportHolding { - response_info: QueryResponseInfo { - destination: Parachain(1).into(), - query_id: query_id_set, - max_weight: Weight::from_parts(1_000_000_000, 1024 * 1024), - }, - assets: All.into(), - }, - ]); - // Send withdraw and deposit with query holding - assert_ok!(ParachainPalletXcm::send_xcm(Here, Parent, message.clone(),)); - }); - - // Check that transfer was executed - Relay::execute_with(|| { - // Withdraw executed - assert_eq!( - relay_chain::Balances::free_balance(child_account_id(1)), - INITIAL_BALANCE - send_amount - ); - // Deposit executed - assert_eq!( - relay_chain::Balances::free_balance(child_account_id(2)), - INITIAL_BALANCE + send_amount - ); - }); - - // Check that QueryResponse message was received - ParaA::execute_with(|| { - assert_eq!( - parachain::MsgQueue::received_dmp(), - vec![Xcm(vec![QueryResponse { - query_id: query_id_set, - response: Response::Assets(Assets::new()), - max_weight: Weight::from_parts(1_000_000_000, 1024 * 1024), - querier: Some(Here.into()), - }])], - ); - }); - } -} diff --git a/polkadot/xcm/xcm-simulator/example/src/parachain.rs b/polkadot/xcm/xcm-simulator/example/src/parachain.rs deleted file mode 100644 index 86401d756af3b7d86c34e394ae89c677684c0fb8..0000000000000000000000000000000000000000 --- a/polkadot/xcm/xcm-simulator/example/src/parachain.rs +++ /dev/null @@ -1,470 +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 . - -//! Parachain runtime mock. - -use codec::{Decode, Encode}; -use core::marker::PhantomData; -use frame_support::{ - construct_runtime, derive_impl, parameter_types, - traits::{ContainsPair, EnsureOrigin, EnsureOriginWithArg, Everything, EverythingBut, Nothing}, - weights::{constants::WEIGHT_REF_TIME_PER_SECOND, Weight}, -}; - -use frame_system::EnsureRoot; -use sp_core::{ConstU32, H256}; -use sp_runtime::{ - traits::{Get, Hash, IdentityLookup}, - AccountId32, -}; -use sp_std::prelude::*; - -use pallet_xcm::XcmPassthrough; -use polkadot_core_primitives::BlockNumber as RelayBlockNumber; -use polkadot_parachain_primitives::primitives::{ - DmpMessageHandler, Id as ParaId, Sibling, XcmpMessageFormat, XcmpMessageHandler, -}; -use xcm::{latest::prelude::*, VersionedXcm}; -use xcm_builder::{ - Account32Hash, AccountId32Aliases, AllowUnpaidExecutionFrom, ConvertedConcreteId, - EnsureXcmOrigin, FixedRateOfFungible, FixedWeightBounds, FrameTransactionalProcessor, - FungibleAdapter, IsConcrete, NativeAsset, NoChecking, NonFungiblesAdapter, ParentIsPreset, - SiblingParachainConvertsVia, SignedAccountId32AsNative, SignedToAccountId32, - SovereignSignedViaLocation, -}; -use xcm_executor::{ - traits::{ConvertLocation, JustTry}, - Config, XcmExecutor, -}; - -pub type SovereignAccountOf = ( - SiblingParachainConvertsVia, - AccountId32Aliases, - ParentIsPreset, -); - -pub type AccountId = AccountId32; -pub type Balance = u128; - -parameter_types! { - pub const BlockHashCount: u64 = 250; -} - -#[derive_impl(frame_system::config_preludes::TestDefaultConfig)] -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 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! { - pub ExistentialDeposit: Balance = 1; - pub const MaxLocks: u32 = 50; - pub const MaxReserves: u32 = 50; -} - -impl pallet_balances::Config for Runtime { - type MaxLocks = MaxLocks; - type Balance = Balance; - type RuntimeEvent = RuntimeEvent; - type DustRemoval = (); - type ExistentialDeposit = ExistentialDeposit; - type AccountStore = System; - type WeightInfo = (); - type MaxReserves = MaxReserves; - type ReserveIdentifier = [u8; 8]; - type RuntimeHoldReason = RuntimeHoldReason; - type RuntimeFreezeReason = RuntimeFreezeReason; - type FreezeIdentifier = (); - type MaxFreezes = ConstU32<0>; -} - -#[cfg(feature = "runtime-benchmarks")] -pub struct UniquesHelper; -#[cfg(feature = "runtime-benchmarks")] -impl pallet_uniques::BenchmarkHelper for UniquesHelper { - fn collection(i: u16) -> Location { - GeneralIndex(i as u128).into() - } - fn item(i: u16) -> AssetInstance { - AssetInstance::Index(i as u128) - } -} - -impl pallet_uniques::Config for Runtime { - type RuntimeEvent = RuntimeEvent; - type CollectionId = Location; - type ItemId = AssetInstance; - type Currency = Balances; - type CreateOrigin = ForeignCreators; - type ForceOrigin = frame_system::EnsureRoot; - type CollectionDeposit = frame_support::traits::ConstU128<1_000>; - type ItemDeposit = frame_support::traits::ConstU128<1_000>; - type MetadataDepositBase = frame_support::traits::ConstU128<1_000>; - type AttributeDepositBase = frame_support::traits::ConstU128<1_000>; - type DepositPerByte = frame_support::traits::ConstU128<1>; - type StringLimit = ConstU32<64>; - type KeyLimit = ConstU32<64>; - type ValueLimit = ConstU32<128>; - type Locker = (); - type WeightInfo = (); - #[cfg(feature = "runtime-benchmarks")] - type Helper = UniquesHelper; -} - -// `EnsureOriginWithArg` impl for `CreateOrigin` which allows only XCM origins -// which are locations containing the class location. -pub struct ForeignCreators; -impl EnsureOriginWithArg for ForeignCreators { - type Success = AccountId; - - fn try_origin( - o: RuntimeOrigin, - a: &Location, - ) -> sp_std::result::Result { - let origin_location = pallet_xcm::EnsureXcm::::try_origin(o.clone())?; - if !a.starts_with(&origin_location) { - return Err(o) - } - SovereignAccountOf::convert_location(&origin_location).ok_or(o) - } - - #[cfg(feature = "runtime-benchmarks")] - fn try_successful_origin(a: &Location) -> Result { - Ok(pallet_xcm::Origin::Xcm(a.clone()).into()) - } -} - -parameter_types! { - pub const ReservedXcmpWeight: Weight = Weight::from_parts(WEIGHT_REF_TIME_PER_SECOND.saturating_div(4), 0); - pub const ReservedDmpWeight: Weight = Weight::from_parts(WEIGHT_REF_TIME_PER_SECOND.saturating_div(4), 0); -} - -parameter_types! { - pub const KsmLocation: Location = Location::parent(); - pub const RelayNetwork: NetworkId = NetworkId::Kusama; - pub UniversalLocation: InteriorLocation = Parachain(MsgQueue::parachain_id().into()).into(); -} - -pub type LocationToAccountId = ( - ParentIsPreset, - SiblingParachainConvertsVia, - AccountId32Aliases, - Account32Hash<(), AccountId>, -); - -pub type XcmOriginToCallOrigin = ( - SovereignSignedViaLocation, - SignedAccountId32AsNative, - XcmPassthrough, -); - -parameter_types! { - pub const UnitWeightCost: Weight = Weight::from_parts(1, 1); - pub KsmPerSecondPerByte: (AssetId, u128, u128) = (AssetId(Parent.into()), 1, 1); - pub const MaxInstructions: u32 = 100; - pub const MaxAssetsIntoHolding: u32 = 64; - pub ForeignPrefix: Location = (Parent,).into(); -} - -pub type LocalAssetTransactor = ( - FungibleAdapter, LocationToAccountId, AccountId, ()>, - NonFungiblesAdapter< - ForeignUniques, - ConvertedConcreteId, - SovereignAccountOf, - AccountId, - NoChecking, - (), - >, -); - -pub type XcmRouter = super::ParachainXcmRouter; -pub type Barrier = AllowUnpaidExecutionFrom; - -parameter_types! { - pub NftCollectionOne: AssetFilter - = Wild(AllOf { fun: WildNonFungible, id: AssetId((Parent, GeneralIndex(1)).into()) }); - pub NftCollectionOneForRelay: (AssetFilter, Location) - = (NftCollectionOne::get(), (Parent,).into()); -} -pub type TrustedTeleporters = xcm_builder::Case; -pub type TrustedReserves = EverythingBut>; - -pub struct XcmConfig; -impl Config for XcmConfig { - type RuntimeCall = RuntimeCall; - type XcmSender = XcmRouter; - type AssetTransactor = LocalAssetTransactor; - type OriginConverter = XcmOriginToCallOrigin; - type IsReserve = (NativeAsset, TrustedReserves); - type IsTeleporter = TrustedTeleporters; - type UniversalLocation = UniversalLocation; - type Barrier = Barrier; - type Weigher = FixedWeightBounds; - type Trader = FixedRateOfFungible; - type ResponseHandler = (); - type AssetTrap = (); - type AssetLocker = PolkadotXcm; - type AssetExchanger = (); - type AssetClaims = (); - type SubscriptionService = (); - type PalletInstancesInfo = (); - type FeeManager = (); - type MaxAssetsIntoHolding = MaxAssetsIntoHolding; - type MessageExporter = (); - type UniversalAliases = Nothing; - type CallDispatcher = RuntimeCall; - type SafeCallFilter = Everything; - type Aliasers = Nothing; - type TransactionalProcessor = FrameTransactionalProcessor; - type HrmpNewChannelOpenRequestHandler = (); - type HrmpChannelAcceptedHandler = (); - type HrmpChannelClosingHandler = (); -} - -#[frame_support::pallet] -pub mod mock_msg_queue { - use super::*; - use frame_support::pallet_prelude::*; - - #[pallet::config] - pub trait Config: frame_system::Config { - type RuntimeEvent: From> + IsType<::RuntimeEvent>; - type XcmExecutor: ExecuteXcm; - } - - #[pallet::call] - impl Pallet {} - - #[pallet::pallet] - #[pallet::without_storage_info] - pub struct Pallet(_); - - #[pallet::storage] - #[pallet::getter(fn parachain_id)] - pub(super) type ParachainId = StorageValue<_, ParaId, ValueQuery>; - - #[pallet::storage] - #[pallet::getter(fn received_dmp)] - /// A queue of received DMP messages - pub(super) type ReceivedDmp = StorageValue<_, Vec>, ValueQuery>; - - impl Get for Pallet { - fn get() -> ParaId { - Self::parachain_id() - } - } - - pub type MessageId = [u8; 32]; - - #[pallet::event] - #[pallet::generate_deposit(pub(super) fn deposit_event)] - pub enum Event { - // XCMP - /// Some XCM was executed OK. - Success(Option), - /// Some XCM failed. - Fail(Option, XcmError), - /// Bad XCM version used. - BadVersion(Option), - /// Bad XCM format used. - BadFormat(Option), - - // DMP - /// Downward message is invalid XCM. - InvalidFormat(MessageId), - /// Downward message is unsupported version of XCM. - UnsupportedVersion(MessageId), - /// Downward message executed with the given outcome. - ExecutedDownward(MessageId, Outcome), - } - - impl Pallet { - pub fn set_para_id(para_id: ParaId) { - ParachainId::::put(para_id); - } - - fn handle_xcmp_message( - sender: ParaId, - _sent_at: RelayBlockNumber, - xcm: VersionedXcm, - max_weight: Weight, - ) -> Result { - let hash = Encode::using_encoded(&xcm, T::Hashing::hash); - let mut message_hash = Encode::using_encoded(&xcm, sp_io::hashing::blake2_256); - let (result, event) = match Xcm::::try_from(xcm) { - Ok(xcm) => { - let location = (Parent, Parachain(sender.into())); - match T::XcmExecutor::prepare_and_execute( - location, - xcm, - &mut message_hash, - max_weight, - Weight::zero(), - ) { - Outcome::Error { error } => (Err(error), Event::Fail(Some(hash), error)), - Outcome::Complete { used } => (Ok(used), Event::Success(Some(hash))), - // As far as the caller is concerned, this was dispatched without error, so - // we just report the weight used. - Outcome::Incomplete { used, error } => - (Ok(used), Event::Fail(Some(hash), error)), - } - }, - Err(()) => (Err(XcmError::UnhandledXcmVersion), Event::BadVersion(Some(hash))), - }; - Self::deposit_event(event); - result - } - } - - impl XcmpMessageHandler for Pallet { - fn handle_xcmp_messages<'a, I: Iterator>( - iter: I, - max_weight: Weight, - ) -> Weight { - for (sender, sent_at, data) in iter { - let mut data_ref = data; - let _ = XcmpMessageFormat::decode(&mut data_ref) - .expect("Simulator encodes with versioned xcm format; qed"); - - let mut remaining_fragments = data_ref; - while !remaining_fragments.is_empty() { - if let Ok(xcm) = - VersionedXcm::::decode(&mut remaining_fragments) - { - let _ = Self::handle_xcmp_message(sender, sent_at, xcm, max_weight); - } else { - debug_assert!(false, "Invalid incoming XCMP message data"); - } - } - } - max_weight - } - } - - impl DmpMessageHandler for Pallet { - fn handle_dmp_messages( - iter: impl Iterator)>, - limit: Weight, - ) -> Weight { - for (_i, (_sent_at, data)) in iter.enumerate() { - let mut id = sp_io::hashing::blake2_256(&data[..]); - let maybe_versioned = VersionedXcm::::decode(&mut &data[..]); - match maybe_versioned { - Err(_) => { - Self::deposit_event(Event::InvalidFormat(id)); - }, - Ok(versioned) => match Xcm::try_from(versioned) { - Err(()) => Self::deposit_event(Event::UnsupportedVersion(id)), - Ok(x) => { - let outcome = T::XcmExecutor::prepare_and_execute( - Parent, - x.clone(), - &mut id, - limit, - Weight::zero(), - ); - >::append(x); - Self::deposit_event(Event::ExecutedDownward(id, outcome)); - }, - }, - } - } - limit - } - } -} - -impl mock_msg_queue::Config for Runtime { - type RuntimeEvent = RuntimeEvent; - type XcmExecutor = XcmExecutor; -} - -pub type LocalOriginToLocation = SignedToAccountId32; - -pub struct TrustedLockerCase(PhantomData); -impl> ContainsPair for TrustedLockerCase { - fn contains(origin: &Location, asset: &Asset) -> bool { - let (o, a) = T::get(); - a.matches(asset) && &o == origin - } -} - -parameter_types! { - pub RelayTokenForRelay: (Location, AssetFilter) = (Parent.into(), Wild(AllOf { id: AssetId(Parent.into()), fun: WildFungible })); -} - -pub type TrustedLockers = TrustedLockerCase; - -impl pallet_xcm::Config for Runtime { - type RuntimeEvent = RuntimeEvent; - type SendXcmOrigin = EnsureXcmOrigin; - type XcmRouter = XcmRouter; - type ExecuteXcmOrigin = EnsureXcmOrigin; - type XcmExecuteFilter = Everything; - type XcmExecutor = XcmExecutor; - type XcmTeleportFilter = Nothing; - type XcmReserveTransferFilter = Everything; - type Weigher = FixedWeightBounds; - type UniversalLocation = UniversalLocation; - type RuntimeOrigin = RuntimeOrigin; - type RuntimeCall = RuntimeCall; - const VERSION_DISCOVERY_QUEUE_SIZE: u32 = 100; - type AdvertisedXcmVersion = pallet_xcm::CurrentXcmVersion; - type Currency = Balances; - type CurrencyMatcher = (); - type TrustedLockers = TrustedLockers; - type SovereignAccountOf = LocationToAccountId; - type MaxLockers = ConstU32<8>; - type MaxRemoteLockConsumers = ConstU32<0>; - type RemoteLockConsumerIdentifier = (); - type WeightInfo = pallet_xcm::TestWeightInfo; - type AdminOrigin = EnsureRoot; -} - -type Block = frame_system::mocking::MockBlock; - -construct_runtime!( - pub enum Runtime - { - System: frame_system, - Balances: pallet_balances, - MsgQueue: mock_msg_queue, - PolkadotXcm: pallet_xcm, - ForeignUniques: pallet_uniques, - } -); diff --git a/polkadot/xcm/xcm-simulator/example/src/parachain/mod.rs b/polkadot/xcm/xcm-simulator/example/src/parachain/mod.rs new file mode 100644 index 0000000000000000000000000000000000000000..93c8302757cb061bc1f97d003ce8b7de2374448e --- /dev/null +++ b/polkadot/xcm/xcm-simulator/example/src/parachain/mod.rs @@ -0,0 +1,182 @@ +// 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 . + +//! Parachain runtime mock. + +mod xcm_config; +pub use xcm_config::*; + +use core::marker::PhantomData; +use frame_support::{ + construct_runtime, derive_impl, parameter_types, + traits::{ConstU128, ContainsPair, EnsureOrigin, EnsureOriginWithArg, Everything, Nothing}, + weights::{constants::WEIGHT_REF_TIME_PER_SECOND, Weight}, +}; +use frame_system::EnsureRoot; +use sp_core::ConstU32; +use sp_runtime::{ + traits::{Get, IdentityLookup}, + AccountId32, +}; +use sp_std::prelude::*; +use xcm::latest::prelude::*; +use xcm_builder::{EnsureXcmOrigin, SignedToAccountId32}; +use xcm_executor::{traits::ConvertLocation, XcmExecutor}; +use xcm_simulator::mock_message_queue; + +pub type AccountId = AccountId32; +pub type Balance = u128; + +parameter_types! { + pub const BlockHashCount: u64 = 250; +} + +#[derive_impl(frame_system::config_preludes::TestDefaultConfig)] +impl frame_system::Config for Runtime { + type AccountId = AccountId; + type Lookup = IdentityLookup; + type Block = Block; + type AccountData = pallet_balances::AccountData; +} + +#[derive_impl(pallet_balances::config_preludes::TestDefaultConfig)] +impl pallet_balances::Config for Runtime { + type Balance = Balance; + type ExistentialDeposit = ConstU128<1>; + type AccountStore = System; +} + +#[cfg(feature = "runtime-benchmarks")] +pub struct UniquesHelper; +#[cfg(feature = "runtime-benchmarks")] +impl pallet_uniques::BenchmarkHelper for UniquesHelper { + fn collection(i: u16) -> Location { + GeneralIndex(i as u128).into() + } + fn item(i: u16) -> AssetInstance { + AssetInstance::Index(i as u128) + } +} + +impl pallet_uniques::Config for Runtime { + type RuntimeEvent = RuntimeEvent; + type CollectionId = Location; + type ItemId = AssetInstance; + type Currency = Balances; + type CreateOrigin = ForeignCreators; + type ForceOrigin = frame_system::EnsureRoot; + type CollectionDeposit = frame_support::traits::ConstU128<1_000>; + type ItemDeposit = frame_support::traits::ConstU128<1_000>; + type MetadataDepositBase = frame_support::traits::ConstU128<1_000>; + type AttributeDepositBase = frame_support::traits::ConstU128<1_000>; + type DepositPerByte = frame_support::traits::ConstU128<1>; + type StringLimit = ConstU32<64>; + type KeyLimit = ConstU32<64>; + type ValueLimit = ConstU32<128>; + type Locker = (); + type WeightInfo = (); + #[cfg(feature = "runtime-benchmarks")] + type Helper = UniquesHelper; +} + +// `EnsureOriginWithArg` impl for `CreateOrigin` which allows only XCM origins +// which are locations containing the class location. +pub struct ForeignCreators; +impl EnsureOriginWithArg for ForeignCreators { + type Success = AccountId; + + fn try_origin( + o: RuntimeOrigin, + a: &Location, + ) -> sp_std::result::Result { + let origin_location = pallet_xcm::EnsureXcm::::try_origin(o.clone())?; + if !a.starts_with(&origin_location) { + return Err(o); + } + xcm_config::location_converter::LocationConverter::convert_location(&origin_location) + .ok_or(o) + } + + #[cfg(feature = "runtime-benchmarks")] + fn try_successful_origin(a: &Location) -> Result { + Ok(pallet_xcm::Origin::Xcm(a.clone()).into()) + } +} + +parameter_types! { + pub const ReservedXcmpWeight: Weight = Weight::from_parts(WEIGHT_REF_TIME_PER_SECOND.saturating_div(4), 0); + pub const ReservedDmpWeight: Weight = Weight::from_parts(WEIGHT_REF_TIME_PER_SECOND.saturating_div(4), 0); +} + +impl mock_message_queue::Config for Runtime { + type RuntimeEvent = RuntimeEvent; + type XcmExecutor = XcmExecutor; +} + +pub type LocalOriginToLocation = + SignedToAccountId32; + +pub struct TrustedLockerCase(PhantomData); +impl> ContainsPair for TrustedLockerCase { + fn contains(origin: &Location, asset: &Asset) -> bool { + let (o, a) = T::get(); + a.matches(asset) && &o == origin + } +} + +parameter_types! { + pub RelayTokenForRelay: (Location, AssetFilter) = (Parent.into(), Wild(AllOf { id: AssetId(Parent.into()), fun: WildFungible })); +} + +pub type TrustedLockers = TrustedLockerCase; + +impl pallet_xcm::Config for Runtime { + type RuntimeEvent = RuntimeEvent; + type SendXcmOrigin = EnsureXcmOrigin; + type XcmRouter = XcmRouter; + type ExecuteXcmOrigin = EnsureXcmOrigin; + type XcmExecuteFilter = Everything; + type XcmExecutor = XcmExecutor; + type XcmTeleportFilter = Nothing; + type XcmReserveTransferFilter = Everything; + type Weigher = weigher::Weigher; + type UniversalLocation = constants::UniversalLocation; + type RuntimeOrigin = RuntimeOrigin; + type RuntimeCall = RuntimeCall; + const VERSION_DISCOVERY_QUEUE_SIZE: u32 = 100; + type AdvertisedXcmVersion = pallet_xcm::CurrentXcmVersion; + type Currency = Balances; + type CurrencyMatcher = (); + type TrustedLockers = TrustedLockers; + type SovereignAccountOf = location_converter::LocationConverter; + type MaxLockers = ConstU32<8>; + type MaxRemoteLockConsumers = ConstU32<0>; + type RemoteLockConsumerIdentifier = (); + type WeightInfo = pallet_xcm::TestWeightInfo; + type AdminOrigin = EnsureRoot; +} + +type Block = frame_system::mocking::MockBlock; + +construct_runtime!( + pub struct Runtime { + System: frame_system, + Balances: pallet_balances, + MsgQueue: mock_message_queue, + PolkadotXcm: pallet_xcm, + ForeignUniques: pallet_uniques, + } +); diff --git a/polkadot/xcm/xcm-simulator/example/src/parachain/xcm_config/asset_transactor.rs b/polkadot/xcm/xcm-simulator/example/src/parachain/xcm_config/asset_transactor.rs new file mode 100644 index 0000000000000000000000000000000000000000..25cffcf8cef25e96983903f324985b10a70ab496 --- /dev/null +++ b/polkadot/xcm/xcm-simulator/example/src/parachain/xcm_config/asset_transactor.rs @@ -0,0 +1,39 @@ +// 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 crate::parachain::{ + constants::KsmLocation, location_converter::LocationConverter, AccountId, Balances, + ForeignUniques, +}; +use xcm::latest::prelude::*; +use xcm_builder::{ + ConvertedConcreteId, FungibleAdapter, IsConcrete, NoChecking, NonFungiblesAdapter, +}; +use xcm_executor::traits::JustTry; + +type LocalAssetTransactor = ( + FungibleAdapter, LocationConverter, AccountId, ()>, + NonFungiblesAdapter< + ForeignUniques, + ConvertedConcreteId, + LocationConverter, + AccountId, + NoChecking, + (), + >, +); + +pub type AssetTransactor = LocalAssetTransactor; diff --git a/polkadot/xcm/xcm-simulator/example/src/parachain/xcm_config/barrier.rs b/polkadot/xcm/xcm-simulator/example/src/parachain/xcm_config/barrier.rs new file mode 100644 index 0000000000000000000000000000000000000000..1c7aa2c6d32100d5de4cd63870b438c2afc192c5 --- /dev/null +++ b/polkadot/xcm/xcm-simulator/example/src/parachain/xcm_config/barrier.rs @@ -0,0 +1,20 @@ +// Copyright (C) Parity Technologies (UK) Ltd. +// This file is part of Polkadot. + +// Polkadot is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// Polkadot is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with Polkadot. If not, see . + +use frame_support::traits::Everything; +use xcm_builder::AllowUnpaidExecutionFrom; + +pub type Barrier = AllowUnpaidExecutionFrom; diff --git a/polkadot/xcm/xcm-simulator/example/src/parachain/xcm_config/constants.rs b/polkadot/xcm/xcm-simulator/example/src/parachain/xcm_config/constants.rs new file mode 100644 index 0000000000000000000000000000000000000000..0769507ec37b70e5f6d60886c4db7db9a866dc0d --- /dev/null +++ b/polkadot/xcm/xcm-simulator/example/src/parachain/xcm_config/constants.rs @@ -0,0 +1,31 @@ +// 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 crate::parachain::Runtime; +use frame_support::parameter_types; +use xcm::latest::prelude::*; +use xcm_simulator::mock_message_queue::ParachainId; + +parameter_types! { + pub KsmPerSecondPerByte: (AssetId, u128, u128) = (AssetId(Parent.into()), 1, 1); + pub const MaxAssetsIntoHolding: u32 = 64; +} + +parameter_types! { + pub const KsmLocation: Location = Location::parent(); + pub const RelayNetwork: NetworkId = NetworkId::Kusama; + pub UniversalLocation: InteriorLocation = [GlobalConsensus(RelayNetwork::get()), Parachain(ParachainId::::get().into())].into(); +} diff --git a/polkadot/xcm/xcm-simulator/example/src/parachain/xcm_config/location_converter.rs b/polkadot/xcm/xcm-simulator/example/src/parachain/xcm_config/location_converter.rs new file mode 100644 index 0000000000000000000000000000000000000000..5a54414dd13fbc05cdbd150ea1edf0400e992c38 --- /dev/null +++ b/polkadot/xcm/xcm-simulator/example/src/parachain/xcm_config/location_converter.rs @@ -0,0 +1,25 @@ +// 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 crate::parachain::{constants::RelayNetwork, AccountId}; +use xcm_builder::{AccountId32Aliases, DescribeAllTerminal, DescribeFamily, HashedDescription}; + +type LocationToAccountId = ( + HashedDescription>, + AccountId32Aliases, +); + +pub type LocationConverter = LocationToAccountId; diff --git a/polkadot/xcm/xcm-simulator/example/src/parachain/xcm_config/mod.rs b/polkadot/xcm/xcm-simulator/example/src/parachain/xcm_config/mod.rs new file mode 100644 index 0000000000000000000000000000000000000000..a6b55d1bd9be05641db343f2f301ae560e0fea29 --- /dev/null +++ b/polkadot/xcm/xcm-simulator/example/src/parachain/xcm_config/mod.rs @@ -0,0 +1,64 @@ +// 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 . + +pub mod asset_transactor; +pub mod barrier; +pub mod constants; +pub mod location_converter; +pub mod origin_converter; +pub mod reserve; +pub mod teleporter; +pub mod weigher; + +use crate::parachain::{MsgQueue, PolkadotXcm, RuntimeCall}; +use frame_support::traits::{Everything, Nothing}; +use xcm_builder::{EnsureDecodableXcm, FixedRateOfFungible, FrameTransactionalProcessor}; + +// Generated from `decl_test_network!` +pub type XcmRouter = EnsureDecodableXcm>; + +pub struct XcmConfig; +impl xcm_executor::Config for XcmConfig { + type RuntimeCall = RuntimeCall; + type XcmSender = XcmRouter; + type AssetTransactor = asset_transactor::AssetTransactor; + type OriginConverter = origin_converter::OriginConverter; + type IsReserve = reserve::TrustedReserves; + type IsTeleporter = teleporter::TrustedTeleporters; + type UniversalLocation = constants::UniversalLocation; + type Barrier = barrier::Barrier; + type Weigher = weigher::Weigher; + type Trader = FixedRateOfFungible; + type ResponseHandler = (); + type AssetTrap = (); + type AssetLocker = PolkadotXcm; + type AssetExchanger = (); + type AssetClaims = (); + type SubscriptionService = (); + type PalletInstancesInfo = (); + type FeeManager = (); + type MaxAssetsIntoHolding = constants::MaxAssetsIntoHolding; + type MessageExporter = (); + type UniversalAliases = Nothing; + type CallDispatcher = RuntimeCall; + type SafeCallFilter = Everything; + type Aliasers = Nothing; + type TransactionalProcessor = FrameTransactionalProcessor; + type HrmpNewChannelOpenRequestHandler = (); + type HrmpChannelAcceptedHandler = (); + type HrmpChannelClosingHandler = (); + type XcmRecorder = PolkadotXcm; +} diff --git a/polkadot/xcm/xcm-simulator/example/src/parachain/xcm_config/origin_converter.rs b/polkadot/xcm/xcm-simulator/example/src/parachain/xcm_config/origin_converter.rs new file mode 100644 index 0000000000000000000000000000000000000000..5a60f0e6001453c746676024528e9a745282ba66 --- /dev/null +++ b/polkadot/xcm/xcm-simulator/example/src/parachain/xcm_config/origin_converter.rs @@ -0,0 +1,29 @@ +// 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 crate::parachain::{ + constants::RelayNetwork, location_converter::LocationConverter, RuntimeOrigin, +}; +use pallet_xcm::XcmPassthrough; +use xcm_builder::{SignedAccountId32AsNative, SovereignSignedViaLocation}; + +type XcmOriginToCallOrigin = ( + SovereignSignedViaLocation, + SignedAccountId32AsNative, + XcmPassthrough, +); + +pub type OriginConverter = XcmOriginToCallOrigin; diff --git a/polkadot/xcm/xcm-simulator/example/src/parachain/xcm_config/reserve.rs b/polkadot/xcm/xcm-simulator/example/src/parachain/xcm_config/reserve.rs new file mode 100644 index 0000000000000000000000000000000000000000..8763a2f37ccd5b0a1f50bdaa18ef006a7621d145 --- /dev/null +++ b/polkadot/xcm/xcm-simulator/example/src/parachain/xcm_config/reserve.rs @@ -0,0 +1,21 @@ +// 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 crate::parachain::teleporter::TrustedTeleporters; +use frame_support::traits::EverythingBut; +use xcm_builder::NativeAsset; + +pub type TrustedReserves = (NativeAsset, EverythingBut); diff --git a/polkadot/xcm/xcm-simulator/example/src/parachain/xcm_config/teleporter.rs b/polkadot/xcm/xcm-simulator/example/src/parachain/xcm_config/teleporter.rs new file mode 100644 index 0000000000000000000000000000000000000000..41cb7a5eb2de73c5327eefdb29dcbf4d36b99efa --- /dev/null +++ b/polkadot/xcm/xcm-simulator/example/src/parachain/xcm_config/teleporter.rs @@ -0,0 +1,27 @@ +// Copyright (C) Parity Technologies (UK) Ltd. +// This file is part of Polkadot. + +// Polkadot is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// Polkadot is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with Polkadot. If not, see . + +use frame_support::parameter_types; +use xcm::latest::prelude::*; + +parameter_types! { + pub NftCollectionOne: AssetFilter + = Wild(AllOf { fun: WildNonFungible, id: AssetId((Parent, GeneralIndex(1)).into()) }); + pub NftCollectionOneForRelay: (AssetFilter, Location) + = (NftCollectionOne::get(), (Parent,).into()); +} + +pub type TrustedTeleporters = xcm_builder::Case; diff --git a/polkadot/xcm/xcm-simulator/example/src/parachain/xcm_config/weigher.rs b/polkadot/xcm/xcm-simulator/example/src/parachain/xcm_config/weigher.rs new file mode 100644 index 0000000000000000000000000000000000000000..4bdc98ea3b0e6438ddb1a41b22ede6b393a76628 --- /dev/null +++ b/polkadot/xcm/xcm-simulator/example/src/parachain/xcm_config/weigher.rs @@ -0,0 +1,27 @@ +// 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 crate::parachain::RuntimeCall; +use frame_support::parameter_types; +use xcm::latest::prelude::*; +use xcm_builder::FixedWeightBounds; + +parameter_types! { + pub const UnitWeightCost: Weight = Weight::from_parts(1, 1); + pub const MaxInstructions: u32 = 100; +} + +pub type Weigher = FixedWeightBounds; diff --git a/polkadot/xcm/xcm-simulator/example/src/relay_chain.rs b/polkadot/xcm/xcm-simulator/example/src/relay_chain/mod.rs similarity index 52% rename from polkadot/xcm/xcm-simulator/example/src/relay_chain.rs rename to polkadot/xcm/xcm-simulator/example/src/relay_chain/mod.rs index 286d0038e187a45504e9b1092fed4b152ffe9d3d..c843f52d41a97f6e70a2320bb3f60a31a9504b50 100644 --- a/polkadot/xcm/xcm-simulator/example/src/relay_chain.rs +++ b/polkadot/xcm/xcm-simulator/example/src/relay_chain/mod.rs @@ -16,31 +16,29 @@ //! Relay chain runtime mock. +mod xcm_config; +pub use xcm_config::*; + use frame_support::{ construct_runtime, derive_impl, parameter_types, - traits::{AsEnsureOriginWithArg, Everything, Nothing, ProcessMessage, ProcessMessageError}, + traits::{ + AsEnsureOriginWithArg, ConstU128, Everything, Nothing, ProcessMessage, ProcessMessageError, + }, weights::{Weight, WeightMeter}, }; use frame_system::EnsureRoot; -use sp_core::{ConstU32, H256}; +use sp_core::ConstU32; use sp_runtime::{traits::IdentityLookup, AccountId32}; -use polkadot_parachain_primitives::primitives::Id as ParaId; use polkadot_runtime_parachains::{ configuration, inclusion::{AggregateMessageOrigin, UmpQueueId}, origin, shared, }; use xcm::latest::prelude::*; -use xcm_builder::{ - Account32Hash, AccountId32Aliases, AllowUnpaidExecutionFrom, AsPrefixedGeneralIndex, - ChildParachainAsNative, ChildParachainConvertsVia, ChildSystemParachainAsSuperuser, - ConvertedConcreteId, FixedRateOfFungible, FixedWeightBounds, FrameTransactionalProcessor, - FungibleAdapter, IsConcrete, NoChecking, NonFungiblesAdapter, SignedAccountId32AsNative, - SignedToAccountId32, SovereignSignedViaLocation, -}; -use xcm_executor::{traits::JustTry, Config, XcmExecutor}; +use xcm_builder::{IsConcrete, SignedToAccountId32}; +use xcm_executor::XcmExecutor; pub type AccountId = AccountId32; pub type Balance = u128; @@ -51,51 +49,17 @@ parameter_types! { #[derive_impl(frame_system::config_preludes::TestDefaultConfig)] 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 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! { - pub ExistentialDeposit: Balance = 1; - pub const MaxLocks: u32 = 50; - pub const MaxReserves: u32 = 50; } +#[derive_impl(pallet_balances::config_preludes::TestDefaultConfig)] impl pallet_balances::Config for Runtime { - type MaxLocks = MaxLocks; type Balance = Balance; - type RuntimeEvent = RuntimeEvent; - type DustRemoval = (); - type ExistentialDeposit = ExistentialDeposit; + type ExistentialDeposit = ConstU128<1>; type AccountStore = System; - type WeightInfo = (); - type MaxReserves = MaxReserves; - type ReserveIdentifier = [u8; 8]; - type RuntimeHoldReason = RuntimeHoldReason; - type RuntimeFreezeReason = RuntimeFreezeReason; - type FreezeIdentifier = (); - type MaxFreezes = ConstU32<0>; } impl pallet_uniques::Config for Runtime { @@ -127,83 +91,8 @@ impl configuration::Config for Runtime { type WeightInfo = configuration::TestWeightInfo; } -parameter_types! { - pub const TokenLocation: Location = Here.into_location(); - pub RelayNetwork: NetworkId = ByGenesis([0; 32]); - pub const AnyNetwork: Option = None; - pub UniversalLocation: InteriorLocation = Here; - pub UnitWeightCost: u64 = 1_000; -} - -pub type LocationToAccountId = ( - ChildParachainConvertsVia, - AccountId32Aliases, - Account32Hash<(), AccountId>, -); - -pub type LocalAssetTransactor = ( - FungibleAdapter, LocationToAccountId, AccountId, ()>, - NonFungiblesAdapter< - Uniques, - ConvertedConcreteId, JustTry>, - LocationToAccountId, - AccountId, - NoChecking, - (), - >, -); - -type LocalOriginConverter = ( - SovereignSignedViaLocation, - ChildParachainAsNative, - SignedAccountId32AsNative, - ChildSystemParachainAsSuperuser, -); - -parameter_types! { - pub const BaseXcmWeight: Weight = Weight::from_parts(1_000, 1_000); - pub TokensPerSecondPerByte: (AssetId, u128, u128) = - (AssetId(TokenLocation::get()), 1_000_000_000_000, 1024 * 1024); - pub const MaxInstructions: u32 = 100; - pub const MaxAssetsIntoHolding: u32 = 64; -} - -pub type XcmRouter = super::RelayChainXcmRouter; -pub type Barrier = AllowUnpaidExecutionFrom; - -pub struct XcmConfig; -impl Config for XcmConfig { - type RuntimeCall = RuntimeCall; - type XcmSender = XcmRouter; - type AssetTransactor = LocalAssetTransactor; - type OriginConverter = LocalOriginConverter; - type IsReserve = (); - type IsTeleporter = (); - type UniversalLocation = UniversalLocation; - type Barrier = Barrier; - type Weigher = FixedWeightBounds; - type Trader = FixedRateOfFungible; - type ResponseHandler = (); - type AssetTrap = (); - type AssetLocker = XcmPallet; - type AssetExchanger = (); - type AssetClaims = (); - type SubscriptionService = (); - type PalletInstancesInfo = (); - type FeeManager = (); - type MaxAssetsIntoHolding = MaxAssetsIntoHolding; - type MessageExporter = (); - type UniversalAliases = Nothing; - type CallDispatcher = RuntimeCall; - type SafeCallFilter = Everything; - type Aliasers = Nothing; - type TransactionalProcessor = FrameTransactionalProcessor; - type HrmpNewChannelOpenRequestHandler = (); - type HrmpChannelAcceptedHandler = (); - type HrmpChannelClosingHandler = (); -} - -pub type LocalOriginToLocation = SignedToAccountId32; +pub type LocalOriginToLocation = + SignedToAccountId32; impl pallet_xcm::Config for Runtime { type RuntimeEvent = RuntimeEvent; @@ -215,16 +104,16 @@ impl pallet_xcm::Config for Runtime { type XcmExecutor = XcmExecutor; type XcmTeleportFilter = Everything; type XcmReserveTransferFilter = Everything; - type Weigher = FixedWeightBounds; - type UniversalLocation = UniversalLocation; + type Weigher = weigher::Weigher; + type UniversalLocation = constants::UniversalLocation; type RuntimeOrigin = RuntimeOrigin; type RuntimeCall = RuntimeCall; const VERSION_DISCOVERY_QUEUE_SIZE: u32 = 100; type AdvertisedXcmVersion = pallet_xcm::CurrentXcmVersion; type Currency = Balances; - type CurrencyMatcher = IsConcrete; + type CurrencyMatcher = IsConcrete; type TrustedLockers = (); - type SovereignAccountOf = LocationToAccountId; + type SovereignAccountOf = location_converter::LocationConverter; type MaxLockers = ConstU32<8>; type MaxRemoteLockConsumers = ConstU32<0>; type RemoteLockConsumerIdentifier = (); @@ -232,10 +121,6 @@ impl pallet_xcm::Config for Runtime { type AdminOrigin = EnsureRoot; } -parameter_types! { - pub const FirstMessageFactorPercent: u64 = 100; -} - impl origin::Config for Runtime {} type Block = frame_system::mocking::MockBlock; diff --git a/polkadot/xcm/xcm-simulator/example/src/relay_chain/xcm_config/asset_transactor.rs b/polkadot/xcm/xcm-simulator/example/src/relay_chain/xcm_config/asset_transactor.rs new file mode 100644 index 0000000000000000000000000000000000000000..c212569d48113e58fc7447cb077571b35614c46a --- /dev/null +++ b/polkadot/xcm/xcm-simulator/example/src/relay_chain/xcm_config/asset_transactor.rs @@ -0,0 +1,38 @@ +// 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 crate::relay_chain::{ + constants::TokenLocation, location_converter::LocationConverter, AccountId, Balances, Uniques, +}; +use xcm_builder::{ + AsPrefixedGeneralIndex, ConvertedConcreteId, FungibleAdapter, IsConcrete, NoChecking, + NonFungiblesAdapter, +}; +use xcm_executor::traits::JustTry; + +type LocalAssetTransactor = ( + FungibleAdapter, LocationConverter, AccountId, ()>, + NonFungiblesAdapter< + Uniques, + ConvertedConcreteId, JustTry>, + LocationConverter, + AccountId, + NoChecking, + (), + >, +); + +pub type AssetTransactor = LocalAssetTransactor; diff --git a/polkadot/xcm/xcm-simulator/example/src/relay_chain/xcm_config/barrier.rs b/polkadot/xcm/xcm-simulator/example/src/relay_chain/xcm_config/barrier.rs new file mode 100644 index 0000000000000000000000000000000000000000..1c7aa2c6d32100d5de4cd63870b438c2afc192c5 --- /dev/null +++ b/polkadot/xcm/xcm-simulator/example/src/relay_chain/xcm_config/barrier.rs @@ -0,0 +1,20 @@ +// Copyright (C) Parity Technologies (UK) Ltd. +// This file is part of Polkadot. + +// Polkadot is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// Polkadot is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with Polkadot. If not, see . + +use frame_support::traits::Everything; +use xcm_builder::AllowUnpaidExecutionFrom; + +pub type Barrier = AllowUnpaidExecutionFrom; diff --git a/polkadot/xcm/xcm-simulator/example/src/relay_chain/xcm_config/constants.rs b/polkadot/xcm/xcm-simulator/example/src/relay_chain/xcm_config/constants.rs new file mode 100644 index 0000000000000000000000000000000000000000..f590c42990da30d112ef25b39bd022e2e376683f --- /dev/null +++ b/polkadot/xcm/xcm-simulator/example/src/relay_chain/xcm_config/constants.rs @@ -0,0 +1,31 @@ +// Copyright (C) Parity Technologies (UK) Ltd. +// This file is part of Polkadot. + +// Polkadot is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// Polkadot is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with Polkadot. If not, see . + +use frame_support::parameter_types; +use xcm::latest::prelude::*; + +parameter_types! { + pub TokensPerSecondPerByte: (AssetId, u128, u128) = + (AssetId(TokenLocation::get()), 1_000_000_000_000, 1024 * 1024); + pub const MaxAssetsIntoHolding: u32 = 64; +} + +parameter_types! { + pub const TokenLocation: Location = Here.into_location(); + pub RelayNetwork: NetworkId = ByGenesis([0; 32]); + pub UniversalLocation: InteriorLocation = RelayNetwork::get().into(); + pub UnitWeightCost: u64 = 1_000; +} diff --git a/polkadot/xcm/xcm-simulator/example/src/relay_chain/xcm_config/location_converter.rs b/polkadot/xcm/xcm-simulator/example/src/relay_chain/xcm_config/location_converter.rs new file mode 100644 index 0000000000000000000000000000000000000000..0f5f4e43dc9706b84ad11e2de01101ad25559069 --- /dev/null +++ b/polkadot/xcm/xcm-simulator/example/src/relay_chain/xcm_config/location_converter.rs @@ -0,0 +1,25 @@ +// 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 crate::relay_chain::{constants::RelayNetwork, AccountId}; +use xcm_builder::{AccountId32Aliases, DescribeAllTerminal, DescribeFamily, HashedDescription}; + +type LocationToAccountId = ( + HashedDescription>, + AccountId32Aliases, +); + +pub type LocationConverter = LocationToAccountId; diff --git a/polkadot/xcm/xcm-simulator/example/src/relay_chain/xcm_config/mod.rs b/polkadot/xcm/xcm-simulator/example/src/relay_chain/xcm_config/mod.rs new file mode 100644 index 0000000000000000000000000000000000000000..c5d5fa66732b939b9a03e1da2cf9c658c4e61acb --- /dev/null +++ b/polkadot/xcm/xcm-simulator/example/src/relay_chain/xcm_config/mod.rs @@ -0,0 +1,63 @@ +// 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 . + +pub mod asset_transactor; +pub mod barrier; +pub mod constants; +pub mod location_converter; +pub mod origin_converter; +pub mod weigher; + +use crate::relay_chain::{RuntimeCall, XcmPallet}; +use frame_support::traits::{Everything, Nothing}; +use xcm_builder::{EnsureDecodableXcm, FixedRateOfFungible, FrameTransactionalProcessor}; +use xcm_executor::Config; + +// Generated from `decl_test_network!` +pub type XcmRouter = EnsureDecodableXcm; + +pub struct XcmConfig; +impl Config for XcmConfig { + type RuntimeCall = RuntimeCall; + type XcmSender = XcmRouter; + type AssetTransactor = asset_transactor::AssetTransactor; + type OriginConverter = origin_converter::OriginConverter; + type IsReserve = (); + type IsTeleporter = (); + type UniversalLocation = constants::UniversalLocation; + type Barrier = barrier::Barrier; + type Weigher = weigher::Weigher; + type Trader = FixedRateOfFungible; + type ResponseHandler = (); + type AssetTrap = (); + type AssetLocker = XcmPallet; + type AssetExchanger = (); + type AssetClaims = (); + type SubscriptionService = (); + type PalletInstancesInfo = (); + type FeeManager = (); + type MaxAssetsIntoHolding = constants::MaxAssetsIntoHolding; + type MessageExporter = (); + type UniversalAliases = Nothing; + type CallDispatcher = RuntimeCall; + type SafeCallFilter = Everything; + type Aliasers = Nothing; + type TransactionalProcessor = FrameTransactionalProcessor; + type HrmpNewChannelOpenRequestHandler = (); + type HrmpChannelAcceptedHandler = (); + type HrmpChannelClosingHandler = (); + type XcmRecorder = XcmPallet; +} diff --git a/polkadot/xcm/xcm-simulator/example/src/relay_chain/xcm_config/origin_converter.rs b/polkadot/xcm/xcm-simulator/example/src/relay_chain/xcm_config/origin_converter.rs new file mode 100644 index 0000000000000000000000000000000000000000..3c79912a926231bf08d4605c1d5f4e9ef253262f --- /dev/null +++ b/polkadot/xcm/xcm-simulator/example/src/relay_chain/xcm_config/origin_converter.rs @@ -0,0 +1,34 @@ +// 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 crate::relay_chain::{ + constants::RelayNetwork, location_converter::LocationConverter, RuntimeOrigin, +}; +use polkadot_parachain_primitives::primitives::Id as ParaId; +use polkadot_runtime_parachains::origin; +use xcm_builder::{ + ChildParachainAsNative, ChildSystemParachainAsSuperuser, SignedAccountId32AsNative, + SovereignSignedViaLocation, +}; + +type LocalOriginConverter = ( + SovereignSignedViaLocation, + ChildParachainAsNative, + SignedAccountId32AsNative, + ChildSystemParachainAsSuperuser, +); + +pub type OriginConverter = LocalOriginConverter; diff --git a/polkadot/xcm/xcm-simulator/example/src/relay_chain/xcm_config/weigher.rs b/polkadot/xcm/xcm-simulator/example/src/relay_chain/xcm_config/weigher.rs new file mode 100644 index 0000000000000000000000000000000000000000..5c02565f460071d9a3100ce57845c4a60b6ebe00 --- /dev/null +++ b/polkadot/xcm/xcm-simulator/example/src/relay_chain/xcm_config/weigher.rs @@ -0,0 +1,27 @@ +// 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 crate::relay_chain::RuntimeCall; +use frame_support::parameter_types; +use xcm::latest::prelude::*; +use xcm_builder::FixedWeightBounds; + +parameter_types! { + pub const BaseXcmWeight: Weight = Weight::from_parts(1_000, 1_000); + pub const MaxInstructions: u32 = 100; +} + +pub type Weigher = FixedWeightBounds; diff --git a/polkadot/xcm/xcm-simulator/example/src/tests.rs b/polkadot/xcm/xcm-simulator/example/src/tests.rs new file mode 100644 index 0000000000000000000000000000000000000000..34c1feb6e946876bb62a5624915e414df65ed35e --- /dev/null +++ b/polkadot/xcm/xcm-simulator/example/src/tests.rs @@ -0,0 +1,513 @@ +// 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 crate::*; + +use codec::Encode; +use frame_support::{assert_ok, weights::Weight}; +use xcm::latest::QueryResponseInfo; +use xcm_simulator::{mock_message_queue::ReceivedDmp, TestExt}; + +// Helper function for forming buy execution message +fn buy_execution(fees: impl Into) -> Instruction { + BuyExecution { fees: fees.into(), weight_limit: Unlimited } +} + +#[test] +fn remote_account_ids_work() { + child_account_account_id(1, ALICE); + sibling_account_account_id(1, ALICE); + parent_account_account_id(ALICE); +} + +#[test] +fn dmp() { + MockNet::reset(); + + let remark = parachain::RuntimeCall::System( + frame_system::Call::::remark_with_event { remark: vec![1, 2, 3] }, + ); + Relay::execute_with(|| { + assert_ok!(RelayChainPalletXcm::send_xcm( + Here, + Parachain(1), + Xcm(vec![Transact { + origin_kind: OriginKind::SovereignAccount, + require_weight_at_most: Weight::from_parts(INITIAL_BALANCE as u64, 1024 * 1024), + call: remark.encode().into(), + }]), + )); + }); + + ParaA::execute_with(|| { + use parachain::{RuntimeEvent, System}; + assert!(System::events().iter().any(|r| matches!( + r.event, + RuntimeEvent::System(frame_system::Event::Remarked { .. }) + ))); + }); +} + +#[test] +fn ump() { + MockNet::reset(); + + let remark = relay_chain::RuntimeCall::System( + frame_system::Call::::remark_with_event { remark: vec![1, 2, 3] }, + ); + ParaA::execute_with(|| { + assert_ok!(ParachainPalletXcm::send_xcm( + Here, + Parent, + Xcm(vec![Transact { + origin_kind: OriginKind::SovereignAccount, + require_weight_at_most: Weight::from_parts(INITIAL_BALANCE as u64, 1024 * 1024), + call: remark.encode().into(), + }]), + )); + }); + + Relay::execute_with(|| { + use relay_chain::{RuntimeEvent, System}; + assert!(System::events().iter().any(|r| matches!( + r.event, + RuntimeEvent::System(frame_system::Event::Remarked { .. }) + ))); + }); +} + +#[test] +fn xcmp() { + MockNet::reset(); + + let remark = parachain::RuntimeCall::System( + frame_system::Call::::remark_with_event { remark: vec![1, 2, 3] }, + ); + ParaA::execute_with(|| { + assert_ok!(ParachainPalletXcm::send_xcm( + Here, + (Parent, Parachain(2)), + Xcm(vec![Transact { + origin_kind: OriginKind::SovereignAccount, + require_weight_at_most: Weight::from_parts(INITIAL_BALANCE as u64, 1024 * 1024), + call: remark.encode().into(), + }]), + )); + }); + + ParaB::execute_with(|| { + use parachain::{RuntimeEvent, System}; + assert!(System::events().iter().any(|r| matches!( + r.event, + RuntimeEvent::System(frame_system::Event::Remarked { .. }) + ))); + }); +} + +#[test] +fn reserve_transfer() { + MockNet::reset(); + + let withdraw_amount = 123; + + Relay::execute_with(|| { + assert_ok!(RelayChainPalletXcm::limited_reserve_transfer_assets( + relay_chain::RuntimeOrigin::signed(ALICE), + Box::new(Parachain(1).into()), + Box::new(AccountId32 { network: None, id: ALICE.into() }.into()), + Box::new((Here, withdraw_amount).into()), + 0, + Unlimited, + )); + assert_eq!( + relay_chain::Balances::free_balance(&child_account_id(1)), + INITIAL_BALANCE + withdraw_amount + ); + }); + + ParaA::execute_with(|| { + // free execution, full amount received + assert_eq!( + pallet_balances::Pallet::::free_balance(&ALICE), + INITIAL_BALANCE + withdraw_amount + ); + }); +} + +#[test] +fn remote_locking_and_unlocking() { + MockNet::reset(); + + let locked_amount = 100; + + ParaB::execute_with(|| { + let message = Xcm(vec![LockAsset { + asset: (Here, locked_amount).into(), + unlocker: Parachain(1).into(), + }]); + assert_ok!(ParachainPalletXcm::send_xcm(Here, Parent, message.clone())); + }); + + Relay::execute_with(|| { + use pallet_balances::{BalanceLock, Reasons}; + assert_eq!( + relay_chain::Balances::locks(&child_account_id(2)), + vec![BalanceLock { id: *b"py/xcmlk", amount: locked_amount, reasons: Reasons::All }] + ); + }); + + ParaA::execute_with(|| { + assert_eq!( + ReceivedDmp::::get(), + vec![Xcm(vec![NoteUnlockable { + owner: (Parent, Parachain(2)).into(), + asset: (Parent, locked_amount).into() + }])] + ); + }); + + ParaB::execute_with(|| { + // Request unlocking part of the funds on the relay chain + let message = Xcm(vec![RequestUnlock { + asset: (Parent, locked_amount - 50).into(), + locker: Parent.into(), + }]); + assert_ok!(ParachainPalletXcm::send_xcm(Here, (Parent, Parachain(1)), message)); + }); + + Relay::execute_with(|| { + use pallet_balances::{BalanceLock, Reasons}; + // Lock is reduced + assert_eq!( + relay_chain::Balances::locks(&child_account_id(2)), + vec![BalanceLock { + id: *b"py/xcmlk", + amount: locked_amount - 50, + reasons: Reasons::All + }] + ); + }); +} + +/// Scenario: +/// A parachain transfers an NFT resident on the relay chain to another parachain account. +/// +/// Asserts that the parachain accounts are updated as expected. +#[test] +fn withdraw_and_deposit_nft() { + MockNet::reset(); + + Relay::execute_with(|| { + assert_eq!(relay_chain::Uniques::owner(1, 42), Some(child_account_id(1))); + }); + + ParaA::execute_with(|| { + let message = Xcm(vec![TransferAsset { + assets: (GeneralIndex(1), 42u32).into(), + beneficiary: Parachain(2).into(), + }]); + // Send withdraw and deposit + assert_ok!(ParachainPalletXcm::send_xcm(Here, Parent, message)); + }); + + Relay::execute_with(|| { + assert_eq!(relay_chain::Uniques::owner(1, 42), Some(child_account_id(2))); + }); +} + +/// Scenario: +/// The relay-chain teleports an NFT to a parachain. +/// +/// Asserts that the parachain accounts are updated as expected. +#[test] +fn teleport_nft() { + MockNet::reset(); + + Relay::execute_with(|| { + // Mint the NFT (1, 69) and give it to our "parachain#1 alias". + assert_ok!(relay_chain::Uniques::mint( + relay_chain::RuntimeOrigin::signed(ALICE), + 1, + 69, + child_account_account_id(1, ALICE), + )); + // The parachain#1 alias of Alice is what must hold it on the Relay-chain for it to be + // withdrawable by Alice on the parachain. + assert_eq!(relay_chain::Uniques::owner(1, 69), Some(child_account_account_id(1, ALICE))); + }); + ParaA::execute_with(|| { + assert_ok!(parachain::ForeignUniques::force_create( + parachain::RuntimeOrigin::root(), + (Parent, GeneralIndex(1)).into(), + ALICE, + false, + )); + assert_eq!( + parachain::ForeignUniques::owner((Parent, GeneralIndex(1)).into(), 69u32.into()), + None, + ); + assert_eq!(parachain::Balances::reserved_balance(&ALICE), 0); + + // IRL Alice would probably just execute this locally on the Relay-chain, but we can't + // easily do that here since we only send between chains. + let message = Xcm(vec![ + WithdrawAsset((GeneralIndex(1), 69u32).into()), + InitiateTeleport { + assets: AllCounted(1).into(), + dest: Parachain(1).into(), + xcm: Xcm(vec![DepositAsset { + assets: AllCounted(1).into(), + beneficiary: (AccountId32 { id: ALICE.into(), network: None },).into(), + }]), + }, + ]); + // Send teleport + let alice = AccountId32 { id: ALICE.into(), network: None }; + assert_ok!(ParachainPalletXcm::send_xcm(alice, Parent, message)); + }); + ParaA::execute_with(|| { + assert_eq!( + parachain::ForeignUniques::owner((Parent, GeneralIndex(1)).into(), 69u32.into()), + Some(ALICE), + ); + assert_eq!(parachain::Balances::reserved_balance(&ALICE), 1000); + }); + Relay::execute_with(|| { + assert_eq!(relay_chain::Uniques::owner(1, 69), None); + }); +} + +/// Scenario: +/// The relay-chain transfers an NFT into a parachain's sovereign account, who then mints a +/// trustless-backed-derived locally. +/// +/// Asserts that the parachain accounts are updated as expected. +#[test] +fn reserve_asset_transfer_nft() { + sp_tracing::init_for_tests(); + MockNet::reset(); + + Relay::execute_with(|| { + assert_ok!(relay_chain::Uniques::force_create( + relay_chain::RuntimeOrigin::root(), + 2, + ALICE, + false + )); + assert_ok!(relay_chain::Uniques::mint( + relay_chain::RuntimeOrigin::signed(ALICE), + 2, + 69, + child_account_account_id(1, ALICE) + )); + assert_eq!(relay_chain::Uniques::owner(2, 69), Some(child_account_account_id(1, ALICE))); + }); + ParaA::execute_with(|| { + assert_ok!(parachain::ForeignUniques::force_create( + parachain::RuntimeOrigin::root(), + (Parent, GeneralIndex(2)).into(), + ALICE, + false, + )); + assert_eq!( + parachain::ForeignUniques::owner((Parent, GeneralIndex(2)).into(), 69u32.into()), + None, + ); + assert_eq!(parachain::Balances::reserved_balance(&ALICE), 0); + + let message = Xcm(vec![ + WithdrawAsset((GeneralIndex(2), 69u32).into()), + DepositReserveAsset { + assets: AllCounted(1).into(), + dest: Parachain(1).into(), + xcm: Xcm(vec![DepositAsset { + assets: AllCounted(1).into(), + beneficiary: (AccountId32 { id: ALICE.into(), network: None },).into(), + }]), + }, + ]); + // Send transfer + let alice = AccountId32 { id: ALICE.into(), network: None }; + assert_ok!(ParachainPalletXcm::send_xcm(alice, Parent, message)); + }); + ParaA::execute_with(|| { + log::debug!(target: "xcm-executor", "Hello"); + assert_eq!( + parachain::ForeignUniques::owner((Parent, GeneralIndex(2)).into(), 69u32.into()), + Some(ALICE), + ); + assert_eq!(parachain::Balances::reserved_balance(&ALICE), 1000); + }); + + Relay::execute_with(|| { + assert_eq!(relay_chain::Uniques::owner(2, 69), Some(child_account_id(1))); + }); +} + +/// Scenario: +/// The relay-chain creates an asset class on a parachain and then Alice transfers her NFT into +/// that parachain's sovereign account, who then mints a trustless-backed-derivative locally. +/// +/// Asserts that the parachain accounts are updated as expected. +#[test] +fn reserve_asset_class_create_and_reserve_transfer() { + MockNet::reset(); + + Relay::execute_with(|| { + assert_ok!(relay_chain::Uniques::force_create( + relay_chain::RuntimeOrigin::root(), + 2, + ALICE, + false + )); + assert_ok!(relay_chain::Uniques::mint( + relay_chain::RuntimeOrigin::signed(ALICE), + 2, + 69, + child_account_account_id(1, ALICE) + )); + assert_eq!(relay_chain::Uniques::owner(2, 69), Some(child_account_account_id(1, ALICE))); + + let message = Xcm(vec![Transact { + origin_kind: OriginKind::Xcm, + require_weight_at_most: Weight::from_parts(1_000_000_000, 1024 * 1024), + call: parachain::RuntimeCall::from( + pallet_uniques::Call::::create { + collection: (Parent, 2u64).into(), + admin: parent_account_id(), + }, + ) + .encode() + .into(), + }]); + // Send creation. + assert_ok!(RelayChainPalletXcm::send_xcm(Here, Parachain(1), message)); + }); + ParaA::execute_with(|| { + // Then transfer + let message = Xcm(vec![ + WithdrawAsset((GeneralIndex(2), 69u32).into()), + DepositReserveAsset { + assets: AllCounted(1).into(), + dest: Parachain(1).into(), + xcm: Xcm(vec![DepositAsset { + assets: AllCounted(1).into(), + beneficiary: (AccountId32 { id: ALICE.into(), network: None },).into(), + }]), + }, + ]); + let alice = AccountId32 { id: ALICE.into(), network: None }; + assert_ok!(ParachainPalletXcm::send_xcm(alice, Parent, message)); + }); + ParaA::execute_with(|| { + assert_eq!(parachain::Balances::reserved_balance(&parent_account_id()), 1000); + assert_eq!( + parachain::ForeignUniques::collection_owner((Parent, 2u64).into()), + Some(parent_account_id()) + ); + }); +} + +/// Scenario: +/// A parachain transfers funds on the relay chain to another parachain account. +/// +/// Asserts that the parachain accounts are updated as expected. +#[test] +fn withdraw_and_deposit() { + MockNet::reset(); + + let send_amount = 10; + + ParaA::execute_with(|| { + let message = Xcm(vec![ + WithdrawAsset((Here, send_amount).into()), + buy_execution((Here, send_amount)), + DepositAsset { assets: AllCounted(1).into(), beneficiary: Parachain(2).into() }, + ]); + // Send withdraw and deposit + assert_ok!(ParachainPalletXcm::send_xcm(Here, Parent, message.clone())); + }); + + Relay::execute_with(|| { + assert_eq!( + relay_chain::Balances::free_balance(child_account_id(1)), + INITIAL_BALANCE - send_amount + ); + assert_eq!( + relay_chain::Balances::free_balance(child_account_id(2)), + INITIAL_BALANCE + send_amount + ); + }); +} + +/// Scenario: +/// A parachain wants to be notified that a transfer worked correctly. +/// It sends a `QueryHolding` after the deposit to get notified on success. +/// +/// Asserts that the balances are updated correctly and the expected XCM is sent. +#[test] +fn query_holding() { + MockNet::reset(); + + let send_amount = 10; + let query_id_set = 1234; + + // Send a message which fully succeeds on the relay chain + ParaA::execute_with(|| { + let message = Xcm(vec![ + WithdrawAsset((Here, send_amount).into()), + buy_execution((Here, send_amount)), + DepositAsset { assets: AllCounted(1).into(), beneficiary: Parachain(2).into() }, + ReportHolding { + response_info: QueryResponseInfo { + destination: Parachain(1).into(), + query_id: query_id_set, + max_weight: Weight::from_parts(1_000_000_000, 1024 * 1024), + }, + assets: All.into(), + }, + ]); + // Send withdraw and deposit with query holding + assert_ok!(ParachainPalletXcm::send_xcm(Here, Parent, message.clone(),)); + }); + + // Check that transfer was executed + Relay::execute_with(|| { + // Withdraw executed + assert_eq!( + relay_chain::Balances::free_balance(child_account_id(1)), + INITIAL_BALANCE - send_amount + ); + // Deposit executed + assert_eq!( + relay_chain::Balances::free_balance(child_account_id(2)), + INITIAL_BALANCE + send_amount + ); + }); + + // Check that QueryResponse message was received + ParaA::execute_with(|| { + assert_eq!( + ReceivedDmp::::get(), + vec![Xcm(vec![QueryResponse { + query_id: query_id_set, + response: Response::Assets(Assets::new()), + max_weight: Weight::from_parts(1_000_000_000, 1024 * 1024), + querier: Some(Here.into()), + }])], + ); + }); +} diff --git a/polkadot/xcm/xcm-simulator/fuzzer/Cargo.toml b/polkadot/xcm/xcm-simulator/fuzzer/Cargo.toml index ca794a07bfb0c73df251d49c2e08a970ea5cf994..6b3b4018d9fbb30862eee8fa5ea1408c96b2f68e 100644 --- a/polkadot/xcm/xcm-simulator/fuzzer/Cargo.toml +++ b/polkadot/xcm/xcm-simulator/fuzzer/Cargo.toml @@ -11,7 +11,7 @@ publish = false workspace = true [dependencies] -codec = { package = "parity-scale-codec", version = "3.6.1" } +codec = { package = "parity-scale-codec", version = "3.6.12" } honggfuzz = "0.5.55" arbitrary = "1.3.2" scale-info = { version = "2.11.1", features = ["derive"] } diff --git a/polkadot/xcm/xcm-simulator/fuzzer/src/parachain.rs b/polkadot/xcm/xcm-simulator/fuzzer/src/parachain.rs index cadfc1e7200c075433ebf295982cc49f8a0d06b1..502bcca2d44270263a45eeaf305b924d8b37c509 100644 --- a/polkadot/xcm/xcm-simulator/fuzzer/src/parachain.rs +++ b/polkadot/xcm/xcm-simulator/fuzzer/src/parachain.rs @@ -101,7 +101,7 @@ parameter_types! { parameter_types! { pub const KsmLocation: Location = Location::parent(); pub const RelayNetwork: NetworkId = NetworkId::Kusama; - pub UniversalLocation: InteriorLocation = Parachain(MsgQueue::parachain_id().into()).into(); + pub UniversalLocation: InteriorLocation = [GlobalConsensus(RelayNetwork::get()), Parachain(MsgQueue::parachain_id().into())].into(); } pub type LocationToAccountId = ( @@ -159,6 +159,7 @@ impl Config for XcmConfig { type HrmpNewChannelOpenRequestHandler = (); type HrmpChannelAcceptedHandler = (); type HrmpChannelClosingHandler = (); + type XcmRecorder = (); } #[frame_support::pallet] diff --git a/polkadot/xcm/xcm-simulator/fuzzer/src/relay_chain.rs b/polkadot/xcm/xcm-simulator/fuzzer/src/relay_chain.rs index 6790b535d169220a3def3e4780af1aa1ef83e759..4740aee83d870a0e260512ac15a982c515a1e803 100644 --- a/polkadot/xcm/xcm-simulator/fuzzer/src/relay_chain.rs +++ b/polkadot/xcm/xcm-simulator/fuzzer/src/relay_chain.rs @@ -104,7 +104,7 @@ parameter_types! { pub const TokenLocation: Location = Here.into_location(); pub const ThisNetwork: NetworkId = NetworkId::ByGenesis([0; 32]); pub const AnyNetwork: Option = None; - pub const UniversalLocation: InteriorLocation = Here; + pub UniversalLocation: InteriorLocation = ThisNetwork::get().into(); } pub type SovereignAccountOf = @@ -160,6 +160,7 @@ impl Config for XcmConfig { type HrmpNewChannelOpenRequestHandler = (); type HrmpChannelAcceptedHandler = (); type HrmpChannelClosingHandler = (); + type XcmRecorder = (); } pub type LocalOriginToLocation = SignedToAccountId32; @@ -191,10 +192,6 @@ impl pallet_xcm::Config for Runtime { type AdminOrigin = EnsureRoot; } -parameter_types! { - pub const FirstMessageFactorPercent: u64 = 100; -} - impl origin::Config for Runtime {} parameter_types! { diff --git a/polkadot/xcm/xcm-simulator/src/lib.rs b/polkadot/xcm/xcm-simulator/src/lib.rs index 7efbc658bbfb8bc3fadfa037ae966ca935816ba6..a6747a4789edf8065462b831893ebc8b0284dd18 100644 --- a/polkadot/xcm/xcm-simulator/src/lib.rs +++ b/polkadot/xcm/xcm-simulator/src/lib.rs @@ -16,6 +16,10 @@ //! Test kit to simulate cross-chain message passing and XCM execution. +/// Implementation of a simple message queue. +/// Used for sending messages. +pub mod mock_message_queue; + pub use codec::Encode; pub use paste; diff --git a/polkadot/xcm/xcm-simulator/src/mock_message_queue.rs b/polkadot/xcm/xcm-simulator/src/mock_message_queue.rs new file mode 100644 index 0000000000000000000000000000000000000000..96b47999fe952145b09faa93aaf2cefd5143acb9 --- /dev/null +++ b/polkadot/xcm/xcm-simulator/src/mock_message_queue.rs @@ -0,0 +1,190 @@ +// Copyright 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 . + +//! Simple mock message queue. + +use codec::{Decode, Encode}; + +use polkadot_parachain_primitives::primitives::{ + DmpMessageHandler, Id as ParaId, XcmpMessageFormat, XcmpMessageHandler, +}; +use polkadot_primitives::BlockNumber as RelayBlockNumber; +use sp_runtime::traits::{Get, Hash}; + +use sp_std::prelude::*; +use xcm::{latest::prelude::*, VersionedXcm}; + +pub use pallet::*; + +#[frame_support::pallet] +pub mod pallet { + use super::*; + use frame_support::pallet_prelude::*; + + #[pallet::config] + pub trait Config: frame_system::Config { + type RuntimeEvent: From> + IsType<::RuntimeEvent>; + type XcmExecutor: ExecuteXcm; + } + + #[pallet::call] + impl Pallet {} + + #[pallet::pallet] + #[pallet::without_storage_info] + pub struct Pallet(_); + + #[pallet::storage] + pub type ParachainId = StorageValue<_, ParaId, ValueQuery>; + + #[pallet::storage] + /// A queue of received DMP messages + pub type ReceivedDmp = StorageValue<_, Vec>, ValueQuery>; + + impl Get for Pallet { + fn get() -> ParaId { + ParachainId::::get() + } + } + + pub type MessageId = [u8; 32]; + + #[pallet::event] + #[pallet::generate_deposit(pub(super) fn deposit_event)] + pub enum Event { + // XCMP + /// Some XCM was executed OK. + Success { message_id: Option }, + /// Some XCM failed. + Fail { message_id: Option, error: XcmError }, + /// Bad XCM version used. + BadVersion { message_id: Option }, + /// Bad XCM format used. + BadFormat { message_id: Option }, + + // DMP + /// Downward message is invalid XCM. + InvalidFormat { message_id: MessageId }, + /// Downward message is unsupported version of XCM. + UnsupportedVersion { message_id: MessageId }, + /// Downward message executed with the given outcome. + ExecutedDownward { message_id: MessageId, outcome: Outcome }, + } + + impl Pallet { + pub fn set_para_id(para_id: ParaId) { + ParachainId::::put(para_id); + } + + fn handle_xcmp_message( + sender: ParaId, + _sent_at: RelayBlockNumber, + xcm: VersionedXcm, + max_weight: xcm::latest::Weight, + ) -> Result { + let hash = Encode::using_encoded(&xcm, T::Hashing::hash); + let mut message_hash = Encode::using_encoded(&xcm, sp_io::hashing::blake2_256); + let (result, event) = match Xcm::::try_from(xcm) { + Ok(xcm) => { + let location = (Parent, Parachain(sender.into())); + match T::XcmExecutor::prepare_and_execute( + location, + xcm, + &mut message_hash, + max_weight, + Weight::zero(), + ) { + Outcome::Error { error } => + (Err(error), Event::Fail { message_id: Some(hash), error }), + Outcome::Complete { used } => + (Ok(used), Event::Success { message_id: Some(hash) }), + // As far as the caller is concerned, this was dispatched without error, so + // we just report the weight used. + Outcome::Incomplete { used, error } => + (Ok(used), Event::Fail { message_id: Some(hash), error }), + } + }, + Err(()) => ( + Err(XcmError::UnhandledXcmVersion), + Event::BadVersion { message_id: Some(hash) }, + ), + }; + Self::deposit_event(event); + result + } + } + + impl XcmpMessageHandler for Pallet { + fn handle_xcmp_messages<'a, I: Iterator>( + iter: I, + max_weight: xcm::latest::Weight, + ) -> xcm::latest::Weight { + for (sender, sent_at, data) in iter { + let mut data_ref = data; + let _ = XcmpMessageFormat::decode(&mut data_ref) + .expect("Simulator encodes with versioned xcm format; qed"); + + let mut remaining_fragments = data_ref; + while !remaining_fragments.is_empty() { + if let Ok(xcm) = + VersionedXcm::::decode(&mut remaining_fragments) + { + let _ = Self::handle_xcmp_message(sender, sent_at, xcm, max_weight); + } else { + debug_assert!(false, "Invalid incoming XCMP message data"); + } + } + } + max_weight + } + } + + impl DmpMessageHandler for Pallet { + fn handle_dmp_messages( + iter: impl Iterator)>, + limit: Weight, + ) -> Weight { + for (_sent_at, data) in iter { + let mut id = sp_io::hashing::blake2_256(&data[..]); + let maybe_versioned = VersionedXcm::::decode(&mut &data[..]); + match maybe_versioned { + Err(_) => { + Self::deposit_event(Event::InvalidFormat { message_id: id }); + }, + Ok(versioned) => match Xcm::try_from(versioned) { + Err(()) => + Self::deposit_event(Event::UnsupportedVersion { message_id: id }), + Ok(x) => { + let outcome = T::XcmExecutor::prepare_and_execute( + Parent, + x.clone(), + &mut id, + limit, + Weight::zero(), + ); + ReceivedDmp::::append(x); + Self::deposit_event(Event::ExecutedDownward { + message_id: id, + outcome, + }); + }, + }, + } + } + limit + } + } +} diff --git a/polkadot/zombienet_tests/functional/0010-validator-disabling.toml b/polkadot/zombienet_tests/functional/0010-validator-disabling.toml index c9d79c5f8f236918cf409fd684b7d0b8d9792d33..806f34d7f7670d9c654837f144f845352c7b41e7 100644 --- a/polkadot/zombienet_tests/functional/0010-validator-disabling.toml +++ b/polkadot/zombienet_tests/functional/0010-validator-disabling.toml @@ -21,7 +21,7 @@ requests = { memory = "2G", cpu = "1" } [[relaychain.node_groups]] name = "honest-validator" count = 3 - args = ["-lparachain=debug"] + args = ["-lparachain=debug,runtime::staking=debug"] [[relaychain.node_groups]] image = "{{MALUS_IMAGE}}" diff --git a/polkadot/zombienet_tests/functional/0012-spam-statement-distribution-requests.toml b/polkadot/zombienet_tests/functional/0012-spam-statement-distribution-requests.toml new file mode 100644 index 0000000000000000000000000000000000000000..14208425d62bac4a7c227211c99da4e01dd89866 --- /dev/null +++ b/polkadot/zombienet_tests/functional/0012-spam-statement-distribution-requests.toml @@ -0,0 +1,43 @@ +[settings] +timeout = 1000 + +[relaychain.genesis.runtimeGenesis.patch.configuration.config] + needed_approvals = 2 + +[relaychain.genesis.runtimeGenesis.patch.configuration.config.scheduler_params] + max_validators_per_core = 5 + +[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.node_groups]] + name = "honest" + count = 4 + args = ["-lparachain=debug,parachain::statement-distribution=trace"] + + [[relaychain.nodes]] + image = "{{MALUS_IMAGE}}" + name = "malus" + command = "malus spam-statement-requests" + args = [ "--alice", "-lparachain=debug,MALUS=trace", "--spam-factor=1000" ] + +{% for id in range(2000,2001) %} +[[parachains]] +id = {{id}} + [parachains.collator] + image = "{{COL_IMAGE}}" + name = "collator" + command = "undying-collator" + args = ["-lparachain=debug"] +{% endfor %} + +[types.Header] +number = "u64" +parent_hash = "Hash" +post_state = "Hash" diff --git a/polkadot/zombienet_tests/functional/0012-spam-statement-distribution-requests.zndsl b/polkadot/zombienet_tests/functional/0012-spam-statement-distribution-requests.zndsl new file mode 100644 index 0000000000000000000000000000000000000000..9985dd24ee38a56c823e07d07556fd77eb7a1ac5 --- /dev/null +++ b/polkadot/zombienet_tests/functional/0012-spam-statement-distribution-requests.zndsl @@ -0,0 +1,27 @@ +Description: Test if parachains progress when group is getting spammed by statement distribution requests. +Network: ./0012-spam-statement-distribution-requests.toml +Creds: config + +# Check authority status and peers. +malus: reports node_roles is 4 +honest: reports node_roles is 4 + +# Ensure parachains are registered. +honest: parachain 2000 is registered within 60 seconds + +# Ensure that malus is already attempting to DoS +malus: log line contains "😈 Duplicating AttestedCandidateV2 request" within 90 seconds + +# Ensure parachains made progress. +honest: parachain 2000 block height is at least 10 within 200 seconds + +# Ensure that honest nodes drop extra requests +honest: log line contains "Peer already being served, dropping request" within 60 seconds + +# Check lag - approval +honest: reports polkadot_parachain_approval_checking_finality_lag is 0 + +# Check lag - dispute conclusion +honest: reports polkadot_parachain_disputes_finality_lag is 0 + + diff --git a/prdoc/pr_2119.prdoc b/prdoc/1.11.0/pr_2119.prdoc similarity index 100% rename from prdoc/pr_2119.prdoc rename to prdoc/1.11.0/pr_2119.prdoc diff --git a/prdoc/pr_2292.prdoc b/prdoc/1.11.0/pr_2292.prdoc similarity index 100% rename from prdoc/pr_2292.prdoc rename to prdoc/1.11.0/pr_2292.prdoc diff --git a/prdoc/pr_2714.prdoc b/prdoc/1.11.0/pr_2714.prdoc similarity index 100% rename from prdoc/pr_2714.prdoc rename to prdoc/1.11.0/pr_2714.prdoc diff --git a/prdoc/pr_2944.prdoc b/prdoc/1.11.0/pr_2944.prdoc similarity index 100% rename from prdoc/pr_2944.prdoc rename to prdoc/1.11.0/pr_2944.prdoc diff --git a/prdoc/1.11.0/pr_3250.prdoc b/prdoc/1.11.0/pr_3250.prdoc new file mode 100644 index 0000000000000000000000000000000000000000..77ea725073e65590715b76eada871afe95e40b5b --- /dev/null +++ b/prdoc/1.11.0/pr_3250.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: "Asset Conversion: Pool Account ID derivation with additional Pallet ID seed" + +doc: + - audience: Runtime Dev + description: | + Introduce PalletId as an additional seed parameter for pool's account id derivation. + The PR also introduces the `pallet_asset_conversion_ops` pallet with a call to migrate + a pool to the new account. Additionally `fungibles::roles::ResetTeam` and + `fungible::lifetime::Refund` traits, to facilitate the migration functionality. + +crates: + - name: pallet-asset-conversion + bump: minor diff --git a/prdoc/1.11.0/pr_3251.prdoc b/prdoc/1.11.0/pr_3251.prdoc new file mode 100644 index 0000000000000000000000000000000000000000..1f95c228f7a8c945d59cc8b2bc64759d3df18421 --- /dev/null +++ b/prdoc/1.11.0/pr_3251.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: "Asset Conversion: Pool Touch Call" + +doc: + - audience: Runtime Dev + description: | + Introduce `touch` call designed to address operational prerequisites before providing liquidity to a pool. + This function ensures that essential requirements, such as the presence of the pool's accounts, are fulfilled. + It is particularly beneficial in scenarios where a pool creator removes the pool's accounts without providing liquidity. + +crates: + - name: pallet-asset-conversion diff --git a/prdoc/1.11.0/pr_3455.prdoc b/prdoc/1.11.0/pr_3455.prdoc new file mode 100644 index 0000000000000000000000000000000000000000..c16ac2244862fc16b0205514564ce2348e205c34 --- /dev/null +++ b/prdoc/1.11.0/pr_3455.prdoc @@ -0,0 +1,28 @@ +# 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: Region reserve transfers fix + +doc: + - audience: Runtime User + description: | + This PR introduces changes enabling the transfer of coretime regions via XCM. + There are two primary issues that are resolved in this PR: + 1. The mint and burn functions were not implemented for coretime regions. These operations + are essential for moving assets to and from the XCM holding register. + 2. The transfer of non-fungible assets through XCM was previously disallowed. This was due + to incorrectly benchmarking non-fungible asset transfers via XCM, which led to assigning + it a weight of Weight::Max, effectively preventing its execution. + +migrations: + db: [] + runtime: + - reference: pallet-broker + description: | + The region owner is optional. + +crates: + - name: pallet-broker + - name: pallet-xcm + - name: coretime-rococo-runtime + - name: coretime-westend-runtime diff --git a/prdoc/pr_3485.prdoc b/prdoc/1.11.0/pr_3485.prdoc similarity index 100% rename from prdoc/pr_3485.prdoc rename to prdoc/1.11.0/pr_3485.prdoc diff --git a/prdoc/pr_3512.prdoc b/prdoc/1.11.0/pr_3512.prdoc similarity index 100% rename from prdoc/pr_3512.prdoc rename to prdoc/1.11.0/pr_3512.prdoc diff --git a/prdoc/pr_3630.prdoc b/prdoc/1.11.0/pr_3630.prdoc similarity index 100% rename from prdoc/pr_3630.prdoc rename to prdoc/1.11.0/pr_3630.prdoc diff --git a/prdoc/1.11.0/pr_3659.prdoc b/prdoc/1.11.0/pr_3659.prdoc new file mode 100644 index 0000000000000000000000000000000000000000..393844d822d864bca595a0257f02989fb4a19ac7 --- /dev/null +++ b/prdoc/1.11.0/pr_3659.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: Unity Balance Conversion for Different IDs of Native Asset + +doc: + - audience: Runtime Dev + description: | + Introduce types to define 1:1 balance conversion for different relative asset ids/locations + of native asset for `ConversionToAssetBalance` trait bounds. + +crates: [ ] \ No newline at end of file diff --git a/prdoc/pr_3660.prdoc b/prdoc/1.11.0/pr_3660.prdoc similarity index 100% rename from prdoc/pr_3660.prdoc rename to prdoc/1.11.0/pr_3660.prdoc diff --git a/prdoc/pr_3695.prdoc b/prdoc/1.11.0/pr_3695.prdoc similarity index 80% rename from prdoc/pr_3695.prdoc rename to prdoc/1.11.0/pr_3695.prdoc index 2c2c2b2e6917819f5f4c3b2c0381e3f7e4890a17..cc54fb240cd021f62a42ed50561d08ec0fb369d9 100644 --- a/prdoc/pr_3695.prdoc +++ b/prdoc/1.11.0/pr_3695.prdoc @@ -6,7 +6,7 @@ title: "pallet-xcm: add new extrinsic for asset transfers using explicit reserve doc: - audience: Runtime User description: | - pallet-xcm has a new extrinsic `transfer_assets_using_type` for transferring + pallet-xcm has a new extrinsic `transfer_assets_using_type_and_then` for transferring assets from local chain to destination chain using an explicit XCM transfer types for transferring the assets and the fees: - `TransferType::LocalReserve`: transfer assets to sovereign account of destination @@ -33,6 +33,13 @@ doc: Same when transferring bridged assets back across the bridge, the local bridging parachain must be used as the explicit reserve location. + The new method takes a `custom_xcm_on_dest` parameter allowing the caller to specify + what should happen to the transferred assets once they reach + the `dest` chain. The `custom_xcm_on_dest` parameter should contains the instructions + to execute on `dest` as a final step. Usually as simple as: + `Xcm(vec![DepositAsset { assets: Wild(AllCounted(assets.len())), beneficiary }])`, + but could be something more exotic like sending the `assets` even further. + crates: - name: pallet-xcm bump: minor diff --git a/prdoc/pr_3708.prdoc b/prdoc/1.11.0/pr_3708.prdoc similarity index 100% rename from prdoc/pr_3708.prdoc rename to prdoc/1.11.0/pr_3708.prdoc diff --git a/prdoc/pr_3721.prdoc b/prdoc/1.11.0/pr_3721.prdoc similarity index 100% rename from prdoc/pr_3721.prdoc rename to prdoc/1.11.0/pr_3721.prdoc diff --git a/prdoc/pr_3789.prdoc b/prdoc/1.11.0/pr_3789.prdoc similarity index 100% rename from prdoc/pr_3789.prdoc rename to prdoc/1.11.0/pr_3789.prdoc diff --git a/prdoc/pr_3801.prdoc b/prdoc/1.11.0/pr_3801.prdoc similarity index 100% rename from prdoc/pr_3801.prdoc rename to prdoc/1.11.0/pr_3801.prdoc diff --git a/prdoc/pr_3813.prdoc b/prdoc/1.11.0/pr_3813.prdoc similarity index 100% rename from prdoc/pr_3813.prdoc rename to prdoc/1.11.0/pr_3813.prdoc diff --git a/prdoc/pr_3852.prdoc b/prdoc/1.11.0/pr_3852.prdoc similarity index 100% rename from prdoc/pr_3852.prdoc rename to prdoc/1.11.0/pr_3852.prdoc diff --git a/prdoc/pr_3875.prdoc b/prdoc/1.11.0/pr_3875.prdoc similarity index 100% rename from prdoc/pr_3875.prdoc rename to prdoc/1.11.0/pr_3875.prdoc diff --git a/prdoc/1.11.0/pr_3889.prdoc b/prdoc/1.11.0/pr_3889.prdoc new file mode 100644 index 0000000000000000000000000000000000000000..b32ffcc214c055879b546c4b19d3339f37dde71b --- /dev/null +++ b/prdoc/1.11.0/pr_3889.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: Allow privileged virtual bond into pallet Staking + +doc: + - audience: Runtime Dev + description: | + Introduces a new low level API to allow privileged virtual bond into pallet Staking. This allows other pallets + to stake funds into staking pallet while managing the fund lock and unlocking process themselves. + +crates: + - name: pallet-staking + diff --git a/prdoc/pr_3915.prdoc b/prdoc/1.11.0/pr_3915.prdoc similarity index 100% rename from prdoc/pr_3915.prdoc rename to prdoc/1.11.0/pr_3915.prdoc diff --git a/prdoc/pr_3930.prdoc b/prdoc/1.11.0/pr_3930.prdoc similarity index 100% rename from prdoc/pr_3930.prdoc rename to prdoc/1.11.0/pr_3930.prdoc diff --git a/prdoc/pr_3934.prdoc b/prdoc/1.11.0/pr_3934.prdoc similarity index 100% rename from prdoc/pr_3934.prdoc rename to prdoc/1.11.0/pr_3934.prdoc diff --git a/prdoc/pr_3953.prdoc b/prdoc/1.11.0/pr_3953.prdoc similarity index 100% rename from prdoc/pr_3953.prdoc rename to prdoc/1.11.0/pr_3953.prdoc diff --git a/prdoc/pr_3959.prdoc b/prdoc/1.11.0/pr_3959.prdoc similarity index 100% rename from prdoc/pr_3959.prdoc rename to prdoc/1.11.0/pr_3959.prdoc diff --git a/prdoc/pr_3976.prdoc b/prdoc/1.11.0/pr_3976.prdoc similarity index 100% rename from prdoc/pr_3976.prdoc rename to prdoc/1.11.0/pr_3976.prdoc diff --git a/prdoc/pr_3979.prdoc b/prdoc/1.11.0/pr_3979.prdoc similarity index 100% rename from prdoc/pr_3979.prdoc rename to prdoc/1.11.0/pr_3979.prdoc diff --git a/prdoc/pr_3983.prdoc b/prdoc/1.11.0/pr_3983.prdoc similarity index 100% rename from prdoc/pr_3983.prdoc rename to prdoc/1.11.0/pr_3983.prdoc diff --git a/prdoc/pr_3997.prdoc b/prdoc/1.11.0/pr_3997.prdoc similarity index 100% rename from prdoc/pr_3997.prdoc rename to prdoc/1.11.0/pr_3997.prdoc diff --git a/prdoc/pr_4006.prdoc b/prdoc/1.11.0/pr_4006.prdoc similarity index 100% rename from prdoc/pr_4006.prdoc rename to prdoc/1.11.0/pr_4006.prdoc diff --git a/prdoc/pr_4015.prdoc b/prdoc/1.11.0/pr_4015.prdoc similarity index 100% rename from prdoc/pr_4015.prdoc rename to prdoc/1.11.0/pr_4015.prdoc diff --git a/prdoc/pr_4017.prdoc b/prdoc/1.11.0/pr_4017.prdoc similarity index 100% rename from prdoc/pr_4017.prdoc rename to prdoc/1.11.0/pr_4017.prdoc diff --git a/prdoc/pr_4021.prdoc b/prdoc/1.11.0/pr_4021.prdoc similarity index 100% rename from prdoc/pr_4021.prdoc rename to prdoc/1.11.0/pr_4021.prdoc diff --git a/prdoc/pr_4027.prdoc b/prdoc/1.11.0/pr_4027.prdoc similarity index 100% rename from prdoc/pr_4027.prdoc rename to prdoc/1.11.0/pr_4027.prdoc diff --git a/prdoc/pr_4037.prdoc b/prdoc/1.11.0/pr_4037.prdoc similarity index 100% rename from prdoc/pr_4037.prdoc rename to prdoc/1.11.0/pr_4037.prdoc diff --git a/prdoc/pr_4059.prdoc b/prdoc/1.11.0/pr_4059.prdoc similarity index 100% rename from prdoc/pr_4059.prdoc rename to prdoc/1.11.0/pr_4059.prdoc diff --git a/prdoc/1.11.0/pr_4060.prdoc b/prdoc/1.11.0/pr_4060.prdoc new file mode 100644 index 0000000000000000000000000000000000000000..621620a44893ea080385332f2dd7b6317f4d4d6b --- /dev/null +++ b/prdoc/1.11.0/pr_4060.prdoc @@ -0,0 +1,54 @@ +title: "Fix nostd build of several crates" + +doc: + - audience: Runtime Dev + description: | + Fixes feature and dependency configuration of several crate. This should allow for better no-std build capabilities. + +crates: + - name: cumulus-pallet-session-benchmarking + bump: patch + - name: asset-hub-rococo-runtime + bump: patch + - name: glutton-westend-runtime + bump: patch + - name: cumulus-primitives-parachain-inherent + bump: patch + - name: polkadot-primitives + bump: patch + - name: polkadot-runtime-parachains + bump: patch + - name: xcm-executor-integration-tests + bump: patch + - name: pallet-atomic-swap + bump: patch + - name: pallet-election-provider-support-benchmarking + bump: patch + - name: pallet-dev-mode + bump: patch + - name: pallet-example-offchain-worker + bump: patch + - name: pallet-indices + bump: patch + - name: pallet-nomination-pools + bump: patch + - name: pallet-nomination-pools-benchmarking + bump: patch + - name: pallet-offences-benchmarking + bump: patch + - name: pallet-root-offences + bump: patch + - name: pallet-session-benchmarking + bump: patch + - name: frame-system-benchmarking + bump: patch + - name: sp-consensus-babe + bump: patch + - name: sp-consensus-babe + bump: patch + - name: sp-core + bump: patch + - name: sp-session + bump: patch + - name: sp-transaction-storage-proof + bump: patch diff --git a/prdoc/pr_4070.prdoc b/prdoc/1.11.0/pr_4070.prdoc similarity index 100% rename from prdoc/pr_4070.prdoc rename to prdoc/1.11.0/pr_4070.prdoc diff --git a/prdoc/pr_4072.prdoc b/prdoc/1.11.0/pr_4072.prdoc similarity index 100% rename from prdoc/pr_4072.prdoc rename to prdoc/1.11.0/pr_4072.prdoc diff --git a/prdoc/1.11.0/pr_4075.prdoc b/prdoc/1.11.0/pr_4075.prdoc new file mode 100644 index 0000000000000000000000000000000000000000..05e54073b6c7b5562b6a8880185d3e38b2526ab8 --- /dev/null +++ b/prdoc/1.11.0/pr_4075.prdoc @@ -0,0 +1,19 @@ +title: Adds ability to trigger tasks via unsigned transactions + +doc: + - audience: Runtime Dev + description: | + This PR updates the `validate_unsigned` hook for `frame_system` to allow valid tasks + to be submitted as unsigned transactions. It also updates the task example to be able to + submit such transactions via an off-chain worker. + + Note that `is_valid` call on a task MUST be cheap with minimal to no storage reads. + Else, it can make the blockchain vulnerable to DoS attacks. + + Further, these tasks will be executed in a random order. + +crates: + - name: frame-system + bump: patch + - name: pallet-example-tasks + bump: minor diff --git a/prdoc/pr_4089.prdoc b/prdoc/1.11.0/pr_4089.prdoc similarity index 100% rename from prdoc/pr_4089.prdoc rename to prdoc/1.11.0/pr_4089.prdoc diff --git a/prdoc/1.11.0/pr_4118.prdoc b/prdoc/1.11.0/pr_4118.prdoc new file mode 100644 index 0000000000000000000000000000000000000000..20f36c1b0a37cc330c23115daa59f7a6c14b3c6a --- /dev/null +++ b/prdoc/1.11.0/pr_4118.prdoc @@ -0,0 +1,13 @@ +title: "pallet assets: minor improvement on errors returned for some calls" + +doc: + - audience: Runtime Dev + description: | + Some calls in pallet assets have better errors. No new error is introduced, only more sensible choice are made. + - audience: Runtime User + description: | + Some calls in pallet assets have better errors. No new error is introduced, only more sensible choice are made. + +crates: + - name: pallet-assets + bump: minor diff --git a/prdoc/1.11.0/pr_4151.prdoc b/prdoc/1.11.0/pr_4151.prdoc new file mode 100644 index 0000000000000000000000000000000000000000..70b9f5e60e14c5a0896b60651be89cc40fbe56a5 --- /dev/null +++ b/prdoc/1.11.0/pr_4151.prdoc @@ -0,0 +1,11 @@ +title: "[pallet-broker] Use saturating math in input validation" + +doc: + - audience: Runtime Dev + description: | + Use saturating in the pallet-broker input validation of the `drop_history` extrinsic. This + fixes a safeguard that only expired historic instantaneous pool records get dropped. + +crates: + - name: pallet-broker + bump: patch diff --git a/prdoc/1.11.0/pr_4156.prdoc b/prdoc/1.11.0/pr_4156.prdoc new file mode 100644 index 0000000000000000000000000000000000000000..fc09a4e0df44b830bf1b394e20a36dd3c3644a48 --- /dev/null +++ b/prdoc/1.11.0/pr_4156.prdoc @@ -0,0 +1,13 @@ +title: "`AllowHrmpNotificationsFromRelayChain` barrier for HRMP notifications from the relaychain" + +doc: + - audience: Runtime Dev + description: | + A new barrier, `AllowHrmpNotificationsFromRelayChain`, has been added. + This barrier can be utilized to ensure that HRMP notifications originate solely from the Relay Chain. + If your runtime relies on these notifications, + you can include it in the runtime's barrier type for `xcm_executor::Config`. + +crates: +- name: staging-xcm-builder + bump: minor diff --git a/prdoc/1.11.0/pr_4168.prdoc b/prdoc/1.11.0/pr_4168.prdoc new file mode 100644 index 0000000000000000000000000000000000000000..9a498500f08b4f7013c3b2829d87b7e588829406 --- /dev/null +++ b/prdoc/1.11.0/pr_4168.prdoc @@ -0,0 +1,8 @@ +title: Stabilize chianHead RPC class to version 1 + +doc: + - audience: Node Dev + description: | + The chainHead RPC API is stabilized to version 1. + +crates: [ ] diff --git a/prdoc/1.11.0/pr_4169.prdoc b/prdoc/1.11.0/pr_4169.prdoc new file mode 100644 index 0000000000000000000000000000000000000000..03f2f6e597e42a9e4f7f5710f86a542438a70c43 --- /dev/null +++ b/prdoc/1.11.0/pr_4169.prdoc @@ -0,0 +1,8 @@ +title: Stabilize transactionBroadcast RPC class to version 1 + +doc: + - audience: Node Dev + description: | + The transactionBroadcast RPC API is stabilized to version 1. + +crates: [ ] diff --git a/prdoc/1.11.0/pr_4171.prdoc b/prdoc/1.11.0/pr_4171.prdoc new file mode 100644 index 0000000000000000000000000000000000000000..eef45ba922c52b2f636a77bf280cc7937ad2b140 --- /dev/null +++ b/prdoc/1.11.0/pr_4171.prdoc @@ -0,0 +1,8 @@ +title: Stabilize transactionWatch RPC class to version 1 + +doc: + - audience: Node Dev + description: | + The transactionWatch RPC API is stabilized to version 1. + +crates: [ ] diff --git a/prdoc/1.11.0/pr_4177.prdoc b/prdoc/1.11.0/pr_4177.prdoc new file mode 100644 index 0000000000000000000000000000000000000000..29d011c93516c35af2049dafdec035e4f888ffec --- /dev/null +++ b/prdoc/1.11.0/pr_4177.prdoc @@ -0,0 +1,12 @@ +title: "wasm-builder: Make it easier to build a WASM binary" + +doc: + - audience: [Runtime Dev, Node Dev] + description: | + Combines all the recommended calls of the `WasmBuilder` into + `build_using_defaults()` or `init_with_defaults()` if more changes are required. + Otherwise the interface doesn't change and users can still continue to use + the "old" interface. + +crates: + - name: substrate-wasm-builder diff --git a/prdoc/1.11.0/pr_4189.prdoc b/prdoc/1.11.0/pr_4189.prdoc new file mode 100644 index 0000000000000000000000000000000000000000..74ed7c67cbdeaf17bcc18476e6e011d62e0d8583 --- /dev/null +++ b/prdoc/1.11.0/pr_4189.prdoc @@ -0,0 +1,16 @@ +title: "polkadot_runtime_parachains::coretime: Expose `MaxXcmTransactWeight`" + +doc: + - audience: Runtime Dev + description: | + Expose `MaxXcmTransactWeight` via the `Config` trait. This exposes the + possibility for runtime implementors to set the maximum weight required + for the calls on the coretime chain. Basically it needs to be set to + `max_weight(set_leases, reserve, notify_core_count)` where `set_leases` + etc are the calls on the coretime chain. This ensures that these XCM + transact calls send by the relay chain coretime pallet to the coretime + chain can be dispatched. + +crates: + - name: polkadot-runtime-parachains + bump: major diff --git a/prdoc/1.11.0/pr_4199.prdoc b/prdoc/1.11.0/pr_4199.prdoc new file mode 100644 index 0000000000000000000000000000000000000000..39f08a0532b8c0318c8d71329962da65309f51cd --- /dev/null +++ b/prdoc/1.11.0/pr_4199.prdoc @@ -0,0 +1,29 @@ +title: "Remove XCM SafeCallFilter for chains using Weights::v3" + +doc: + - audience: Runtime User + description: | + `SafeCallFilter` was removed from Rococo and Westend relay and system chains as they + all now use Weights::v3 which already accounts for call PoV size. + This effectively removes artificial limitations on what users can `XCM::Transact` on + these chains (blockspace limitations are still upheld). + +crates: + - name: asset-hub-rococo-runtime + bump: minor + - name: asset-hub-westend-runtime + bump: minor + - name: bridge-hub-rococo-runtime + bump: minor + - name: bridge-hub-westend-runtime + bump: minor + - name: collectives-westend-runtime + bump: minor + - name: coretime-rococo-runtime + bump: minor + - name: coretime-westend-runtime + bump: minor + - name: people-rococo-runtime + bump: minor + - name: people-westend-runtime + bump: minor diff --git a/prdoc/1.11.0/pr_4208.prdoc b/prdoc/1.11.0/pr_4208.prdoc new file mode 100644 index 0000000000000000000000000000000000000000..be2a1b084a5f98f5192590eb6c645c11b8f15bb4 --- /dev/null +++ b/prdoc/1.11.0/pr_4208.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: Fixed GrandpaConsensusLogReader::find_scheduled_change + +doc: + - audience: Runtime Dev + description: | + This PR fixes the issue with authorities set change digest item search + in the bridges code. The issue happens when there are multiple consensus + digest items in the same header digest. + +crates: + - name: bp-header-chain diff --git a/prdoc/1.11.0/pr_4221.prdoc b/prdoc/1.11.0/pr_4221.prdoc new file mode 100644 index 0000000000000000000000000000000000000000..e4941cce892a183c8feafe5b259207dbb0e01c57 --- /dev/null +++ b/prdoc/1.11.0/pr_4221.prdoc @@ -0,0 +1,15 @@ +title: "pallet_broker::start_sales: Take `extra_cores` and not total cores" + +doc: + - audience: Runtime User + description: | + Change `pallet_broker::start_sales` to take `extra_cores` and not total cores. + It will calculate the total number of cores to offer based on number of + reservations plus number of leases plus `extra_cores`. Internally it will + also notify the relay chain of the required number of cores. + + Thus, starting the first sales with `pallet-broker` requires less brain power ;) + +crates: +- name: pallet-broker + bump: minor diff --git a/prdoc/1.11.0/pr_4229.prdoc b/prdoc/1.11.0/pr_4229.prdoc new file mode 100644 index 0000000000000000000000000000000000000000..05af8e062a32b5df8284f269159df53982412531 --- /dev/null +++ b/prdoc/1.11.0/pr_4229.prdoc @@ -0,0 +1,10 @@ +title: "Fix Stuck Collator Funds" + +doc: + - audience: Runtime Dev + description: | + Fixes stuck collator funds by providing a migration that should have been in PR 1340. + +crates: + - name: pallet-collator-selection + bump: patch diff --git a/prdoc/1.11.0/pr_4252.prdoc b/prdoc/1.11.0/pr_4252.prdoc new file mode 100644 index 0000000000000000000000000000000000000000..22987b46845d8382d83e4501301465643167fea4 --- /dev/null +++ b/prdoc/1.11.0/pr_4252.prdoc @@ -0,0 +1,15 @@ +title: "Add logic to increase pvf worker based on chain" + +doc: + - audience: Node Operator + description: | + A new logic and cli parameters were added to allow increasing the number of pvf + workers based on the chain-id. + +crates: + - name: polkadot-node-core-candidate-validation + bump: minor + - name: polkadot-cli + bump: minor + - name: polkadot-service + bump: minor diff --git a/prdoc/pr_2226.prdoc b/prdoc/pr_2226.prdoc new file mode 100644 index 0000000000000000000000000000000000000000..9047dca44558c72bd680fe30239a7905255f0ae6 --- /dev/null +++ b/prdoc/pr_2226.prdoc @@ -0,0 +1,35 @@ +title: Validator disabling strategy in runtime + +doc: + - audience: Node Operator + description: | + On each committed offence (no matter slashable or not) the offending validator will be + disabled for a whole era. Offenders are no longer chilled so the node operator should monitor + the behavior of their validators and act swiftly if they are raising disputes. + - audience: Runtime Dev + description: | + The disabling strategy in staking pallet is no longer hardcoded but abstracted away via + `DisablingStrategy` trait. The trait contains a single function (make_disabling_decision) which + is called for each offence. The function makes a decision if (and which) validators should be + disabled. A default implementation is provided - `UpToLimitDisablingStrategy`. It + will be used on Kusama and Polkadot. In nutshell `UpToLimitDisablingStrategy` + disables offenders up to the configured threshold. Offending validators are not disabled for + offences in previous eras. The threshold is controlled via `DISABLING_LIMIT_FACTOR` (a generic + parameter of `UpToLimitDisablingStrategy`). Also offending validators are no longer chilled + after an offence is committed. This change is made to protect the network in case of honest nodes being slashed. + - audience: RuntimeUser + description: | + Nominators should be aware that the validators are no longer chilled if they commit an offence. + This means that token holders should be extra careful, monitor closely the behavior of their + nominees and take measures if they commit an offence. + +migrations: + db: [] + runtime: + - reference: pallet-staking + description: | + Renames `OffendingValidators` storage item to `DisabledValidators` and changes its type from + `Vec<(u32, bool)>` to `Vec`. + +crates: + - name: pallet-staking \ No newline at end of file diff --git a/prdoc/pr_3444.prdoc b/prdoc/pr_3444.prdoc new file mode 100644 index 0000000000000000000000000000000000000000..3afb38106417bdb3784fba0f7306b04c7705b9cf --- /dev/null +++ b/prdoc/pr_3444.prdoc @@ -0,0 +1,25 @@ +# Schema: Polkadot SDK PRDoc Schema (prdoc) v1.0.0 +# See doc at https://raw.githubusercontent.com/paritytech/polkadot-sdk/master/prdoc/schema_user.json + +title: Rate-limiting of statement distribution v2 requests to 1 per peer + +doc: + - audience: Node Dev + description: | + A new malicious node variant that sends duplicate statement + distribution messages to spam other peers. + + - audience: Node Operator + description: | + Added rate-limiting in the statement distribution request-response + protocol. Requesters will not issue another request to a peer if one + is already pending with that peer and receiving nodes will reject + requests from peers that they are currently serving. + This should reduce the risk of validator-validator DoS attacks and + better load-balance statement distribution. + +crates: + - name: polkadot-test-malus + bump: minor + - name: polkadot-statement-distribution + bump: minor diff --git a/prdoc/pr_3701.prdoc b/prdoc/pr_3701.prdoc new file mode 100644 index 0000000000000000000000000000000000000000..6f9fcc92ad3050df4011a8984053057a3ec91167 --- /dev/null +++ b/prdoc/pr_3701.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 option to whitelist peers in rpc rate limiting + +doc: + - audience: Node Operator + description: | + This PR adds two new CLI options to disable rate limiting for certain ip addresses and whether to trust "proxy headers". + +crates: [ ] diff --git a/prdoc/pr_3865.prdoc b/prdoc/pr_3865.prdoc new file mode 100644 index 0000000000000000000000000000000000000000..8e39c04825b1a525850939e3030f00521e0d0065 --- /dev/null +++ b/prdoc/pr_3865.prdoc @@ -0,0 +1,11 @@ +title: "Balances: add failsafe for consumer ref underflow" + +doc: + - audience: Runtime Dev + description: | + Pallet balances now handles the case that historic accounts violate a invariant that they should have a consumer ref on `reserved > 0` balance. + This disallows such accounts from reaping and should prevent TI from getting messed up even more. + +crates: + - name: pallet-balances + bump: patch diff --git a/prdoc/pr_3872.prdoc b/prdoc/pr_3872.prdoc new file mode 100644 index 0000000000000000000000000000000000000000..3a5be3d2bc74d08ec83aa1cacaceb294e948c563 --- /dev/null +++ b/prdoc/pr_3872.prdoc @@ -0,0 +1,86 @@ +title: XcmDryRunApi - Runtime API for dry-running extrinsics and XCM programs. + +doc: + - audience: Runtime Dev + description: | + This PR introduces a new runtime API, the XcmDryRunApi, that allows dry-running + extrinsics and XCM programs to get their execution effects. + These effects include: + - Local execution result, either pass or fail + - Emitted events + - Forwarded XCMs + - In the case of extrinsics, the XCM program that they execute + This API can be used on its own to test extrinsics or XCM programs, + or used alongside the XcmPaymentApi to estimate execution and delivery + fees. + + This PR also adds a new configuration item to XCM: XcmRecorder. + This can be set to either (), the xcm pallet, or some custom implementation. + If set to (), the dry run API will not return the local XCM program executed + by running an extrinsic. + After this PR, it is necessary to add the new configuration item to your xcm + configs. + - audience: Runtime User + description: | + This PR introduces a new runtime API, the XcmDryRunApi, that allows dry-running + extrinsics and XCM programs to get their execution effects. + These effects include: + - Local execution result, either pass or fail + - Emitted events + - Forwarded XCMs + - In the case of extrinsics, the XCM program that they execute + This API can be used on its own to test extrinsics or XCM programs, + or used alongside the XcmPaymentApi to estimate execution and delivery + fees. + +crates: + - name: xcm-fee-payment-runtime-api + bump: major + - name: pallet-xcm + bump: minor + - name: staging-xcm-executor + bump: minor + - name: staging-xcm-builder + bump: minor + - name: rococo-runtime + bump: minor + - name: westend-runtime + bump: minor + - name: pallet-xcm-benchmarks + bump: minor + - name: asset-hub-rococo-runtime + bump: minor + - name: asset-hub-westend-runtime + bump: minor + - name: bridge-hub-rococo-runtime + bump: minor + - name: bridge-hub-westend-runtime + bump: minor + - name: collectives-westend-runtime + bump: minor + - name: contracts-rococo-runtime + bump: minor + - name: coretime-rococo-runtime + bump: minor + - name: coretime-westend-runtime + bump: minor + - name: glutton-westend-runtime + bump: minor + - name: people-rococo-runtime + bump: minor + - name: people-westend-runtime + bump: minor + - name: shell-runtime + bump: minor + - name: penpal-runtime + bump: minor + - name: rococo-parachain-runtime + bump: minor + - name: polkadot-service + bump: minor + - name: polkadot-test-runtime + bump: minor + - name: parachain-template-runtime + bump: minor + - name: pallet-contracts-mock-network + bump: minor diff --git a/prdoc/pr_3904.prdoc b/prdoc/pr_3904.prdoc new file mode 100644 index 0000000000000000000000000000000000000000..694f9b443877329e02f47d12de4d375b42fefb36 --- /dev/null +++ b/prdoc/pr_3904.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 pallet-delegated-staking + +doc: + - audience: Runtime Dev + description: | + Adds a new pallet `delegated-staking` that allows delegators to delegate their funds to agents who can stake + these funds on behalf of them. This would be used by Nomination Pools to migrate into a delegation staking based + pool. + +crates: + - name: pallet-delegated-staking + bump: patch + - name: pallet-staking + bump: patch + - name: sp-staking + bump: minor diff --git a/prdoc/pr_3952.prdoc b/prdoc/pr_3952.prdoc new file mode 100644 index 0000000000000000000000000000000000000000..2401adbb76c13cbee7c467df1a0284fc9b4fcaa4 --- /dev/null +++ b/prdoc/pr_3952.prdoc @@ -0,0 +1,35 @@ +title: Storage bound the XCMP queue pallet + +doc: + - audience: Runtime Dev + description: | + Enforce upper limits for the number of active XCMP channels, the number of outgoing XCMP + messages per channel and the number of signals per channel. + + ## Integration + + If you see this error in your try-runtime-cli: + ```pre + Max message size for channel is too large. This means that the V5 migration can be front-run and an + attacker could place a large message just right before the migration to make other messages un-decodable. + Please either increase `MaxPageSize` or decrease the `max_message_size` for this channel. Channel max: + 102400, MaxPageSize: 65535 + ``` + + Then increase the `MaxPageSize` of the `cumulus_pallet_xcmp_queue` to something like this: + ```rust + type MaxPageSize = ConstU32<{ 103 * 1024 }>; + ``` + +migrations: + db: [] + + runtime: + - reference: cumulus_pallet_xcmp_queue::migration::v5::MigrateV4ToV5 + description: A No-OP migration is deployed to ensure that all `BoundedVec`s` still decode as expected. + +crates: + - name: cumulus-pallet-xcmp-queue + bump: major + +host_functions: [] diff --git a/prdoc/pr_3962.prdoc b/prdoc/pr_3962.prdoc new file mode 100644 index 0000000000000000000000000000000000000000..7ef59d38ce5cdea9dbf623e71f14c07752d06828 --- /dev/null +++ b/prdoc/pr_3962.prdoc @@ -0,0 +1,12 @@ +title: Change fork calculation algorithm. + +doc: + - audience: Node Dev + description: | + This PR changes the fork calculation and pruning algorithm to enable future block header pruning. + During the finalization of the block we prune known stale forks, so forks are pruned faster. + +crates: + - name: sc-client-api + - name: sc-client-db + - name: sp-blockchain diff --git a/prdoc/pr_3964.prdoc b/prdoc/pr_3964.prdoc new file mode 100644 index 0000000000000000000000000000000000000000..adf0d95b36a41fe3d4f1b1438c47a276e990d76b --- /dev/null +++ b/prdoc/pr_3964.prdoc @@ -0,0 +1,16 @@ +title: Burn extrinsic call and `fn burn_from` `Preservation` argument + +doc: + - audience: Runtime Dev + description: | + pallet-balances extrinsic calls has been expanded with `burn` call. + An argument flag is allowed to specify whether the account should be kept alive or not. + This in turn required a change to the fungible's `pub trait Mutate` `burn_from` function which now + also accepts `Preservation` as an argument. + In order to keep the behavior same as before, developers should simply specify `Preservation::Expandable`. + +crates: + - name: frame-support + bump: major + - name: pallet-balances + bump: minor diff --git a/prdoc/pr_4034.prdoc b/prdoc/pr_4034.prdoc new file mode 100644 index 0000000000000000000000000000000000000000..994811b5d672e8a267a2c647af442eacdf724bcb --- /dev/null +++ b/prdoc/pr_4034.prdoc @@ -0,0 +1,14 @@ +title: "Introduces `TypeWithDefault>`" + +doc: + - audience: Runtime Dev + description: | + This PR introduces a new type `TypeWithDefault>` to be able to provide a + custom default for any type. This can, then, be used to provide the nonce type that returns + the current block number as the default, to avoid replay of immortal transactions. + +crates: +- name: sp-runtime + bump: minor +- name: frame-system + bump: patch diff --git a/prdoc/pr_4035.prdoc b/prdoc/pr_4035.prdoc new file mode 100644 index 0000000000000000000000000000000000000000..0617a6a261898b743d74dc8fa55224012080391b --- /dev/null +++ b/prdoc/pr_4035.prdoc @@ -0,0 +1,24 @@ +title: "Prospective parachains rework" + +doc: + - audience: Node Dev + description: | + Changes prospective-parachains from dealing with trees of unincluded candidates to maintaining only candidate chains + and a number of unconnected candidates (for which we don't yet know the parent candidate but which otherwise seem potentially viable). + This is needed for elastic scaling, in order to have full throughput even if a candidate is validated by a backing group before the parent candidate + is fetched from the other backing group. + Also simplifies the subsystem by no longer allowing parachain cycles. + +crates: + - name: polkadot-node-core-prospective-parachains + bump: major + - name: polkadot-node-core-backing + bump: minor + - name: polkadot-collator-protocol + bump: minor + - name: polkadot-statement-distribution + bump: minor + - name: polkadot-node-subsystem-types + bump: major + - name: polkadot-node-subsystem-util + bump: major diff --git a/prdoc/pr_4091.prdoc b/prdoc/pr_4091.prdoc new file mode 100644 index 0000000000000000000000000000000000000000..5c38a344bd8ad1405dd8d1daaf8f16ee7ffaf06b --- /dev/null +++ b/prdoc/pr_4091.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 the authority-discovery pallet + +doc: + - audience: Runtime Dev + description: | + This PR removed `pallet::getter`s from `pallet-authority-discovery`s storage items. + When accessed inside the pallet, use the syntax `StorageItem::::get()`. + When accessed outside the pallet, use the getters current_authorities() and next_authorities() instead. + +crates: + - name: pallet-authority-discovery + bump: major diff --git a/prdoc/pr_4102.prdoc b/prdoc/pr_4102.prdoc new file mode 100644 index 0000000000000000000000000000000000000000..50c1ec23b2ac1a08c02181727b70bce49f80a0fa --- /dev/null +++ b/prdoc/pr_4102.prdoc @@ -0,0 +1,43 @@ +title: "Bridge: make some headers submissions free" + +doc: + - audience: Runtime Dev + description: | + Adds `FreeHeadersInterval` configuration constant to the `pallet_bridge_grandpa`. + Transactions that improve best known header by at least `FreeHeadersInterval` headers + are now free for the submitter. Additionally, we allow single free parachain header + update per every free relay chain header. Bridge signed extensions are adjusted + to support that new scheme. Bridge runtime APIs are extended to support that new + scheme. Bridge fees are decreased by ~98% because now they do not include cost of + finality submissions - we assume relayers will be submitting finality transactions + for free. + +crates: + - name: bridge-runtime-common + bump: major + - name: bp-bridge-hub-cumulus + bump: patch + - name: bp-bridge-hub-kusama + bump: major + - name: bp-bridge-hub-polkadot + bump: major + - name: bp-bridge-hub-rococo + bump: major + - name: bp-bridge-hub-westend + bump: major + - name: pallet-bridge-grandpa + bump: major + - name: pallet-bridge-parachains + bump: major + - name: bp-parachains + bump: major + - name: bp-runtime + bump: major + - name: relay-substrate-client + bump: major + - name: bridge-hub-rococo-runtime + bump: major + - name: bridge-hub-westend-runtime + bump: major + - name: bridge-hub-test-utils + bump: minor diff --git a/prdoc/pr_4157.prdoc b/prdoc/pr_4157.prdoc new file mode 100644 index 0000000000000000000000000000000000000000..783eaa2dd4276fbf35dd996c06865f734433a3af --- /dev/null +++ b/prdoc/pr_4157.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: "Bridge: added free headers submission support to the substrate-relay" + +doc: + - audience: Node Dev + description: | + Bridge finality and parachains relayer now supports mode, where it only submits some headers + for free. There's a setting in a runtime configuration, which introduces this "free header" + concept. Submitting such header is considered a common good deed, so it is free for relayers. + +crates: + - name: bp-bridge-hub-kusama + bump: major + - name: bp-bridge-hub-polkadot + bump: major + - name: bp-bridge-hub-rococo + bump: major + - name: bp-bridge-hub-westend + bump: major + - name: relay-substrate-client + bump: major + - name: finality-relay + bump: major + - name: substrate-relay-helper + bump: major + - name: parachains-relay + bump: major diff --git a/prdoc/pr_4175.prdoc b/prdoc/pr_4175.prdoc new file mode 100644 index 0000000000000000000000000000000000000000..7fc2fb68b38e610108adc57b9b1e5eb7cec5bd31 --- /dev/null +++ b/prdoc/pr_4175.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: "Snowbridge: deposit extra fee to beneficiary on Asset Hub" + +doc: + - audience: Runtime Dev + description: | + Snowbridge transfers arriving on Asset Hub will deposit both asset and fees to beneficiary so the fees will not get trapped. + Another benefit is when fees left more than ED, could be used to create the beneficiary account in case it does not exist on asset hub. + +crates: + - name: snowbridge-router-primitives diff --git a/prdoc/pr_4185.prdoc b/prdoc/pr_4185.prdoc new file mode 100644 index 0000000000000000000000000000000000000000..88cb6772e5d499cfd542c6cb8f39ca6147877299 --- /dev/null +++ b/prdoc/pr_4185.prdoc @@ -0,0 +1,20 @@ +title: "State trie migration on asset-hub westend and collectives westend" + +doc: + - audience: Node Dev + description: | + On westend and rococo asset-hub and collectives westend the state version is switched to one + and a manual migration will be operate as describe in https://hackmd.io/JagpUd8tTjuKf9HQtpvHIQ + `2.2 Running the signed migration` with account `5F4EbSkZz18X36xhbsjvDNs6NuZ82HyYtq5UiJ1h9SBHJXZD`. + - audience: Runtime User + description: | + On westend and rococo asset-hub and collectives westend the parachain state will migrate + and warpsync will be broken during migration. + +crates: + - name: asset-hub-rococo-runtime + bump: minor + - name: asset-hub-westend-runtime + bump: minor + - name: collectives-westend-runtime + bump: minor diff --git a/prdoc/pr_4202.prdoc b/prdoc/pr_4202.prdoc new file mode 100644 index 0000000000000000000000000000000000000000..6469c3c7840767080b52a6e52d2eea1c7faf3559 --- /dev/null +++ b/prdoc/pr_4202.prdoc @@ -0,0 +1,16 @@ +title: "Treat XCM ExceedsStackLimit errors as transient in the MQ pallet" + +doc: + - audience: Runtime User + description: | + Fixes an issue where the MessageQueue can incorrectly assume that a message will permanently fail to process and disallow retrial of it. + +crates: + - name: frame-support + bump: major + - name: pallet-message-queue + bump: patch + - name: staging-xcm-builder + bump: patch + - name: staging-xcm-executor + bump: patch diff --git a/prdoc/pr_4211.prdoc b/prdoc/pr_4211.prdoc new file mode 100644 index 0000000000000000000000000000000000000000..161dc8485e83ca8de8574b3573b0bb3461f10e15 --- /dev/null +++ b/prdoc/pr_4211.prdoc @@ -0,0 +1,15 @@ +title: "Re-prepare PVF artifacts only if needed" + +doc: + - audience: Node Dev + description: | + When a change in the executor environment parameters can not affect the prepared artifact, + it is preserved without recompilation and used for future executions. That mitigates + situations where every unrelated executor parameter change resulted in re-preparing every + artifact on every validator, causing a significant finality lag. + +crates: + - name: polkadot-node-core-pvf + bump: minor + - name: polkadot-primitives + bump: minor diff --git a/prdoc/pr_4213.prdoc b/prdoc/pr_4213.prdoc new file mode 100644 index 0000000000000000000000000000000000000000..ce7eb65969b06aa54adba7753362fdd5e77c8400 --- /dev/null +++ b/prdoc/pr_4213.prdoc @@ -0,0 +1,11 @@ +title: "[pallet-contracts] stabilize xcm_send and xcm_execute" + +doc: + - audience: Runtime Dev + description: | + `xcm_send` and `xcm_execute` are currently marked as unstable. This PR stabilizes them. +crates: +- name: pallet-contracts + bump: major + + diff --git a/prdoc/pr_4220.prdoc b/prdoc/pr_4220.prdoc new file mode 100644 index 0000000000000000000000000000000000000000..d5688ab325cd1ee013dc235c19ce78af46253fd6 --- /dev/null +++ b/prdoc/pr_4220.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: Refactor XCM Simulator Example + +doc: + - audience: Runtime Dev + description: | + This PR refactors the XCM Simulator Example to improve developer experience when trying to read and understand the example. 3 monolithic files have been broken down into their respective components across various modules. No major logical changes were made. + +crates: [ ] diff --git a/prdoc/pr_4281.prdoc b/prdoc/pr_4281.prdoc new file mode 100644 index 0000000000000000000000000000000000000000..ab2156a9505a666c16e1c079a4cff071a271b21b --- /dev/null +++ b/prdoc/pr_4281.prdoc @@ -0,0 +1,16 @@ +title: "Add support for versioned notification for HRMP pallet" + +doc: + - audience: Runtime Dev + description: | + The configuration of the HRMP pallet has been expanded to include the `VersionWrapper` type, + which controls the encoding of XCM notifications related to the opening/closing of HRMP channels. + If your runtime does not concern itself with the XCM version used for notifications, + you can set it as `type VersionWrapper = ()` to always use the latest XCM. + If your runtime does care about the XCM version when sending to child parachains, + you can provide an instance of the `pallet_xcm` with `type VersionWrapper = XcmPallet`, + which can manage XCM versions for destinations. + +crates: +- name: polkadot-runtime-parachains + bump: major diff --git a/prdoc/pr_4295.prdoc b/prdoc/pr_4295.prdoc new file mode 100644 index 0000000000000000000000000000000000000000..e8b2010a8496fcb5f04bb449139c075b0e8894b5 --- /dev/null +++ b/prdoc/pr_4295.prdoc @@ -0,0 +1,14 @@ +title: "Make parachain template async backing ready" + +doc: + - audience: Node Dev + description: | + Promotes the parachain template (both node and runtime) to use async backing APIs so that + developers starting a new project from the template could get async backing integrated out + of the box. + +crates: + - name: parachain-template-node + bump: major + - name: parachain-template-runtime + bump: major diff --git a/prdoc/pr_4301.prdoc b/prdoc/pr_4301.prdoc new file mode 100644 index 0000000000000000000000000000000000000000..2ca2534243a8e1875ae2ef30b164d05a5c36f95e --- /dev/null +++ b/prdoc/pr_4301.prdoc @@ -0,0 +1,13 @@ +title: New runtime api to check if a validator has pending pages of rewards for an era. + +doc: + - audience: + - Node Dev + - Runtime User + description: | + Creates a new runtime api to check if reward for an era is pending for a validator. Era rewards are paged and this + api will return true as long as there is one or more pages of era reward which are not claimed. + +crates: +- name: pallet-staking +- name: pallet-staking-runtime-api diff --git a/prdoc/pr_4302.prdoc b/prdoc/pr_4302.prdoc new file mode 100644 index 0000000000000000000000000000000000000000..bb4331f280239ffb3a8ee44d912916f8b23b91cb --- /dev/null +++ b/prdoc/pr_4302.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: "migrations: take() should consume read and write operation weight" + +doc: + - audience: Runtime Dev + description: | + `take()` consumes only 1 read worth of weight in `single-block-migrations` example, while `take()` is `get() + kill()`, + i.e should be 1 read + 1 write. Since this could mislead developers writing migrations following the example, + this PR fixes the weight calculation. + +crates: + - name: pallet-example-single-block-migrations + bump: minor diff --git a/prdoc/pr_4311.prdoc b/prdoc/pr_4311.prdoc new file mode 100644 index 0000000000000000000000000000000000000000..cf32acaf00895995da73df90b7f6be1053d77ac9 --- /dev/null +++ b/prdoc/pr_4311.prdoc @@ -0,0 +1,9 @@ +title: Not allow reap stash for virtual stakers. + +doc: + - audience: Runtime Dev + description: | + Add guards to staking dispathables to prevent virtual stakers to be reaped. + +crates: +- name: pallet-staking diff --git a/prdoc/pr_4312.prdoc b/prdoc/pr_4312.prdoc new file mode 100644 index 0000000000000000000000000000000000000000..d773edbd14de113c5106485210683aedf491e9ba --- /dev/null +++ b/prdoc/pr_4312.prdoc @@ -0,0 +1,19 @@ +title: Add `Deposited`/`Withdrawn` events for `pallet-assets` + +doc: + - audience: Runtime Dev + description: | + New events were added to `pallet-assets`: `Deposited` and `Withdrawn`. Make sure + to cover those events on tests if necessary. + - audience: Runtime User + description: | + New events were added to `pallet-assets`: `Deposited` and `Withdrawn`. These indicate + a change in the balance of an account. + +crates: + - name: pallet-assets + bump: minor + - name: pallet-asset-tx-payment + bump: minor + - name: pallet-asset-conversion-tx-payment + bump: minor diff --git a/prdoc/pr_4326.prdoc b/prdoc/pr_4326.prdoc new file mode 100644 index 0000000000000000000000000000000000000000..b448bd7e52e76be92924761b8fd925e9b5083247 --- /dev/null +++ b/prdoc/pr_4326.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: CheckWeight checks for combined extrinsic length and proof size + +doc: + - audience: Runtime Dev + description: | + The `CheckWeight` `SignedExtension` will now perform an additional check. The extension was verifying the extrinsic length and + weight limits individually. However, the proof size dimension of the weight and extrinsic length together are bound by the PoV size limit. + The `CheckWeight` extension will now check that the combined size of the proof and the extrinsic lengths will not + exceed the PoV size limit. + +crates: + - name: frame-system + bump: minor diff --git a/prdoc/pr_4329.prdoc b/prdoc/pr_4329.prdoc new file mode 100644 index 0000000000000000000000000000000000000000..2fe11a60f4baad8374c751a6b533c495ed7152b3 --- /dev/null +++ b/prdoc/pr_4329.prdoc @@ -0,0 +1,14 @@ +title: "Deprecate `NativeElseWasmExecutor`" + +doc: + - audience: Node Dev + description: | + Deprecates the `NativeElseWasmExecutor` as native execution is already + discouraged and should be removed entirely. The executor should be + replaced by `WasmExecutor` which can be found in `sc-executor`. + + The `NativeElseWasmExecutor` will be removed at the end of 2024. + +crates: + - name: sc-executor + bump: minor diff --git a/prdoc/pr_4346.prdoc b/prdoc/pr_4346.prdoc new file mode 100644 index 0000000000000000000000000000000000000000..e222dec885ced40df8b4b783078e88b0b1e42f40 --- /dev/null +++ b/prdoc/pr_4346.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: Allow for 0 existential deposit in benchmarks for pallet_staking, pallet_session, and pallet_balances + +doc: + - audience: Runtime Dev + description: | + Changes were made to benchmarks for `pallet_staking`, `pallet_session`, and `pallet-balances` to accommodate runtimes with 0 existential deposit. This should not affect the vast majority of runtimes. For runtimes with 0 existential deposit, the benchmarks for `pallet_staking` and `pallet_session` will still fail when using `U128CurrencyToVote` in the `pallet-staking` config; developers can use or write another `CurrencyToVote` implementation for benchmarking to work around this. + +crates: + - name: pallet-staking + bump: patch + - name: pallet-session-benchmarking + bump: patch + - name: pallet-balances + bump: patch diff --git a/prdoc/pr_4349.prdoc b/prdoc/pr_4349.prdoc new file mode 100644 index 0000000000000000000000000000000000000000..fdc9e816e1b9630cb505f7d8270850ad9450c57e --- /dev/null +++ b/prdoc/pr_4349.prdoc @@ -0,0 +1,9 @@ +title: "Store Header in RemoteExt Snapshot" + +doc: + - audience: Runtime Dev + description: Replaces the block hash in the RemoteExt snapshot with the block header. + +crates: + - name: frame-remote-externalities + bump: major diff --git a/prdoc/pr_4364.prdoc b/prdoc/pr_4364.prdoc new file mode 100644 index 0000000000000000000000000000000000000000..88ee8d12286dbc31f2ae1a6ef64b78ad223d836f --- /dev/null +++ b/prdoc/pr_4364.prdoc @@ -0,0 +1,10 @@ +title: Fix dust unbonded for zero existential deposit + +doc: + - audience: Runtime Dev + description: | + When a staker unbonds and withdraws, it is possible that their stash will contain less currency than the existential deposit. If that happens, their stash is reaped. But if the existential deposit is zero, the reap is not triggered. This PR adjusts pallet_staking to reap a stash in the special case that the stash value is zero and the existential deposit is zero. + +crates: + - name: pallet-staking + bump: patch diff --git a/prdoc/pr_4392.prdoc b/prdoc/pr_4392.prdoc new file mode 100644 index 0000000000000000000000000000000000000000..898ce9be069e20a09ccbe1ee4a85bcec36893f02 --- /dev/null +++ b/prdoc/pr_4392.prdoc @@ -0,0 +1,16 @@ +# Schema: Polkadot SDK PRDoc Schema (prdoc) v1.0.0 +# See doc at https://raw.githubusercontent.com/paritytech/polkadot-sdk/master/prdoc/schema_user.json + +title: Remove `pallet::getter` usage from both bounties and child bounties pallet + +doc: + - audience: Runtime Dev + description: | + This PR removes `pallet::getter`s from `pallet-bounties` and `pallet-child-bounties`. + The syntax `StorageItem::::get()` should be used instead. + +crates: + - name: pallet-bounties + bump: major + - name: pallet-child-bounties + bump: major diff --git a/prdoc/pr_4394.prdoc b/prdoc/pr_4394.prdoc new file mode 100644 index 0000000000000000000000000000000000000000..16409236c94f9240623a56ae9481f3040e27958d --- /dev/null +++ b/prdoc/pr_4394.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 Kusama People Chain genesis chainspec + +doc: + - audience: Node Operator + description: | + Adds the Kusama People Chain chain spec with the genesis head data and add to + `polkadot-parachain`. + +crates: + - name: polkadot-parachain-bin + bump: minor diff --git a/prdoc/pr_4406.prdoc b/prdoc/pr_4406.prdoc new file mode 100644 index 0000000000000000000000000000000000000000..9372b532512b57f6895076f3b5cf561c1bd4a059 --- /dev/null +++ b/prdoc/pr_4406.prdoc @@ -0,0 +1,10 @@ +title: Adds benchmarking and try-runtime support in `polkadot-sdk-frame` crate + +doc: + - audience: Runtime Dev + description: | + Adds benchmarking and try-runtime support in `polkadot-sdk-frame` crate + +crates: + - name: polkadot-sdk-frame + bump: minor diff --git a/prdoc/pr_4414.prdoc b/prdoc/pr_4414.prdoc new file mode 100644 index 0000000000000000000000000000000000000000..864e816be91a9632859c9b11bf992af5ae7832b4 --- /dev/null +++ b/prdoc/pr_4414.prdoc @@ -0,0 +1,10 @@ +title: "Rococo Asset Hub: undeploy state-trie migration" + +doc: + - audience: Runtime Dev + description: | + The state-trie migration on the Rococo Asset Hub is completed and is now removed. + +crates: + - name: asset-hub-rococo-runtime + bump: major diff --git a/prdoc/pr_4417.prdoc b/prdoc/pr_4417.prdoc new file mode 100644 index 0000000000000000000000000000000000000000..5aa72edd066a7de2a8e66ca1464446c503802644 --- /dev/null +++ b/prdoc/pr_4417.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: Removed `pallet::getter` usage from pallet-contracts-mock-network + +doc: + - audience: Runtime Dev + description: | + This PR removed the `pallet::getter`s from `pallet-contracts-mock-network`s storage items. + +crates: + - name: pallet-contracts-mock-network + bump: minor diff --git a/prdoc/pr_4426.prdoc b/prdoc/pr_4426.prdoc new file mode 100644 index 0000000000000000000000000000000000000000..5beccbd2a57a593b4937b9f9fbd7c3552d80cc2c --- /dev/null +++ b/prdoc/pr_4426.prdoc @@ -0,0 +1,15 @@ +title: "Remove warning about `BadCertificate`" + +doc: + - audience: Node Operator + description: | + The node was printing the following warning from time to time: + ``` + Sending fatal alert BadCertificate + ``` + + This is not an user error and thus, the warning will now not be printed + anymore. + +crates: + - name: sc-cli diff --git a/prdoc/pr_4442.prdoc b/prdoc/pr_4442.prdoc new file mode 100644 index 0000000000000000000000000000000000000000..ee6ac29e1a1045c67679d4014b893f3eafa8a9f8 --- /dev/null +++ b/prdoc/pr_4442.prdoc @@ -0,0 +1,13 @@ +# Schema: Polkadot SDK PRDoc Schema (prdoc) v1.0.0 +# See doc at https://raw.githubusercontent.com/paritytech/polkadot-sdk/master/prdoc/schema_user.json + +title: Improve mock relay in --dev mode to support async backing + +doc: + - audience: Node Dev + description: | + Support async backing in --dev mode. Improve the relay mock MockValidationDataInherentDataProvider to mach expectations of async backing runtimes. + +crates: + - name: cumulus-client-parachain-inherent + bump: patch diff --git a/prdoc/pr_4457.prdoc b/prdoc/pr_4457.prdoc new file mode 100644 index 0000000000000000000000000000000000000000..5c9bd9822769745adcb916b52e98923fc3e555a5 --- /dev/null +++ b/prdoc/pr_4457.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: "sc-service: export all public functions" + +doc: + - audience: Node Dev + description: | + A PR #3166 converted private functions used in `spawn_tasks()` to public to make it possible to have custom + implementation of the `spawn_tasks()`. However, not all functions were included in the list of exports from + `sc-service` crate. + +crates: + - name: sc-service + bump: minor diff --git a/prdoc/pr_4461.prdoc b/prdoc/pr_4461.prdoc new file mode 100644 index 0000000000000000000000000000000000000000..2dafa3812878b4a2767a91d5ad2121bd23652310 --- /dev/null +++ b/prdoc/pr_4461.prdoc @@ -0,0 +1,10 @@ +title: Fix extrinsics count logging in frame-system + +doc: + - audience: Runtime Dev + description: | + Fixes the issue of the number of extrinsics in the block always being 0 in the log of frame-system. + +crates: + - name: frame-system + bump: patch diff --git a/prdoc/pr_4472.prdoc b/prdoc/pr_4472.prdoc new file mode 100644 index 0000000000000000000000000000000000000000..cd7527d73d6ba3689d9623c09a591ed61ab5da42 --- /dev/null +++ b/prdoc/pr_4472.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: Remove `pallet::getter` usage from pallet-democracy + +doc: + - audience: Runtime Dev + description: | + This PR removes the `pallet::getter`s from `pallet-democracy`. + The syntax `StorageItem::::get()` should be used instead. + +crates: + - name: pallet-democracy + bump: major diff --git a/prdoc/pr_4475.prdoc b/prdoc/pr_4475.prdoc new file mode 100644 index 0000000000000000000000000000000000000000..30093dcd32b89d8f34c00154ee73fc60ced0b00a --- /dev/null +++ b/prdoc/pr_4475.prdoc @@ -0,0 +1,10 @@ +title: "Deprecate dmp-queue pallet" + +doc: + - audience: Runtime Dev + description: | + Schedule the DMP queue pallet for deletion. It is not needed anymore sine https://github.com/paritytech/polkadot-sdk/pull/1246. + +crates: + - name: cumulus-pallet-dmp-queue + bump: minor diff --git a/prdoc/pr_4478.prdoc b/prdoc/pr_4478.prdoc new file mode 100644 index 0000000000000000000000000000000000000000..22e2e43db4caff9d405ca0ca8c4915416e7df1f5 --- /dev/null +++ b/prdoc/pr_4478.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: Snowbridge - Ethereum Client - Reject finalized updates without a sync committee in next store period + +doc: + - audience: Runtime Dev + description: | + Bug fix in the Ethereum light client that stalls the light client when an update in the next sync committee period is received without receiving the next sync committee update in the next period. + +crates: + - name: snowbridge-pallet-ethereum-client + bump: patch diff --git a/prdoc/schema_user.json b/prdoc/schema_user.json index 6b44b1b28dfb859dde52e46974a6ef1d06aa3722..294005f209d57d719816a40132ea7f5d49b3d029 100644 --- a/prdoc/schema_user.json +++ b/prdoc/schema_user.json @@ -140,6 +140,9 @@ "bump": { "$ref": "#/$defs/semver_bump" }, + "validate": { + "$ref": "#/$defs/semver_validate" + }, "note": { "type": "string" } @@ -183,6 +186,11 @@ "description" ] }, + "semver_validate": { + "type": "boolean", + "description": "Whether or not to validate the specified semver bump.", + "default": true + }, "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": [ @@ -200,6 +208,11 @@ "const": "patch", "title": "Patch", "description": "A bump to the third leftmost non-zero digit of the version number." + }, + { + "const": "none", + "title": "None", + "description": "This change requires no SemVer bump (e.g. change was a test)." } ] }, diff --git a/scripts/release/build-changelogs.sh b/scripts/release/build-changelogs.sh index 84054391936294adbd13340932f2ac5c458692aa..d73f06c8cd6bb3f8a0814fd797a19da951d51418 100755 --- a/scripts/release/build-changelogs.sh +++ b/scripts/release/build-changelogs.sh @@ -2,11 +2,10 @@ export PRODUCT=polkadot export VERSION=${VERSION:-1.5.0} -export ENGINE=${ENGINE:-docker} +export ENGINE=${ENGINE:-podman} export REF1=${REF1:-'HEAD'} export REF2=${REF2} export RUSTC_STABLE=${RUSTC_STABLE:-'1.0'} -export RUSTC_NIGHTLY=${RUSTC_NIGHTLY:-'1.0'} PROJECT_ROOT=`git rev-parse --show-toplevel` echo $PROJECT_ROOT @@ -27,35 +26,43 @@ echo -e "OUTPUT: \t\t$OUTPUT" mkdir -p $OUTPUT $ENGINE run --rm -v ${PROJECT_ROOT}:/repo paritytech/prdoc load -d "prdoc/$VERSION" --json > $DATA_JSON -# ls -al $DATA_JSON cat $DATA_JSON | jq ' { "prdoc" : .}' > $CONTEXT_JSON -# ls -al $CONTEXT_JSON -# Fetch the list of valid audiences +# Fetch the list of valid audiences and their descriptions SCHEMA_URL=https://raw.githubusercontent.com/paritytech/polkadot-sdk/master/prdoc/schema_user.json SCHEMA=$(curl -s $SCHEMA_URL | sed 's|^//.*||') -AUDIENCE_ARRAY=$(echo -E $SCHEMA | jq -r '."$defs".audience.oneOf[] | .const') - -readarray -t audiences < <(echo "$AUDIENCE_ARRAY") -declare -p audiences - - -# Generate a changelog -echo "Generating changelog..." -tera -t "${TEMPLATE_CHANGELOG}" --env --env-key env "${CONTEXT_JSON}" > "$OUTPUT/changelog.md" -echo "Changelog ready in $OUTPUT/changelog.md" +aud_desc_array=() +while IFS= read -r line; do + audience=$(jq -r '.const' <<< "$line" ) + description=$(jq -r '.description' <<< "$line") + if [ -n "$audience" ] && [ -n "$description" ]; then + aud_desc_array+=("($audience; $description)") + fi +done < <(jq -c '."$defs".audience_id.oneOf[]' <<< "$SCHEMA") # Generate a release notes doc per audience -for audience in "${audiences[@]}"; do +for tuple in "${aud_desc_array[@]}"; do + audience=$(echo "$tuple" | cut -d ';' -f 1 | sed 's/(//') audience_id="$(tr [A-Z] [a-z] <<< "$audience")" audience_id="$(tr ' ' '_' <<< "$audience_id")" + + description=$(echo "$tuple" | cut -d ';' -f 2 | sed 's/)//') + echo "Processing audience: $audience ($audience_id)" - export TARGET_AUDIENCE=$audience + export TARGET_AUDIENCE="$audience" + export AUDIENCE_DESC="**ℹ️ These changes are relevant to:** $description" + tera -t "${TEMPLATE_AUDIENCE}" --env --env-key env "${CONTEXT_JSON}" > "$OUTPUT/relnote_${audience_id}.md" cat "$OUTPUT/relnote_${audience_id}.md" >> "$PROJECT_ROOT/scripts/release/templates/changelog.md" done + +# Generate a changelog containing list of the commits +echo "Generating changelog..." +tera -t "${TEMPLATE_CHANGELOG}" --env --env-key env "${CONTEXT_JSON}" > "$OUTPUT/relnote_commits.md" +echo "Changelog ready in $OUTPUT/relnote_commits.md" + # Show the files tree -s -h -c $OUTPUT/ diff --git a/scripts/release/templates/_free_notes.md.tera b/scripts/release/templates/_free_notes.md.tera new file mode 100644 index 0000000000000000000000000000000000000000..c4a841a992515a0016f8aec99cc0038e7428cafb --- /dev/null +++ b/scripts/release/templates/_free_notes.md.tera @@ -0,0 +1,10 @@ + +{# This file uses the Markdown format with additional templating such as this comment. -#} +{# Such a comment will not show up in the rendered release notes. -#} +{# The content of this file (if any) will be inserted at the top of the release notes -#} +{# and generated for each new release candidate. -#} +{# Ensure you leave an empty line at both top and bottom of this file. -#} + + + + diff --git a/scripts/release/templates/audience.md.tera b/scripts/release/templates/audience.md.tera index 0b47850e3a37026a5aa5562cd685cbca48bde6f0..237643cfa3926688ed0d09c9874e4643a218a486 100644 --- a/scripts/release/templates/audience.md.tera +++ b/scripts/release/templates/audience.md.tera @@ -1,5 +1,7 @@ ### Changelog for `{{ env.TARGET_AUDIENCE }}` +{{ env.AUDIENCE_DESC }} + {% for file in prdoc -%} {% for doc_item in file.content.doc %} {%- if doc_item.audience == env.TARGET_AUDIENCE %} diff --git a/scripts/release/templates/docker_image.md.tera b/scripts/release/templates/docker_image.md.tera new file mode 100644 index 0000000000000000000000000000000000000000..273635670e17ae365576bcb9ea8b707c00804a24 --- /dev/null +++ b/scripts/release/templates/docker_image.md.tera @@ -0,0 +1,19 @@ + +## Docker images + +The docker images for the `polkadot` node binary and the `polkadot-parachain` binary can be found at Docker hub (will be available a few minutes after the release has been published): +- [Polkadot image](https://hub.docker.com/r/parity/polkadot/tags?page=1&ordering=last_updated) +- [Polkadot-Parachain image](https://hub.docker.com/r/parity/polkadot-parachain/tags?page=1&ordering=last_updated) + + +You may also pull it with: + +``` +docker pull parity/polkadot:latest +``` + +or + +``` +docker pull parity/polkadot-parachain:latest +``` diff --git a/scripts/release/templates/template.md.tera b/scripts/release/templates/template.md.tera index 39bc1c74402173a04021c20b340be1239e77bb64..0211cafb428b7cad37a0eee7f43b58f8b10b574b 100644 --- a/scripts/release/templates/template.md.tera +++ b/scripts/release/templates/template.md.tera @@ -2,8 +2,14 @@ This release contains the changes from `{{ env.REF1 | replace(from="refs/tags/", to="") }}` to `{{ env.REF2 | replace(from="refs/tags/", to="") }}`. +{# -- Manual free notes section -- #} +{% include "_free_notes.md.tera" -%} + +{# -- Automatic section -- #} {% include "changes.md.tera" -%} {% include "compiler.md.tera" -%} {% include "runtimes.md.tera" -%} + +{% include "docker_image.md.tera" -%} diff --git a/substrate/bin/node/bench/Cargo.toml b/substrate/bin/node/bench/Cargo.toml index 49485fe2a1b9b8017ec560adef2f0f2114b07b5d..b756f3504655bf44f0b5e51699026dcd82afaca3 100644 --- a/substrate/bin/node/bench/Cargo.toml +++ b/substrate/bin/node/bench/Cargo.toml @@ -15,7 +15,7 @@ workspace = true # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] -array-bytes = "6.1" +array-bytes = "6.2.2" clap = { version = "4.5.3", features = ["derive"] } log = { workspace = true, default-features = true } node-primitives = { path = "../primitives" } diff --git a/substrate/bin/node/cli/Cargo.toml b/substrate/bin/node/cli/Cargo.toml index e6f754fa40b1b6e7cc8faba9e149ee726be3b85b..ec9d6c306b58ffee59a7e9f4c9add93b828edd27 100644 --- a/substrate/bin/node/cli/Cargo.toml +++ b/substrate/bin/node/cli/Cargo.toml @@ -40,9 +40,9 @@ crate-type = ["cdylib", "rlib"] [dependencies] # third-party dependencies -array-bytes = "6.1" +array-bytes = "6.2.2" clap = { version = "4.5.3", features = ["derive"], optional = true } -codec = { package = "parity-scale-codec", version = "3.6.1" } +codec = { package = "parity-scale-codec", version = "3.6.12" } serde = { features = ["derive"], workspace = true, default-features = true } jsonrpsee = { version = "0.22", features = ["server"] } futures = "0.3.30" @@ -132,11 +132,11 @@ sp-crypto-hashing = { path = "../../../primitives/crypto/hashing" } futures = "0.3.30" tempfile = "3.1.0" assert_cmd = "2.0.2" -nix = { version = "0.26.1", features = ["signal"] } +nix = { version = "0.28.0", features = ["signal"] } regex = "1.6.0" platforms = "3.0" soketto = "0.7.1" -criterion = { version = "0.4.0", features = ["async_tokio"] } +criterion = { version = "0.5.1", features = ["async_tokio"] } tokio = { version = "1.22.0", features = ["macros", "parking_lot", "time"] } tokio-util = { version = "0.7.4", features = ["compat"] } wait-timeout = "0.2" @@ -170,7 +170,6 @@ 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 } substrate-build-script-utils = { path = "../../../utils/build-script-utils", optional = true } -substrate-frame-cli = { path = "../../../utils/frame/frame-utilities-cli", optional = true } sc-cli = { path = "../../../client/cli", optional = true } pallet-balances = { path = "../../../frame/balances" } sc-storage-monitor = { path = "../../../client/storage-monitor" } @@ -185,7 +184,6 @@ cli = [ "sc-cli", "sc-service/rocksdb", "substrate-build-script-utils", - "substrate-frame-cli", ] runtime-benchmarks = [ "frame-benchmarking-cli/runtime-benchmarks", diff --git a/substrate/bin/node/cli/benches/block_production.rs b/substrate/bin/node/cli/benches/block_production.rs index f60610873d8c5a3832c77864a2c93fed023998ea..ef7ae4fdf26308827e2745d4cb54c8fe21fbc14f 100644 --- a/substrate/bin/node/cli/benches/block_production.rs +++ b/substrate/bin/node/cli/benches/block_production.rs @@ -86,6 +86,8 @@ fn new_node(tokio_handle: Handle) -> node_cli::service::NewFullBase { rpc_message_buffer_capacity: Default::default(), rpc_batch_config: RpcBatchRequestConfig::Unlimited, rpc_rate_limit: None, + rpc_rate_limit_whitelisted_ips: Default::default(), + rpc_rate_limit_trust_proxy_headers: Default::default(), prometheus_config: None, telemetry_endpoints: None, default_heap_pages: None, diff --git a/substrate/bin/node/cli/benches/transaction_pool.rs b/substrate/bin/node/cli/benches/transaction_pool.rs index 1906ae697e9007ece7539757dbd40d9f504007bd..c4488415b98343a15c8c81eb2ff164db4b36fa29 100644 --- a/substrate/bin/node/cli/benches/transaction_pool.rs +++ b/substrate/bin/node/cli/benches/transaction_pool.rs @@ -82,6 +82,8 @@ fn new_node(tokio_handle: Handle) -> node_cli::service::NewFullBase { rpc_message_buffer_capacity: Default::default(), rpc_batch_config: RpcBatchRequestConfig::Unlimited, rpc_rate_limit: None, + rpc_rate_limit_whitelisted_ips: Default::default(), + rpc_rate_limit_trust_proxy_headers: Default::default(), prometheus_config: None, telemetry_endpoints: None, default_heap_pages: None, diff --git a/substrate/bin/node/inspect/Cargo.toml b/substrate/bin/node/inspect/Cargo.toml index 8453aa3cdeb18715afede5d93fb52f3c6b39be7e..5e4488903bf45fa32dd1f219bf9cf5766522e5bd 100644 --- a/substrate/bin/node/inspect/Cargo.toml +++ b/substrate/bin/node/inspect/Cargo.toml @@ -16,7 +16,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] clap = { version = "4.5.3", features = ["derive"] } -codec = { package = "parity-scale-codec", version = "3.6.1" } +codec = { package = "parity-scale-codec", version = "3.6.12" } thiserror = { workspace = true } sc-cli = { path = "../../../client/cli" } sc-client-api = { path = "../../../client/api" } diff --git a/substrate/bin/node/runtime/Cargo.toml b/substrate/bin/node/runtime/Cargo.toml index f4ed75b919642811ace4147076245c912a0e7d07..98b8c0ae6bf35a85e5cb2225d4a4b5101f3f73e3 100644 --- a/substrate/bin/node/runtime/Cargo.toml +++ b/substrate/bin/node/runtime/Cargo.toml @@ -19,7 +19,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] # third-party dependencies -codec = { package = "parity-scale-codec", version = "3.6.1", default-features = false, features = [ +codec = { package = "parity-scale-codec", version = "3.6.12", default-features = false, features = [ "derive", "max-encoded-len", ] } @@ -66,6 +66,7 @@ frame-system-rpc-runtime-api = { path = "../../../frame/system/rpc/runtime-api", frame-try-runtime = { path = "../../../frame/try-runtime", default-features = false, optional = true } pallet-alliance = { path = "../../../frame/alliance", default-features = false } pallet-asset-conversion = { path = "../../../frame/asset-conversion", default-features = false } +pallet-asset-conversion-ops = { path = "../../../frame/asset-conversion/ops", default-features = false } pallet-asset-rate = { path = "../../../frame/asset-rate", default-features = false } pallet-assets = { path = "../../../frame/assets", default-features = false } pallet-authority-discovery = { path = "../../../frame/authority-discovery", default-features = false } @@ -166,6 +167,7 @@ std = [ "log/std", "node-primitives/std", "pallet-alliance/std", + "pallet-asset-conversion-ops/std", "pallet-asset-conversion-tx-payment/std", "pallet-asset-conversion/std", "pallet-asset-rate/std", @@ -278,6 +280,7 @@ runtime-benchmarks = [ "frame-system-benchmarking/runtime-benchmarks", "frame-system/runtime-benchmarks", "pallet-alliance/runtime-benchmarks", + "pallet-asset-conversion-ops/runtime-benchmarks", "pallet-asset-conversion/runtime-benchmarks", "pallet-asset-rate/runtime-benchmarks", "pallet-asset-tx-payment/runtime-benchmarks", @@ -354,6 +357,7 @@ try-runtime = [ "frame-system/try-runtime", "frame-try-runtime/try-runtime", "pallet-alliance/try-runtime", + "pallet-asset-conversion-ops/try-runtime", "pallet-asset-conversion-tx-payment/try-runtime", "pallet-asset-conversion/try-runtime", "pallet-asset-rate/try-runtime", diff --git a/substrate/bin/node/runtime/src/constants.rs b/substrate/bin/node/runtime/src/constants.rs index e4fafbf0fa4790121787788cef8aa2547b226cf3..d13dca48d1f125acdc38217b677279f259a35aa5 100644 --- a/substrate/bin/node/runtime/src/constants.rs +++ b/substrate/bin/node/runtime/src/constants.rs @@ -50,7 +50,7 @@ pub mod time { /// always be assigned, in which case `MILLISECS_PER_BLOCK` and /// `SLOT_DURATION` should have the same value. /// - /// + /// pub const MILLISECS_PER_BLOCK: Moment = 3000; pub const SECS_PER_BLOCK: Moment = MILLISECS_PER_BLOCK / 1000; diff --git a/substrate/bin/node/runtime/src/lib.rs b/substrate/bin/node/runtime/src/lib.rs index faf7cf7967b74f70a8437e2e7e2ee7fb4d98e37c..017ee9100f9e5ff8124b2446cd5d9333b93a64da 100644 --- a/substrate/bin/node/runtime/src/lib.rs +++ b/substrate/bin/node/runtime/src/lib.rs @@ -63,7 +63,7 @@ use frame_system::{ }; pub use node_primitives::{AccountId, Signature}; use node_primitives::{AccountIndex, Balance, BlockNumber, Hash, Moment, Nonce}; -use pallet_asset_conversion::{Ascending, Chain, WithFirstAsset}; +use pallet_asset_conversion::{AccountIdConverter, Ascending, Chain, WithFirstAsset}; use pallet_broker::{CoreAssignment, CoreIndex, CoretimeInterface, PartsOf57600}; use pallet_election_provider_multi_phase::{GeometricDepositBase, SolutionAccuracyOf}; use pallet_identity::legacy::IdentityInfo; @@ -654,7 +654,6 @@ parameter_types! { pub const SlashDeferDuration: sp_staking::EraIndex = 24 * 7; // 1/4 the bonding duration. pub const RewardCurve: &'static PiecewiseLinear<'static> = &REWARD_CURVE; pub const MaxNominators: u32 = 64; - pub const OffendingValidatorsThreshold: Perbill = Perbill::from_percent(17); pub const MaxControllersInDeprecationBatch: u32 = 5900; pub OffchainRepeat: BlockNumber = 5; pub HistoryDepth: u32 = 84; @@ -690,7 +689,6 @@ impl pallet_staking::Config for Runtime { type EraPayout = pallet_staking::ConvertCurve; type NextNewSession = Session; type MaxExposurePageSize = ConstU32<256>; - type OffendingValidatorsThreshold = OffendingValidatorsThreshold; type ElectionProvider = ElectionProviderMultiPhase; type GenesisElectionProvider = onchain::OnChainExecution; type VoterList = VoterList; @@ -703,6 +701,7 @@ impl pallet_staking::Config for Runtime { type EventListeners = NominationPools; type WeightInfo = pallet_staking::weights::SubstrateWeight; type BenchmarkingConfig = StakingBenchmarkingConfig; + type DisablingStrategy = pallet_staking::UpToLimitDisablingStrategy; } impl pallet_fast_unstake::Config for Runtime { @@ -1710,8 +1709,17 @@ impl pallet_asset_conversion::Config for Runtime { type Assets = UnionOf, AccountId>; type PoolId = (Self::AssetKind, Self::AssetKind); type PoolLocator = Chain< - WithFirstAsset>, - Ascending>, + WithFirstAsset< + Native, + AccountId, + NativeOrWithId, + AccountIdConverter, + >, + Ascending< + AccountId, + NativeOrWithId, + AccountIdConverter, + >, >; type PoolAssetId = >::AssetId; type PoolAssets = PoolAssets; @@ -1728,6 +1736,19 @@ impl pallet_asset_conversion::Config for Runtime { type BenchmarkHelper = (); } +impl pallet_asset_conversion_ops::Config for Runtime { + type RuntimeEvent = RuntimeEvent; + type PriorAccountIdConverter = pallet_asset_conversion::AccountIdConverterNoSeed<( + NativeOrWithId, + NativeOrWithId, + )>; + type AssetsRefund = ::Assets; + type PoolAssetsRefund = ::PoolAssets; + type PoolAssetsTeam = ::PoolAssets; + type DepositAsset = Balances; + type WeightInfo = pallet_asset_conversion_ops::weights::SubstrateWeight; +} + parameter_types! { pub const QueueCount: u32 = 300; pub const MaxQueueLen: u32 = 1000; @@ -2474,6 +2495,9 @@ mod runtime { #[runtime::pallet_index(78)] pub type PalletExampleMbms = pallet_example_mbm; + + #[runtime::pallet_index(79)] + pub type AssetConversionMigration = pallet_asset_conversion_ops; } /// The address format for describing accounts. @@ -2633,6 +2657,7 @@ mod benches { [pallet_tx_pause, TxPause] [pallet_safe_mode, SafeMode] [pallet_example_mbm, PalletExampleMbms] + [pallet_asset_conversion_ops, AssetConversionMigration] ); } @@ -2766,6 +2791,10 @@ impl_runtime_apis! { fn eras_stakers_page_count(era: sp_staking::EraIndex, account: AccountId) -> sp_staking::Page { Staking::api_eras_stakers_page_count(era, account) } + + fn pending_rewards(era: sp_staking::EraIndex, account: AccountId) -> bool { + Staking::api_pending_rewards(era, account) + } } impl sp_consensus_babe::BabeApi for Runtime { @@ -3024,7 +3053,7 @@ impl_runtime_apis! { } fn submit_report_equivocation_unsigned_extrinsic( - equivocation_proof: sp_consensus_beefy::EquivocationProof< + equivocation_proof: sp_consensus_beefy::DoubleVotingProof< BlockNumber, BeefyId, BeefySignature, @@ -3065,7 +3094,7 @@ impl_runtime_apis! { fn generate_proof( block_numbers: Vec, best_known_block_number: Option, - ) -> Result<(Vec, mmr::Proof), mmr::Error> { + ) -> Result<(Vec, mmr::LeafProof), mmr::Error> { Mmr::generate_proof(block_numbers, best_known_block_number).map( |(leaves, proof)| { ( @@ -3079,7 +3108,7 @@ impl_runtime_apis! { ) } - fn verify_proof(leaves: Vec, proof: mmr::Proof) + fn verify_proof(leaves: Vec, proof: mmr::LeafProof) -> Result<(), mmr::Error> { let leaves = leaves.into_iter().map(|leaf| @@ -3092,7 +3121,7 @@ impl_runtime_apis! { fn verify_proof_stateless( root: mmr::Hash, leaves: Vec, - proof: mmr::Proof + proof: mmr::LeafProof ) -> Result<(), mmr::Error> { let nodes = leaves.into_iter().map(|leaf|mmr::DataOrHash::Data(leaf.into_opaque_leaf())).collect(); pallet_mmr::verify_leaves_proof::(root, nodes, proof) diff --git a/substrate/bin/node/testing/Cargo.toml b/substrate/bin/node/testing/Cargo.toml index fa3f90193ba5d11325bfb068fa69780495ec8c90..09db10563fb27e485c1f7ff5052896e7c2b6fb4f 100644 --- a/substrate/bin/node/testing/Cargo.toml +++ b/substrate/bin/node/testing/Cargo.toml @@ -16,7 +16,7 @@ workspace = true targets = ["x86_64-unknown-linux-gnu"] [dependencies] -codec = { package = "parity-scale-codec", version = "3.6.1" } +codec = { package = "parity-scale-codec", version = "3.6.12" } fs_extra = "1" futures = "0.3.30" log = { workspace = true, default-features = true } diff --git a/substrate/client/api/Cargo.toml b/substrate/client/api/Cargo.toml index fb650c5b532f2cbf841dc65e5f7f1a3c35dae733..147ea2bfbf5df83716c4a7f1f5fb2ade0c41d3f8 100644 --- a/substrate/client/api/Cargo.toml +++ b/substrate/client/api/Cargo.toml @@ -17,7 +17,7 @@ workspace = true targets = ["x86_64-unknown-linux-gnu"] [dependencies] -codec = { package = "parity-scale-codec", version = "3.6.1", default-features = false, features = [ +codec = { package = "parity-scale-codec", version = "3.6.12", default-features = false, features = [ "derive", ] } fnv = "1.0.6" diff --git a/substrate/client/api/src/in_mem.rs b/substrate/client/api/src/in_mem.rs index b933ed1f17e01a8822b958ac6a064fe2f3503926..ba89aede9147ff0ebe16beb6fedf39389ee9c700 100644 --- a/substrate/client/api/src/in_mem.rs +++ b/substrate/client/api/src/in_mem.rs @@ -419,20 +419,6 @@ impl blockchain::Backend for Blockchain { Ok(self.storage.read().leaves.hashes()) } - fn displaced_leaves_after_finalizing( - &self, - block_number: NumberFor, - ) -> sp_blockchain::Result> { - Ok(self - .storage - .read() - .leaves - .displaced_by_finalize_height(block_number) - .leaves() - .cloned() - .collect::>()) - } - fn children(&self, _parent_hash: Block::Hash) -> sp_blockchain::Result> { unimplemented!() } diff --git a/substrate/client/api/src/leaves.rs b/substrate/client/api/src/leaves.rs index a8a988771e2fdf346dd0c50983d0e8b32c74bafc..e129de8bf3fad30a0bb76569957c93138c631db8 100644 --- a/substrate/client/api/src/leaves.rs +++ b/substrate/client/api/src/leaves.rs @@ -49,7 +49,7 @@ pub struct FinalizationOutcome { removed: BTreeMap, Vec>, } -impl FinalizationOutcome { +impl FinalizationOutcome { /// Merge with another. This should only be used for displaced items that /// are produced within one transaction of each other. pub fn merge(&mut self, mut other: Self) { @@ -63,6 +63,16 @@ impl FinalizationOutcome { pub fn leaves(&self) -> impl Iterator { self.removed.values().flatten() } + + /// Constructor + pub fn new(new_displaced: impl Iterator) -> Self { + let mut removed = BTreeMap::, Vec>::new(); + for (hash, number) in new_displaced { + removed.entry(Reverse(number)).or_default().push(hash); + } + + FinalizationOutcome { removed } + } } /// list of leaf hashes ordered by number (descending). @@ -151,39 +161,12 @@ where Some(RemoveOutcome { inserted, removed: LeafSetItem { hash, number } }) } - /// Note a block height finalized, displacing all leaves with number less than the finalized - /// block's. - /// - /// Although it would be more technically correct to also prune out leaves at the - /// same number as the finalized block, but with different hashes, the current behavior - /// is simpler and our assumptions about how finalization works means that those leaves - /// will be pruned soon afterwards anyway. - pub fn finalize_height(&mut self, number: N) -> FinalizationOutcome { - let boundary = if number == N::zero() { - return FinalizationOutcome { removed: BTreeMap::new() } - } else { - number - N::one() - }; - - let below_boundary = self.storage.split_off(&Reverse(boundary)); - FinalizationOutcome { removed: below_boundary } - } - - /// The same as [`Self::finalize_height`], but it only simulates the operation. - /// - /// This means that no changes are done. - /// - /// Returns the leaves that would be displaced by finalizing the given block. - pub fn displaced_by_finalize_height(&self, number: N) -> FinalizationOutcome { - let boundary = if number == N::zero() { - return FinalizationOutcome { removed: BTreeMap::new() } - } else { - number - N::one() - }; - - let below_boundary = self.storage.range(&Reverse(boundary)..); - FinalizationOutcome { - removed: below_boundary.map(|(k, v)| (k.clone(), v.clone())).collect(), + /// Remove all leaves displaced by the last block finalization. + pub fn remove_displaced_leaves(&mut self, displaced_leaves: &FinalizationOutcome) { + for (number, hashes) in &displaced_leaves.removed { + for hash in hashes.iter() { + self.remove_leaf(number, hash); + } } } @@ -420,32 +403,6 @@ mod tests { assert!(set.contains(11, 11_2)); } - #[test] - fn finalization_works() { - let mut set = LeafSet::new(); - set.import(9_1u32, 9u32, 0u32); - set.import(10_1, 10, 9_1); - set.import(10_2, 10, 9_1); - set.import(11_1, 11, 10_1); - set.import(11_2, 11, 10_1); - set.import(12_1, 12, 11_2); - - let outcome = set.finalize_height(11); - assert_eq!(set.count(), 2); - assert!(set.contains(11, 11_1)); - assert!(set.contains(12, 12_1)); - assert_eq!( - outcome.removed, - [(Reverse(10), vec![10_2])].into_iter().collect::>(), - ); - - set.undo().undo_finalization(outcome); - assert_eq!(set.count(), 3); - assert!(set.contains(11, 11_1)); - assert!(set.contains(12, 12_1)); - assert!(set.contains(10, 10_2)); - } - #[test] fn flush_to_disk() { const PREFIX: &[u8] = b"abcdefg"; @@ -479,35 +436,4 @@ mod tests { assert!(set.contains(10, 1_2)); assert!(!set.contains(10, 1_3)); } - - #[test] - fn finalization_consistent_with_disk() { - const PREFIX: &[u8] = b"prefix"; - let db = Arc::new(sp_database::MemDb::default()); - - let mut set = LeafSet::new(); - set.import(10_1u32, 10u32, 0u32); - set.import(11_1, 11, 10_2); - set.import(11_2, 11, 10_2); - set.import(12_1, 12, 11_123); - - assert!(set.contains(10, 10_1)); - - let mut tx = Transaction::new(); - set.prepare_transaction(&mut tx, 0, PREFIX); - db.commit(tx).unwrap(); - - let _ = set.finalize_height(11); - let mut tx = Transaction::new(); - set.prepare_transaction(&mut tx, 0, PREFIX); - db.commit(tx).unwrap(); - - assert!(set.contains(11, 11_1)); - assert!(set.contains(11, 11_2)); - assert!(set.contains(12, 12_1)); - assert!(!set.contains(10, 10_1)); - - let set2 = LeafSet::read_from_db(&*db, 0, PREFIX).unwrap(); - assert_eq!(set, set2); - } } diff --git a/substrate/client/authority-discovery/Cargo.toml b/substrate/client/authority-discovery/Cargo.toml index 0cf90ada8ac61bda63a12c5f3072017ccd067270..435ca88a80079c9da9510b0f505d21677afb52cf 100644 --- a/substrate/client/authority-discovery/Cargo.toml +++ b/substrate/client/authority-discovery/Cargo.toml @@ -17,10 +17,10 @@ workspace = true targets = ["x86_64-unknown-linux-gnu"] [build-dependencies] -prost-build = "0.11" +prost-build = "0.12.4" [dependencies] -codec = { package = "parity-scale-codec", version = "3.6.1", default-features = false } +codec = { package = "parity-scale-codec", version = "3.6.12", default-features = false } futures = "0.3.30" futures-timer = "3.0.1" ip_network = "0.4.1" @@ -28,7 +28,7 @@ libp2p = { version = "0.51.4", features = ["ed25519", "kad"] } multihash = { version = "0.17.0", default-features = false, features = ["sha2", "std"] } linked_hash_set = "0.1.4" log = { workspace = true, default-features = true } -prost = "0.12" +prost = "0.12.4" rand = "0.8.5" thiserror = { workspace = true } prometheus-endpoint = { package = "substrate-prometheus-endpoint", path = "../../utils/prometheus" } diff --git a/substrate/client/basic-authorship/Cargo.toml b/substrate/client/basic-authorship/Cargo.toml index 4890b66c9b2f91ef13ea74fa9f66c797d0beb32c..b75cb463b1a874c48a7b8c4511929eade4245704 100644 --- a/substrate/client/basic-authorship/Cargo.toml +++ b/substrate/client/basic-authorship/Cargo.toml @@ -16,7 +16,7 @@ workspace = true targets = ["x86_64-unknown-linux-gnu"] [dependencies] -codec = { package = "parity-scale-codec", version = "3.6.1" } +codec = { package = "parity-scale-codec", version = "3.6.12" } futures = "0.3.30" futures-timer = "3.0.1" log = { workspace = true, default-features = true } diff --git a/substrate/client/block-builder/Cargo.toml b/substrate/client/block-builder/Cargo.toml index e74d587d9b40fc57e0575b0fae7ecb0c5a177c15..62efe977e989c13bfc6e3fe0fb11d13ac3aca298 100644 --- a/substrate/client/block-builder/Cargo.toml +++ b/substrate/client/block-builder/Cargo.toml @@ -16,7 +16,7 @@ workspace = true targets = ["x86_64-unknown-linux-gnu"] [dependencies] -codec = { package = "parity-scale-codec", version = "3.6.1", features = [ +codec = { package = "parity-scale-codec", version = "3.6.12", features = [ "derive", ] } sp-api = { path = "../../primitives/api" } diff --git a/substrate/client/chain-spec/Cargo.toml b/substrate/client/chain-spec/Cargo.toml index 84320f17d7cb92c8319d437d49f70f2967e8fda1..84ef89783adc0facdbf5d826fc71468b932594d7 100644 --- a/substrate/client/chain-spec/Cargo.toml +++ b/substrate/client/chain-spec/Cargo.toml @@ -16,7 +16,7 @@ workspace = true targets = ["x86_64-unknown-linux-gnu"] [dependencies] -codec = { package = "parity-scale-codec", version = "3.6.1", default-features = false, features = ["derive"] } +codec = { package = "parity-scale-codec", version = "3.6.12", default-features = false, features = ["derive"] } memmap2 = "0.9.3" serde = { features = ["derive"], workspace = true, default-features = true } serde_json = { workspace = true, default-features = true } @@ -34,7 +34,7 @@ sp-runtime = { path = "../../primitives/runtime" } sp-state-machine = { path = "../../primitives/state-machine" } log = { workspace = true } sp-tracing = { path = "../../primitives/tracing" } -array-bytes = { version = "6.1" } +array-bytes = "6.2.2" docify = "0.2.8" [dev-dependencies] diff --git a/substrate/client/cli/Cargo.toml b/substrate/client/cli/Cargo.toml index 805d3ee117f4ac19b636550bea6a0845978defee..1f3bce799b2c436565cf948f54d2017338344732 100644 --- a/substrate/client/cli/Cargo.toml +++ b/substrate/client/cli/Cargo.toml @@ -16,16 +16,16 @@ workspace = true targets = ["x86_64-unknown-linux-gnu"] [dependencies] -array-bytes = "6.1" +array-bytes = "6.2.2" chrono = "0.4.31" clap = { version = "4.5.3", features = ["derive", "string", "wrap_help"] } fdlimit = "0.3.0" futures = "0.3.30" -itertools = "0.10.3" +itertools = "0.11" libp2p-identity = { version = "0.1.3", features = ["ed25519", "peerid"] } log = { workspace = true, default-features = true } names = { version = "0.14.0", default-features = false } -parity-scale-codec = "3.6.1" +parity-scale-codec = "3.6.12" rand = "0.8.5" regex = "1.6.0" rpassword = "7.0.0" diff --git a/substrate/client/cli/src/commands/run_cmd.rs b/substrate/client/cli/src/commands/run_cmd.rs index 221c32affd5a91d680f23ed11eb5f7a9a4051da2..c1288b502c95a4045215b66d57e18d7ade0e38ab 100644 --- a/substrate/client/cli/src/commands/run_cmd.rs +++ b/substrate/client/cli/src/commands/run_cmd.rs @@ -30,7 +30,9 @@ use crate::{ use clap::Parser; use regex::Regex; use sc_service::{ - config::{BasePath, PrometheusConfig, RpcBatchRequestConfig, TransactionPoolOptions}, + config::{ + BasePath, IpNetwork, PrometheusConfig, RpcBatchRequestConfig, TransactionPoolOptions, + }, ChainSpec, Role, }; use sc_telemetry::TelemetryEndpoints; @@ -94,6 +96,22 @@ pub struct RunCmd { #[arg(long)] pub rpc_rate_limit: Option, + /// Disable RPC rate limiting for certain ip addresses. + /// + /// Each IP address must be in CIDR notation such as `1.2.3.4/24`. + #[arg(long, num_args = 1..)] + pub rpc_rate_limit_whitelisted_ips: Vec, + + /// Trust proxy headers for disable rate limiting. + /// + /// By default the rpc server will not trust headers such `X-Real-IP`, `X-Forwarded-For` and + /// `Forwarded` and this option will make the rpc server to trust these headers. + /// + /// For instance this may be secure if the rpc server is behind a reverse proxy and that the + /// proxy always sets these headers. + #[arg(long)] + pub rpc_rate_limit_trust_proxy_headers: bool, + /// 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, @@ -439,6 +457,14 @@ impl CliConfiguration for RunCmd { Ok(self.rpc_rate_limit) } + fn rpc_rate_limit_whitelisted_ips(&self) -> Result> { + Ok(self.rpc_rate_limit_whitelisted_ips.clone()) + } + + fn rpc_rate_limit_trust_proxy_headers(&self) -> Result { + Ok(self.rpc_rate_limit_trust_proxy_headers) + } + 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 70a4885e5eef79780bdbec5b2cb7550b28ad866a..783c9313121fef1a199705e8a6508688e51b67ca 100644 --- a/substrate/client/cli/src/config.rs +++ b/substrate/client/cli/src/config.rs @@ -26,7 +26,7 @@ use log::warn; use names::{Generator, Name}; use sc_service::{ config::{ - BasePath, Configuration, DatabaseSource, KeystoreConfig, NetworkConfiguration, + BasePath, Configuration, DatabaseSource, IpNetwork, KeystoreConfig, NetworkConfiguration, NodeKeyConfig, OffchainWorkerConfig, OutputFormat, PrometheusConfig, PruningMode, Role, RpcBatchRequestConfig, RpcMethods, TelemetryEndpoints, TransactionPoolOptions, WasmExecutionMethod, @@ -349,6 +349,16 @@ pub trait CliConfiguration: Sized { Ok(None) } + /// RPC rate limit whitelisted ip addresses. + fn rpc_rate_limit_whitelisted_ips(&self) -> Result> { + Ok(vec![]) + } + + /// RPC rate limit trust proxy headers. + fn rpc_rate_limit_trust_proxy_headers(&self) -> Result { + Ok(false) + } + /// Get the prometheus configuration (`None` if disabled) /// /// By default this is `None`. @@ -523,6 +533,8 @@ pub trait CliConfiguration: Sized { rpc_message_buffer_capacity: self.rpc_buffer_capacity_per_connection()?, rpc_batch_config: self.rpc_batch_config()?, rpc_rate_limit: self.rpc_rate_limit()?, + rpc_rate_limit_whitelisted_ips: self.rpc_rate_limit_whitelisted_ips()?, + rpc_rate_limit_trust_proxy_headers: self.rpc_rate_limit_trust_proxy_headers()?, 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 4201a0f4062fb0063621d85dd02feb0deade24bc..3bf2768078401f8cfafaceab1b76c8a83e2548d5 100644 --- a/substrate/client/cli/src/runner.rs +++ b/substrate/client/cli/src/runner.rs @@ -273,6 +273,8 @@ mod tests { rpc_port: 9944, rpc_batch_config: sc_service::config::RpcBatchRequestConfig::Unlimited, rpc_rate_limit: None, + rpc_rate_limit_whitelisted_ips: Default::default(), + rpc_rate_limit_trust_proxy_headers: Default::default(), 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 64e2d16cd913aaea5d2688087e90088e5ff46ab8..d1460c45356d7ec86204b52c42c08ee28e9c5faf 100644 --- a/substrate/client/consensus/aura/Cargo.toml +++ b/substrate/client/consensus/aura/Cargo.toml @@ -17,7 +17,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] async-trait = "0.1.79" -codec = { package = "parity-scale-codec", version = "3.6.1" } +codec = { package = "parity-scale-codec", version = "3.6.12" } futures = "0.3.30" log = { workspace = true, default-features = true } thiserror = { workspace = true } diff --git a/substrate/client/consensus/aura/src/lib.rs b/substrate/client/consensus/aura/src/lib.rs index e220aaac508df50c1c6d440cfe50ee3b4015d64a..2d6264a48929502c2791180c1fbfb305bf9181cc 100644 --- a/substrate/client/consensus/aura/src/lib.rs +++ b/substrate/client/consensus/aura/src/lib.rs @@ -579,15 +579,15 @@ mod tests { type Error = sp_blockchain::Error; struct DummyFactory(Arc); - struct DummyProposer(u64, Arc); + struct DummyProposer(Arc); impl Environment for DummyFactory { type Proposer = DummyProposer; type CreateProposer = futures::future::Ready>; type Error = Error; - fn init(&mut self, parent_header: &::Header) -> Self::CreateProposer { - futures::future::ready(Ok(DummyProposer(parent_header.number + 1, self.0.clone()))) + fn init(&mut self, _: &::Header) -> Self::CreateProposer { + futures::future::ready(Ok(DummyProposer(self.0.clone()))) } } @@ -604,9 +604,9 @@ mod tests { _: Duration, _: Option, ) -> Self::Proposal { - let r = BlockBuilderBuilder::new(&*self.1) - .on_parent_block(self.1.chain_info().best_hash) - .fetch_parent_block_number(&*self.1) + let r = BlockBuilderBuilder::new(&*self.0) + .on_parent_block(self.0.chain_info().best_hash) + .fetch_parent_block_number(&*self.0) .unwrap() .with_inherent_digests(digests) .build() diff --git a/substrate/client/consensus/babe/Cargo.toml b/substrate/client/consensus/babe/Cargo.toml index b001e3d117aa94c86e76484336b434f840ec3e69..c51082a018b5cfd558efe0b76985d6add890057d 100644 --- a/substrate/client/consensus/babe/Cargo.toml +++ b/substrate/client/consensus/babe/Cargo.toml @@ -18,7 +18,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] async-trait = "0.1.79" -codec = { package = "parity-scale-codec", version = "3.6.1", features = ["derive"] } +codec = { package = "parity-scale-codec", version = "3.6.12", features = ["derive"] } futures = "0.3.30" log = { workspace = true, default-features = true } num-bigint = "0.4.3" diff --git a/substrate/client/consensus/babe/README.md b/substrate/client/consensus/babe/README.md index a3cf944b513b80eb96493342b821147bfc905592..47b5820ff71aab8a4a6c92640ebd8981c396fa09 100644 --- a/substrate/client/consensus/babe/README.md +++ b/substrate/client/consensus/babe/README.md @@ -43,6 +43,6 @@ primary blocks in the chain. We will pick the heaviest chain (more primary blocks) and will go with the longest one in case of a tie. An in-depth description and analysis of the protocol can be found here: - + License: GPL-3.0-or-later WITH Classpath-exception-2.0 diff --git a/substrate/client/consensus/babe/rpc/Cargo.toml b/substrate/client/consensus/babe/rpc/Cargo.toml index b2661bbde27e4a9d72d0140e241c1da1bcc0f2b2..4c755df541d70315dea241092145e17c2bd28800 100644 --- a/substrate/client/consensus/babe/rpc/Cargo.toml +++ b/substrate/client/consensus/babe/rpc/Cargo.toml @@ -16,7 +16,7 @@ workspace = true targets = ["x86_64-unknown-linux-gnu"] [dependencies] -jsonrpsee = { version = "0.22", features = ["client-core", "macros", "server"] } +jsonrpsee = { version = "0.22.5", features = ["client-core", "macros", "server-core"] } futures = "0.3.30" serde = { features = ["derive"], workspace = true, default-features = true } thiserror = { workspace = true } diff --git a/substrate/client/consensus/babe/src/lib.rs b/substrate/client/consensus/babe/src/lib.rs index d10bdd8c7e4c4d108b78ef3286f475ba85e16a8a..0c85de24004031fce96be35bc413506069093eb1 100644 --- a/substrate/client/consensus/babe/src/lib.rs +++ b/substrate/client/consensus/babe/src/lib.rs @@ -61,7 +61,7 @@ //! blocks) and will go with the longest one in case of a tie. //! //! An in-depth description and analysis of the protocol can be found here: -//! +//! #![forbid(unsafe_code)] #![warn(missing_docs)] @@ -562,9 +562,10 @@ fn aux_storage_cleanup + HeaderBackend, Block: B // Cleans data for stale forks. let stale_forks = match client.expand_forks(¬ification.stale_heads) { Ok(stale_forks) => stale_forks, - Err((stale_forks, e)) => { + Err(e) => { warn!(target: LOG_TARGET, "{:?}", e); - stale_forks + + Default::default() }, }; hashes.extend(stale_forks.iter()); diff --git a/substrate/client/consensus/babe/src/tests.rs b/substrate/client/consensus/babe/src/tests.rs index 38c9e1ff6ac25cc26151c668902838ec65ab6189..716067ae4000661beab6aeb90772087720d0a5ae 100644 --- a/substrate/client/consensus/babe/src/tests.rs +++ b/substrate/client/consensus/babe/src/tests.rs @@ -1094,8 +1094,8 @@ async fn obsolete_blocks_aux_data_cleanup() { assert!(aux_data_check(&fork1_hashes[2..3], false)); // Present: A4 assert!(aux_data_check(&fork1_hashes[3..], true)); - // Present C4, C5 - assert!(aux_data_check(&fork3_hashes, true)); + // Wiped C4, C5 + assert!(aux_data_check(&fork3_hashes, false)); } #[tokio::test] diff --git a/substrate/client/consensus/beefy/Cargo.toml b/substrate/client/consensus/beefy/Cargo.toml index 7b61b3c6c01f39003d9212fcfc0ea4abc8963bd2..193acbe52a1e8b3bc7752b984296bb9c1456d483 100644 --- a/substrate/client/consensus/beefy/Cargo.toml +++ b/substrate/client/consensus/beefy/Cargo.toml @@ -12,10 +12,10 @@ homepage = "https://substrate.io" workspace = true [dependencies] -array-bytes = "6.1" +array-bytes = "6.2.2" async-channel = "1.8.0" async-trait = "0.1.79" -codec = { package = "parity-scale-codec", version = "3.6.1", features = ["derive"] } +codec = { package = "parity-scale-codec", version = "3.6.12", features = ["derive"] } fnv = "1.0.6" futures = "0.3.30" log = { workspace = true, default-features = true } @@ -39,7 +39,6 @@ sp-consensus-beefy = { path = "../../../primitives/consensus/beefy" } sp-core = { path = "../../../primitives/core" } sp-crypto-hashing = { path = "../../../primitives/crypto/hashing" } sp-keystore = { path = "../../../primitives/keystore" } -sp-mmr-primitives = { path = "../../../primitives/merkle-mountain-range" } sp-runtime = { path = "../../../primitives/runtime" } tokio = "1.37" @@ -51,6 +50,7 @@ sc-block-builder = { path = "../../block-builder" } sc-network-test = { path = "../../network/test" } sp-consensus-grandpa = { path = "../../../primitives/consensus/grandpa" } sp-keyring = { path = "../../../primitives/keyring" } +sp-mmr-primitives = { path = "../../../primitives/merkle-mountain-range" } sp-tracing = { path = "../../../primitives/tracing" } substrate-test-runtime-client = { path = "../../../test-utils/runtime/client" } diff --git a/substrate/client/consensus/beefy/rpc/Cargo.toml b/substrate/client/consensus/beefy/rpc/Cargo.toml index e46fc4f4410a461f73f5e5fe791bd9b08fd98a99..07e46dbda156a79a77a60e8340e46a323e133fd2 100644 --- a/substrate/client/consensus/beefy/rpc/Cargo.toml +++ b/substrate/client/consensus/beefy/rpc/Cargo.toml @@ -12,9 +12,9 @@ homepage = "https://substrate.io" workspace = true [dependencies] -codec = { package = "parity-scale-codec", version = "3.6.1", features = ["derive"] } +codec = { package = "parity-scale-codec", version = "3.6.12", features = ["derive"] } futures = "0.3.30" -jsonrpsee = { version = "0.22", features = ["client-core", "macros", "server"] } +jsonrpsee = { version = "0.22.5", features = ["client-core", "macros", "server-core"] } log = { workspace = true, default-features = true } parking_lot = "0.12.1" serde = { features = ["derive"], workspace = true, default-features = true } diff --git a/substrate/client/consensus/beefy/src/fisherman.rs b/substrate/client/consensus/beefy/src/fisherman.rs new file mode 100644 index 0000000000000000000000000000000000000000..a2b4c8f945d1c224c45e522bc7e7b0461a3c00ce --- /dev/null +++ b/substrate/client/consensus/beefy/src/fisherman.rs @@ -0,0 +1,162 @@ +// 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::{error::Error, keystore::BeefyKeystore, round::Rounds, LOG_TARGET}; +use log::{debug, error, warn}; +use sc_client_api::Backend; +use sp_api::ProvideRuntimeApi; +use sp_blockchain::HeaderBackend; +use sp_consensus_beefy::{ + check_equivocation_proof, + ecdsa_crypto::{AuthorityId, Signature}, + BeefyApi, BeefySignatureHasher, DoubleVotingProof, OpaqueKeyOwnershipProof, ValidatorSetId, +}; +use sp_runtime::{ + generic::BlockId, + traits::{Block, NumberFor}, +}; +use std::{marker::PhantomData, sync::Arc}; + +/// Helper struct containing the id and the key ownership proof for a validator. +pub struct ProvedValidator<'a> { + pub id: &'a AuthorityId, + pub key_owner_proof: OpaqueKeyOwnershipProof, +} + +/// Helper used to check and report equivocations. +pub struct Fisherman { + backend: Arc, + runtime: Arc, + key_store: Arc>, + + _phantom: PhantomData, +} + +impl, RuntimeApi: ProvideRuntimeApi> Fisherman +where + RuntimeApi::Api: BeefyApi, +{ + pub fn new( + backend: Arc, + runtime: Arc, + keystore: Arc>, + ) -> Self { + Self { backend, runtime, key_store: keystore, _phantom: Default::default() } + } + + fn prove_offenders<'a>( + &self, + at: BlockId, + offender_ids: impl Iterator, + validator_set_id: ValidatorSetId, + ) -> Result>, Error> { + let hash = match at { + BlockId::Hash(hash) => hash, + BlockId::Number(number) => self + .backend + .blockchain() + .expect_block_hash_from_id(&BlockId::Number(number)) + .map_err(|err| { + Error::Backend(format!( + "Couldn't get hash for block #{:?} (error: {:?}). \ + Skipping report for equivocation", + at, err + )) + })?, + }; + + let runtime_api = self.runtime.runtime_api(); + let mut proved_offenders = vec![]; + for offender_id in offender_ids { + match runtime_api.generate_key_ownership_proof( + hash, + validator_set_id, + offender_id.clone(), + ) { + Ok(Some(key_owner_proof)) => { + proved_offenders.push(ProvedValidator { id: offender_id, key_owner_proof }); + }, + Ok(None) => { + debug!( + target: LOG_TARGET, + "🥩 Equivocation offender {} not part of the authority set {}.", + offender_id, validator_set_id + ); + }, + Err(e) => { + error!( + target: LOG_TARGET, + "🥩 Error generating key ownership proof for equivocation offender {} \ + in authority set {}: {}", + offender_id, validator_set_id, e + ); + }, + }; + } + + Ok(proved_offenders) + } + + /// Report the given equivocation to the BEEFY runtime module. This method + /// generates a session membership proof of the offender and then submits an + /// extrinsic to report the equivocation. In particular, the session membership + /// proof must be generated at the block at which the given set was active which + /// isn't necessarily the best block if there are pending authority set changes. + pub fn report_double_voting( + &self, + proof: DoubleVotingProof, AuthorityId, Signature>, + active_rounds: &Rounds, + ) -> Result<(), Error> { + let (validators, validator_set_id) = + (active_rounds.validators(), active_rounds.validator_set_id()); + let offender_id = proof.offender_id(); + + if !check_equivocation_proof::<_, _, BeefySignatureHasher>(&proof) { + debug!(target: LOG_TARGET, "🥩 Skipping report for bad equivocation {:?}", proof); + return Ok(()) + } + + if let Some(local_id) = self.key_store.authority_id(validators) { + if offender_id == &local_id { + warn!(target: LOG_TARGET, "🥩 Skipping report for own equivocation"); + return Ok(()) + } + } + + let key_owner_proofs = self.prove_offenders( + BlockId::Number(*proof.round_number()), + vec![offender_id].into_iter(), + validator_set_id, + )?; + + // submit equivocation report at **best** block + let best_block_hash = self.backend.blockchain().info().best_hash; + for ProvedValidator { key_owner_proof, .. } in key_owner_proofs { + self.runtime + .runtime_api() + .submit_report_equivocation_unsigned_extrinsic( + best_block_hash, + proof.clone(), + key_owner_proof, + ) + .map_err(Error::RuntimeApi)?; + } + + Ok(()) + } +} diff --git a/substrate/client/consensus/beefy/src/justification.rs b/substrate/client/consensus/beefy/src/justification.rs index 7f1b9e5237c3970eb8cba4936debd18c77117288..886368c9d7cb096c0178819e1bad23f06c82f3fb 100644 --- a/substrate/client/consensus/beefy/src/justification.rs +++ b/substrate/client/consensus/beefy/src/justification.rs @@ -16,12 +16,11 @@ // You should have received a copy of the GNU General Public License // along with this program. If not, see . -use crate::keystore::BeefyKeystore; -use codec::{DecodeAll, Encode}; +use codec::DecodeAll; use sp_consensus::Error as ConsensusError; use sp_consensus_beefy::{ ecdsa_crypto::{AuthorityId, Signature}, - ValidatorSet, ValidatorSetId, VersionedFinalityProof, + BeefySignatureHasher, KnownSignature, ValidatorSet, ValidatorSetId, VersionedFinalityProof, }; use sp_runtime::traits::{Block as BlockT, NumberFor}; @@ -45,46 +44,31 @@ pub(crate) fn decode_and_verify_finality_proof( ) -> Result, (ConsensusError, u32)> { let proof = >::decode_all(&mut &*encoded) .map_err(|_| (ConsensusError::InvalidJustification, 0))?; - verify_with_validator_set::(target_number, validator_set, &proof).map(|_| proof) + verify_with_validator_set::(target_number, validator_set, &proof)?; + Ok(proof) } /// Verify the Beefy finality proof against the validator set at the block it was generated. -pub(crate) fn verify_with_validator_set( +pub(crate) fn verify_with_validator_set<'a, Block: BlockT>( target_number: NumberFor, - validator_set: &ValidatorSet, - proof: &BeefyVersionedFinalityProof, -) -> Result<(), (ConsensusError, u32)> { - let mut signatures_checked = 0u32; + validator_set: &'a ValidatorSet, + proof: &'a BeefyVersionedFinalityProof, +) -> Result>, (ConsensusError, u32)> { match proof { VersionedFinalityProof::V1(signed_commitment) => { - if signed_commitment.signatures.len() != validator_set.len() || - signed_commitment.commitment.validator_set_id != validator_set.id() || - signed_commitment.commitment.block_number != target_number - { - return Err((ConsensusError::InvalidJustification, 0)) - } - - // Arrangement of signatures in the commitment should be in the same order - // as validators for that set. - let message = signed_commitment.commitment.encode(); - let valid_signatures = validator_set - .validators() - .into_iter() - .zip(signed_commitment.signatures.iter()) - .filter(|(id, signature)| { - signature - .as_ref() - .map(|sig| { - signatures_checked += 1; - BeefyKeystore::verify(*id, sig, &message[..]) - }) - .unwrap_or(false) - }) - .count(); - if valid_signatures >= crate::round::threshold(validator_set.len()) { - Ok(()) + let signatories = signed_commitment + .verify_signatures::<_, BeefySignatureHasher>(target_number, validator_set) + .map_err(|checked_signatures| { + (ConsensusError::InvalidJustification, checked_signatures) + })?; + + if signatories.len() >= crate::round::threshold(validator_set.len()) { + Ok(signatories) } else { - Err((ConsensusError::InvalidJustification, signatures_checked)) + Err(( + ConsensusError::InvalidJustification, + signed_commitment.signature_count() as u32, + )) } }, } @@ -92,6 +76,7 @@ pub(crate) fn verify_with_validator_set( #[cfg(test)] pub(crate) mod tests { + use codec::Encode; use sp_consensus_beefy::{ known_payloads, test_utils::Keyring, Commitment, Payload, SignedCommitment, VersionedFinalityProof, diff --git a/substrate/client/consensus/beefy/src/lib.rs b/substrate/client/consensus/beefy/src/lib.rs index 2637481fbf3e0375fbad46de64fcb1b67fdd4668..0e49839f0fd2dae76e26738823ea9e5af775acb7 100644 --- a/substrate/client/consensus/beefy/src/lib.rs +++ b/substrate/client/consensus/beefy/src/lib.rs @@ -43,11 +43,10 @@ use sp_api::ProvideRuntimeApi; use sp_blockchain::{Backend as BlockchainBackend, HeaderBackend}; use sp_consensus::{Error as ConsensusError, SyncOracle}; use sp_consensus_beefy::{ - ecdsa_crypto::AuthorityId, BeefyApi, ConsensusLog, MmrRootHash, PayloadProvider, ValidatorSet, + ecdsa_crypto::AuthorityId, BeefyApi, ConsensusLog, 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, VecDeque}, @@ -69,6 +68,7 @@ pub mod justification; use crate::{ communication::gossip::GossipValidator, + fisherman::Fisherman, justification::BeefyVersionedFinalityProof, keystore::BeefyKeystore, metrics::VoterMetrics, @@ -80,6 +80,7 @@ pub use communication::beefy_protocol_name::{ }; use sp_runtime::generic::OpaqueDigestItemId; +mod fisherman; #[cfg(test)] mod tests; @@ -305,14 +306,16 @@ where pending_justifications: BTreeMap, BeefyVersionedFinalityProof>, is_authority: bool, ) -> BeefyWorker { + let key_store = Arc::new(self.key_store); BeefyWorker { - backend: self.backend, - runtime: self.runtime, - key_store: self.key_store, - metrics: self.metrics, - persisted_state: self.persisted_state, + backend: self.backend.clone(), + runtime: self.runtime.clone(), + key_store: key_store.clone(), payload_provider, sync, + fisherman: Arc::new(Fisherman::new(self.backend, self.runtime, key_store)), + metrics: self.metrics, + persisted_state: self.persisted_state, comms, links, pending_justifications, @@ -487,7 +490,7 @@ pub async fn start_beefy_gadget( C: Client + BlockBackend, P: PayloadProvider + Clone, R: ProvideRuntimeApi, - R::Api: BeefyApi + MmrApi>, + R::Api: BeefyApi, N: GossipNetwork + NetworkRequest + Send + Sync + 'static, S: GossipSyncing + SyncOracle + 'static, { diff --git a/substrate/client/consensus/beefy/src/round.rs b/substrate/client/consensus/beefy/src/round.rs index 0045dc70c260ee43ca1137d7d7f92b097220aeaf..5dae80cb1830ddc2d6402625865af6e965046897 100644 --- a/substrate/client/consensus/beefy/src/round.rs +++ b/substrate/client/consensus/beefy/src/round.rs @@ -22,7 +22,7 @@ use codec::{Decode, Encode}; use log::{debug, info}; use sp_consensus_beefy::{ ecdsa_crypto::{AuthorityId, Signature}, - Commitment, EquivocationProof, SignedCommitment, ValidatorSet, ValidatorSetId, VoteMessage, + Commitment, DoubleVotingProof, SignedCommitment, ValidatorSet, ValidatorSetId, VoteMessage, }; use sp_runtime::traits::{Block, NumberFor}; use std::collections::BTreeMap; @@ -61,7 +61,7 @@ pub fn threshold(authorities: usize) -> usize { pub enum VoteImportResult { Ok, RoundConcluded(SignedCommitment, Signature>), - Equivocation(EquivocationProof, AuthorityId, Signature>), + DoubleVoting(DoubleVotingProof, AuthorityId, Signature>), Invalid, Stale, } @@ -153,7 +153,7 @@ where target: LOG_TARGET, "🥩 detected equivocated vote: 1st: {:?}, 2nd: {:?}", previous_vote, vote ); - return VoteImportResult::Equivocation(EquivocationProof { + return VoteImportResult::DoubleVoting(DoubleVotingProof { first: previous_vote.clone(), second: vote, }) @@ -207,7 +207,7 @@ mod tests { use sc_network_test::Block; use sp_consensus_beefy::{ - known_payloads::MMR_ROOT_ID, test_utils::Keyring, Commitment, EquivocationProof, Payload, + known_payloads::MMR_ROOT_ID, test_utils::Keyring, Commitment, DoubleVotingProof, Payload, SignedCommitment, ValidatorSet, VoteMessage, }; @@ -494,7 +494,7 @@ mod tests { let mut alice_vote2 = alice_vote1.clone(); alice_vote2.commitment = commitment2; - let expected_result = VoteImportResult::Equivocation(EquivocationProof { + let expected_result = VoteImportResult::DoubleVoting(DoubleVotingProof { first: alice_vote1.clone(), second: alice_vote2.clone(), }); diff --git a/substrate/client/consensus/beefy/src/tests.rs b/substrate/client/consensus/beefy/src/tests.rs index 9b13d1da6d7da38b74864c9a750f515ef9472230..2bb145d660df061561efd2196b2193b5ef70b1df 100644 --- a/substrate/client/consensus/beefy/src/tests.rs +++ b/substrate/client/consensus/beefy/src/tests.rs @@ -59,7 +59,7 @@ use sp_consensus_beefy::{ known_payloads, mmr::{find_mmr_root_digest, MmrRootProvider}, test_utils::Keyring as BeefyKeyring, - BeefyApi, Commitment, ConsensusLog, EquivocationProof, MmrRootHash, OpaqueKeyOwnershipProof, + BeefyApi, Commitment, ConsensusLog, DoubleVotingProof, MmrRootHash, OpaqueKeyOwnershipProof, Payload, SignedCommitment, ValidatorSet, ValidatorSetId, VersionedFinalityProof, VoteMessage, BEEFY_ENGINE_ID, }; @@ -259,7 +259,7 @@ pub(crate) struct TestApi { pub validator_set: Option, pub mmr_root_hash: MmrRootHash, pub reported_equivocations: - Option, AuthorityId, Signature>>>>>, + Option, AuthorityId, Signature>>>>>, } impl TestApi { @@ -313,7 +313,7 @@ sp_api::mock_impl_runtime_apis! { } fn submit_report_equivocation_unsigned_extrinsic( - proof: EquivocationProof, AuthorityId, Signature>, + proof: DoubleVotingProof, AuthorityId, Signature>, _dummy: OpaqueKeyOwnershipProof, ) -> Option<()> { if let Some(equivocations_buf) = self.inner.reported_equivocations.as_ref() { diff --git a/substrate/client/consensus/beefy/src/worker.rs b/substrate/client/consensus/beefy/src/worker.rs index 05575ae01c3011e57c13d930a493cc57d7261a52..cfbb3d63aea446d5b6a9a20a0eb9b2cf8c391e79 100644 --- a/substrate/client/consensus/beefy/src/worker.rs +++ b/substrate/client/consensus/beefy/src/worker.rs @@ -23,6 +23,7 @@ use crate::{ }, error::Error, find_authorities_change, + fisherman::Fisherman, justification::BeefyVersionedFinalityProof, keystore::BeefyKeystore, metric_inc, metric_set, @@ -39,10 +40,9 @@ use sp_api::ProvideRuntimeApi; use sp_arithmetic::traits::{AtLeast32Bit, Saturating}; use sp_consensus::SyncOracle; use sp_consensus_beefy::{ - check_equivocation_proof, ecdsa_crypto::{AuthorityId, Signature}, - BeefyApi, BeefySignatureHasher, Commitment, EquivocationProof, PayloadProvider, ValidatorSet, - VersionedFinalityProof, VoteMessage, BEEFY_ENGINE_ID, + BeefyApi, Commitment, DoubleVotingProof, PayloadProvider, ValidatorSet, VersionedFinalityProof, + VoteMessage, BEEFY_ENGINE_ID, }; use sp_runtime::{ generic::BlockId, @@ -377,9 +377,10 @@ pub(crate) struct BeefyWorker { // utilities pub backend: Arc, pub runtime: Arc, - pub key_store: BeefyKeystore, + pub key_store: Arc>, pub payload_provider: P, pub sync: Arc, + pub fisherman: Arc>, // communication (created once, but returned and reused if worker is restarted/reinitialized) pub comms: BeefyComms, @@ -590,9 +591,9 @@ where } metric_inc!(self.metrics, beefy_good_votes_processed); }, - VoteImportResult::Equivocation(proof) => { + VoteImportResult::DoubleVoting(proof) => { metric_inc!(self.metrics, beefy_equivocation_votes); - self.report_equivocation(proof)?; + self.report_double_voting(proof)?; }, VoteImportResult::Invalid => metric_inc!(self.metrics, beefy_invalid_votes), VoteImportResult::Stale => metric_inc!(self.metrics, beefy_stale_votes), @@ -941,64 +942,13 @@ where (error, self.comms) } - /// Report the given equivocation to the BEEFY runtime module. This method - /// generates a session membership proof of the offender and then submits an - /// extrinsic to report the equivocation. In particular, the session membership - /// proof must be generated at the block at which the given set was active which - /// isn't necessarily the best block if there are pending authority set changes. - pub(crate) fn report_equivocation( + /// Report the given equivocation to the BEEFY runtime module. + fn report_double_voting( &self, - proof: EquivocationProof, AuthorityId, Signature>, + proof: DoubleVotingProof, AuthorityId, Signature>, ) -> Result<(), Error> { let rounds = self.persisted_state.voting_oracle.active_rounds()?; - let (validators, validator_set_id) = (rounds.validators(), rounds.validator_set_id()); - let offender_id = proof.offender_id().clone(); - - 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.key_store.authority_id(validators) { - if offender_id == local_id { - warn!(target: LOG_TARGET, "🥩 Skip equivocation report for own equivocation"); - return Ok(()) - } - } - - let number = *proof.round_number(); - let hash = self - .backend - .blockchain() - .expect_block_hash_from_id(&BlockId::Number(number)) - .map_err(|err| { - let err_msg = format!( - "Couldn't get hash for block #{:?} (error: {:?}), skipping report for equivocation", - number, err - ); - Error::Backend(err_msg) - })?; - 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) - .map_err(Error::RuntimeApi)? - { - Some(proof) => proof, - None => { - debug!( - target: LOG_TARGET, - "🥩 Equivocation offender not part of the authority set." - ); - return Ok(()) - }, - }; - - // submit equivocation report at **best** block - 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)?; - - Ok(()) + self.fisherman.report_double_voting(proof, rounds) } } @@ -1165,13 +1115,15 @@ pub(crate) mod tests { .unwrap(); let payload_provider = MmrRootProvider::new(api.clone()); let comms = BeefyComms { gossip_engine, gossip_validator, on_demand_justifications }; + let key_store: Arc> = Arc::new(Some(keystore).into()); BeefyWorker { - backend, - runtime: api, - key_store: Some(keystore).into(), + backend: backend.clone(), + runtime: api.clone(), + key_store: key_store.clone(), metrics, payload_provider, sync: Arc::new(sync), + fisherman: Arc::new(Fisherman::new(backend, api, key_store)), links, comms, pending_justifications: BTreeMap::new(), @@ -1590,6 +1542,11 @@ 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.runtime = api_alice.clone(); + worker.fisherman = Arc::new(Fisherman::new( + worker.backend.clone(), + worker.runtime.clone(), + worker.key_store.clone(), + )); // let there be a block with num = 1: let _ = net.peer(0).push_blocks(1, false); @@ -1604,7 +1561,7 @@ pub(crate) mod tests { ); { // expect voter (Alice) to successfully report it - assert_eq!(worker.report_equivocation(good_proof.clone()), Ok(())); + assert_eq!(worker.report_double_voting(good_proof.clone()), Ok(())); // verify Alice reports Bob equivocation to runtime let reported = api_alice.reported_equivocations.as_ref().unwrap().lock(); assert_eq!(reported.len(), 1); @@ -1616,7 +1573,7 @@ pub(crate) mod tests { let mut bad_proof = good_proof.clone(); bad_proof.first.id = Keyring::Charlie.public(); // bad proofs are simply ignored - assert_eq!(worker.report_equivocation(bad_proof), Ok(())); + assert_eq!(worker.report_double_voting(bad_proof), Ok(())); // verify nothing reported to runtime assert!(api_alice.reported_equivocations.as_ref().unwrap().lock().is_empty()); @@ -1625,7 +1582,7 @@ pub(crate) mod tests { old_proof.first.commitment.validator_set_id = 0; old_proof.second.commitment.validator_set_id = 0; // old proofs are simply ignored - assert_eq!(worker.report_equivocation(old_proof), Ok(())); + assert_eq!(worker.report_double_voting(old_proof), Ok(())); // verify nothing reported to runtime assert!(api_alice.reported_equivocations.as_ref().unwrap().lock().is_empty()); @@ -1635,7 +1592,7 @@ pub(crate) mod tests { (block_num, payload2.clone(), set_id, &Keyring::Alice), ); // equivocations done by 'self' are simply ignored (not reported) - assert_eq!(worker.report_equivocation(self_proof), Ok(())); + assert_eq!(worker.report_double_voting(self_proof), Ok(())); // verify nothing reported to runtime assert!(api_alice.reported_equivocations.as_ref().unwrap().lock().is_empty()); } diff --git a/substrate/client/consensus/epochs/Cargo.toml b/substrate/client/consensus/epochs/Cargo.toml index ff6bf86a6a441d49a8950c38d2333bd0e067724d..e409e171e477c2452903a09ee78916808a210011 100644 --- a/substrate/client/consensus/epochs/Cargo.toml +++ b/substrate/client/consensus/epochs/Cargo.toml @@ -16,7 +16,7 @@ workspace = true targets = ["x86_64-unknown-linux-gnu"] [dependencies] -codec = { package = "parity-scale-codec", version = "3.6.1", features = ["derive"] } +codec = { package = "parity-scale-codec", version = "3.6.12", features = ["derive"] } fork-tree = { path = "../../../utils/fork-tree" } sc-client-api = { path = "../../api" } sc-consensus = { path = "../common" } diff --git a/substrate/client/consensus/grandpa/Cargo.toml b/substrate/client/consensus/grandpa/Cargo.toml index e59c17b0680374d7195e823514d02f807f6f3cbf..9099761fbceb4a30624eef4f636982f3e3b9921b 100644 --- a/substrate/client/consensus/grandpa/Cargo.toml +++ b/substrate/client/consensus/grandpa/Cargo.toml @@ -18,14 +18,14 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] ahash = "0.8.2" -array-bytes = "6.1" +array-bytes = "6.2.2" async-trait = "0.1.79" dyn-clone = "1.0" finality-grandpa = { version = "0.16.2", features = ["derive-codec"] } futures = "0.3.30" futures-timer = "3.0.1" log = { workspace = true, default-features = true } -parity-scale-codec = { version = "3.6.1", features = ["derive"] } +parity-scale-codec = { version = "3.6.12", features = ["derive"] } parking_lot = "0.12.1" rand = "0.8.5" serde_json = { workspace = true, default-features = true } diff --git a/substrate/client/consensus/grandpa/rpc/Cargo.toml b/substrate/client/consensus/grandpa/rpc/Cargo.toml index 0789a429ac416de70201e30e909d4f3dec7e4a66..d4e72baef3e7df47baf948cba59e35b2687c76e1 100644 --- a/substrate/client/consensus/grandpa/rpc/Cargo.toml +++ b/substrate/client/consensus/grandpa/rpc/Cargo.toml @@ -15,9 +15,9 @@ workspace = true [dependencies] finality-grandpa = { version = "0.16.2", features = ["derive-codec"] } futures = "0.3.30" -jsonrpsee = { version = "0.22", features = ["client-core", "macros", "server"] } +jsonrpsee = { version = "0.22.5", features = ["client-core", "macros", "server-core"] } log = { workspace = true, default-features = true } -parity-scale-codec = { version = "3.6.1", features = ["derive"] } +parity-scale-codec = { version = "3.6.12", features = ["derive"] } serde = { features = ["derive"], workspace = true, default-features = true } thiserror = { workspace = true } sc-client-api = { path = "../../../api" } diff --git a/substrate/client/consensus/grandpa/rpc/src/lib.rs b/substrate/client/consensus/grandpa/rpc/src/lib.rs index 0557eab93e2956b56956f50edea118c9c30cbd76..68de068c3058377a6be9c8907581498d3466aaba 100644 --- a/substrate/client/consensus/grandpa/rpc/src/lib.rs +++ b/substrate/client/consensus/grandpa/rpc/src/lib.rs @@ -125,7 +125,7 @@ where #[cfg(test)] mod tests { use super::*; - use std::{collections::HashSet, convert::TryInto, sync::Arc}; + use std::{collections::HashSet, sync::Arc}; use jsonrpsee::{core::EmptyServerParams as EmptyParams, types::SubscriptionId, RpcModule}; use parity_scale_codec::{Decode, Encode}; diff --git a/substrate/client/consensus/grandpa/src/communication/gossip.rs b/substrate/client/consensus/grandpa/src/communication/gossip.rs index 88821faf0aba1a67ea65fe0e2a553e89eac40f47..c7fe5a46a5eb6db29501effde313cdc6c08894d9 100644 --- a/substrate/client/consensus/grandpa/src/communication/gossip.rs +++ b/substrate/client/consensus/grandpa/src/communication/gossip.rs @@ -810,7 +810,7 @@ impl Inner { self.live_topics.push(round, set_id); self.peers.reshuffle(); - self.multicast_neighbor_packet(false) + self.multicast_neighbor_packet() } /// Note that a voter set with given ID has started. Does nothing if the last @@ -847,10 +847,7 @@ impl Inner { self.live_topics.push(Round(1), set_id); self.authorities = authorities; - // when transitioning to a new set we also want to send neighbor packets to light clients, - // this is so that they know who to ask justifications from in order to finalize the last - // block in the previous set. - self.multicast_neighbor_packet(true) + self.multicast_neighbor_packet() } /// Note that we've imported a commit finalizing a given block. Does nothing if the last @@ -869,7 +866,7 @@ impl Inner { return None } - self.multicast_neighbor_packet(false) + self.multicast_neighbor_packet() } fn consider_vote(&self, round: Round, set_id: SetId) -> Consider { @@ -1183,7 +1180,7 @@ impl Inner { (neighbor_topics, action, catch_up, report) } - fn multicast_neighbor_packet(&self, force_light: bool) -> MaybeMessage { + fn multicast_neighbor_packet(&self) -> MaybeMessage { self.local_view.as_ref().map(|local_view| { let packet = NeighborPacket { round: local_view.round, @@ -1191,22 +1188,7 @@ impl Inner { commit_finalized_height: *local_view.last_commit_height().unwrap_or(&Zero::zero()), }; - let peers = self - .peers - .inner - .iter() - .filter_map(|(id, info)| { - // light clients don't participate in the full GRANDPA voter protocol - // and therefore don't need to be informed about all view updates unless - // we explicitly require it (e.g. when transitioning to a new set) - if info.roles.is_light() && !force_light { - None - } else { - Some(id) - } - }) - .cloned() - .collect(); + let peers = self.peers.inner.iter().map(|(id, _)| id).cloned().collect(); (peers, packet) }) @@ -2602,7 +2584,7 @@ mod tests { } #[test] - fn sends_neighbor_packets_to_non_light_peers_when_starting_a_new_round() { + fn sends_neighbor_packets_to_all_peers_when_starting_a_new_round() { let (val, _) = GossipValidator::::new(config(), voter_set_state(), None, None); // initialize the validator to a stable set id @@ -2617,10 +2599,10 @@ mod tests { val.inner.write().peers.new_peer(light_peer, ObservedRole::Light); val.note_round(Round(2), |peers, message| { - assert_eq!(peers.len(), 2); + assert_eq!(peers.len(), 3); assert!(peers.contains(&authority_peer)); assert!(peers.contains(&full_peer)); - assert!(!peers.contains(&light_peer)); + assert!(peers.contains(&light_peer)); assert!(matches!(message, NeighborPacket { set_id: SetId(1), round: Round(2), .. })); }); } diff --git a/substrate/client/consensus/grandpa/src/communication/tests.rs b/substrate/client/consensus/grandpa/src/communication/tests.rs index 40d901b2fec68449a29e6f4c2cf6ea03fa504a9e..bc3023fc0281d150864cb3bb21214c3648a73c42 100644 --- a/substrate/client/consensus/grandpa/src/communication/tests.rs +++ b/substrate/client/consensus/grandpa/src/communication/tests.rs @@ -51,10 +51,8 @@ use std::{ #[derive(Debug)] pub(crate) enum Event { - EventStream(TracingUnboundedSender), WriteNotification(PeerId, Vec), Report(PeerId, ReputationChange), - Announce(Hash), } #[derive(Clone)] @@ -146,15 +144,13 @@ impl NetworkEventStream for TestNetwork { &self, _name: &'static str, ) -> Pin + Send>> { - let (tx, rx) = tracing_unbounded("test", 100_000); - let _ = self.sender.unbounded_send(Event::EventStream(tx)); - Box::pin(rx) + futures::stream::pending().boxed() } } impl NetworkBlock> for TestNetwork { - fn announce_block(&self, hash: Hash, _data: Option>) { - let _ = self.sender.unbounded_send(Event::Announce(hash)); + fn announce_block(&self, _: Hash, _data: Option>) { + unimplemented!(); } fn new_best_block_imported(&self, _hash: Hash, _number: NumberFor) { diff --git a/substrate/client/consensus/grandpa/src/environment.rs b/substrate/client/consensus/grandpa/src/environment.rs index d3e2beb84e79c101f7618421c16f7797123f55fa..31df038044a4904e49f8447c4ab05c4cd36a5142 100644 --- a/substrate/client/consensus/grandpa/src/environment.rs +++ b/substrate/client/consensus/grandpa/src/environment.rs @@ -18,7 +18,6 @@ use std::{ collections::{BTreeMap, HashMap}, - iter::FromIterator, marker::PhantomData, pin::Pin, sync::Arc, diff --git a/substrate/client/consensus/manual-seal/Cargo.toml b/substrate/client/consensus/manual-seal/Cargo.toml index 1422d46105b22bd093de3260e3e13219aa2731a9..33f5bf1f8c1501e0e366edab6c3606716aeb47ab 100644 --- a/substrate/client/consensus/manual-seal/Cargo.toml +++ b/substrate/client/consensus/manual-seal/Cargo.toml @@ -16,10 +16,10 @@ workspace = true targets = ["x86_64-unknown-linux-gnu"] [dependencies] -jsonrpsee = { version = "0.22", features = ["client-core", "macros", "server"] } +jsonrpsee = { version = "0.22.5", features = ["client-core", "macros", "server-core"] } assert_matches = "1.3.0" async-trait = "0.1.79" -codec = { package = "parity-scale-codec", version = "3.6.1" } +codec = { package = "parity-scale-codec", version = "3.6.12" } futures = "0.3.30" futures-timer = "3.0.1" log = { workspace = true, default-features = true } diff --git a/substrate/client/consensus/manual-seal/src/lib.rs b/substrate/client/consensus/manual-seal/src/lib.rs index c3d360f071974ab38c6f1d112c23d6705f937bd3..8fc7e7ecab2f45cf8359c2f449dde3b480bb3ad3 100644 --- a/substrate/client/consensus/manual-seal/src/lib.rs +++ b/substrate/client/consensus/manual-seal/src/lib.rs @@ -86,7 +86,7 @@ where BasicQueue::new(ManualSealVerifier, block_import, None, spawner, registry) } -/// Params required to start the instant sealing authorship task. +/// Params required to start the manual sealing authorship task. pub struct ManualSealParams, TP, SC, CS, CIDP, P> { /// Block import instance. pub block_import: BI, @@ -114,7 +114,7 @@ pub struct ManualSealParams, TP, SC, C pub create_inherent_data_providers: CIDP, } -/// Params required to start the manual sealing authorship task. +/// Params required to start the instant sealing authorship task. pub struct InstantSealParams, TP, SC, CIDP, P> { /// Block import instance for well. importing blocks. pub block_import: BI, diff --git a/substrate/client/consensus/pow/Cargo.toml b/substrate/client/consensus/pow/Cargo.toml index ecfa29aa194d424d35eba858a0b829fb58a610e3..51a2be1b6cf5d4be2d5a5c3af6b0e6ea2bc25406 100644 --- a/substrate/client/consensus/pow/Cargo.toml +++ b/substrate/client/consensus/pow/Cargo.toml @@ -17,7 +17,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] async-trait = "0.1.79" -codec = { package = "parity-scale-codec", version = "3.6.1", features = ["derive"] } +codec = { package = "parity-scale-codec", version = "3.6.12", features = ["derive"] } futures = "0.3.30" futures-timer = "3.0.1" log = { workspace = true, default-features = true } diff --git a/substrate/client/consensus/slots/Cargo.toml b/substrate/client/consensus/slots/Cargo.toml index 4ac6ce90713798d2cce4172f3544c6a116736a84..8e88ee68d7d739a888f3b0e32b7a8fee3ac1e41c 100644 --- a/substrate/client/consensus/slots/Cargo.toml +++ b/substrate/client/consensus/slots/Cargo.toml @@ -18,7 +18,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] async-trait = "0.1.79" -codec = { package = "parity-scale-codec", version = "3.6.1" } +codec = { package = "parity-scale-codec", version = "3.6.12" } futures = "0.3.30" futures-timer = "3.0.1" log = { workspace = true, default-features = true } diff --git a/substrate/client/db/Cargo.toml b/substrate/client/db/Cargo.toml index 57ee1a8ad3315036f44e5b560fb55fa3f31c97e5..b10c42d50f0bcbf9aed764a2df85cffe7c6baf66 100644 --- a/substrate/client/db/Cargo.toml +++ b/substrate/client/db/Cargo.toml @@ -16,7 +16,7 @@ workspace = true targets = ["x86_64-unknown-linux-gnu"] [dependencies] -codec = { package = "parity-scale-codec", version = "3.6.1", features = [ +codec = { package = "parity-scale-codec", version = "3.6.12", features = [ "derive", ] } hash-db = "0.16.0" @@ -39,7 +39,7 @@ sp-state-machine = { path = "../../primitives/state-machine" } sp-trie = { path = "../../primitives/trie" } [dev-dependencies] -criterion = "0.4.0" +criterion = "0.5.1" kvdb-rocksdb = "0.19.0" rand = "0.8.5" tempfile = "3.1.0" @@ -47,7 +47,7 @@ quickcheck = { version = "1.0.3", default-features = false } kitchensink-runtime = { path = "../../bin/node/runtime" } sp-tracing = { path = "../../primitives/tracing" } substrate-test-runtime-client = { path = "../../test-utils/runtime/client" } -array-bytes = "6.1" +array-bytes = "6.2.2" [features] default = [] diff --git a/substrate/client/db/src/lib.rs b/substrate/client/db/src/lib.rs index 0faa90dfc4f925db8776c6914fcf864813b790a5..36f9aea817c9c7031ae69a588a9385e88e786b0c 100644 --- a/substrate/client/db/src/lib.rs +++ b/substrate/client/db/src/lib.rs @@ -68,8 +68,8 @@ use sc_client_api::{ use sc_state_db::{IsPruned, LastCanonicalized, StateDb}; use sp_arithmetic::traits::Saturating; use sp_blockchain::{ - Backend as _, CachedHeaderMetadata, Error as ClientError, HeaderBackend, HeaderMetadata, - HeaderMetadataCache, Result as ClientResult, + Backend as _, CachedHeaderMetadata, DisplacedLeavesAfterFinalization, Error as ClientError, + HeaderBackend, HeaderMetadata, HeaderMetadataCache, Result as ClientResult, }; use sp_core::{ offchain::OffchainOverlayedChange, @@ -747,19 +747,6 @@ impl sc_client_api::blockchain::Backend for BlockchainDb, - ) -> ClientResult> { - Ok(self - .leaves - .read() - .displaced_by_finalize_height(block_number) - .leaves() - .cloned() - .collect::>()) - } - fn children(&self, parent_hash: Block::Hash) -> ClientResult> { children::read_children(&*self.db, columns::META, meta_keys::CHILDREN_PREFIX, parent_hash) } @@ -1813,14 +1800,13 @@ impl Backend { apply_state_commit(transaction, commit); } - let new_displaced = self.blockchain.leaves.write().finalize_height(f_num); - self.prune_blocks( - transaction, - f_num, - f_hash, - &new_displaced, - current_transaction_justifications, - )?; + let new_displaced = self.blockchain.displaced_leaves_after_finalizing(f_hash, f_num)?; + let finalization_outcome = + FinalizationOutcome::new(new_displaced.displaced_leaves.clone().into_iter()); + + self.blockchain.leaves.write().remove_displaced_leaves(&finalization_outcome); + + self.prune_blocks(transaction, f_num, &new_displaced, current_transaction_justifications)?; Ok(()) } @@ -1829,8 +1815,7 @@ impl Backend { &self, transaction: &mut Transaction, finalized_number: NumberFor, - finalized_hash: Block::Hash, - displaced: &FinalizationOutcome>, + displaced: &DisplacedLeavesAfterFinalization, current_transaction_justifications: &mut HashMap, ) -> ClientResult<()> { match self.blocks_pruning { @@ -1858,10 +1843,10 @@ impl Backend { self.prune_block(transaction, BlockId::::number(number))?; } - self.prune_displaced_branches(transaction, finalized_hash, displaced)?; + self.prune_displaced_branches(transaction, displaced)?; }, BlocksPruning::KeepFinalized => { - self.prune_displaced_branches(transaction, finalized_hash, displaced)?; + self.prune_displaced_branches(transaction, displaced)?; }, } Ok(()) @@ -1870,21 +1855,13 @@ impl Backend { fn prune_displaced_branches( &self, transaction: &mut Transaction, - finalized: Block::Hash, - displaced: &FinalizationOutcome>, + displaced: &DisplacedLeavesAfterFinalization, ) -> ClientResult<()> { // Discard all blocks from displaced branches - for h in displaced.leaves() { - match sp_blockchain::tree_route(&self.blockchain, *h, finalized) { - Ok(tree_route) => - for r in tree_route.retracted() { - self.blockchain.insert_persisted_body_if_pinned(r.hash)?; - self.prune_block(transaction, BlockId::::hash(r.hash))?; - }, - Err(sp_blockchain::Error::UnknownBlock(_)) => { - // Sometimes routes can't be calculated. E.g. after warp sync. - }, - Err(e) => Err(e)?, + for (_, tree_route) in displaced.tree_routes.iter() { + for r in tree_route.retracted() { + self.blockchain.insert_persisted_body_if_pinned(r.hash)?; + self.prune_block(transaction, BlockId::::hash(r.hash))?; } } Ok(()) @@ -3190,6 +3167,9 @@ pub(crate) mod tests { #[test] fn test_leaves_pruned_on_finality() { + // / 1b - 2b - 3b + // 0 - 1a - 2a + // \ 1c let backend: Backend = Backend::new_test(10, 10); let block0 = insert_header(&backend, 0, Default::default(), None, Default::default()); @@ -3201,18 +3181,16 @@ pub(crate) mod tests { let block2_a = insert_header(&backend, 2, block1_a, None, Default::default()); let block2_b = insert_header(&backend, 2, block1_b, None, Default::default()); - let block2_c = insert_header(&backend, 2, block1_b, None, [1; 32].into()); - assert_eq!( - backend.blockchain().leaves().unwrap(), - vec![block2_a, block2_b, block2_c, block1_c] - ); + let block3_b = insert_header(&backend, 3, block2_b, None, [3; 32].into()); + + assert_eq!(backend.blockchain().leaves().unwrap(), vec![block3_b, block2_a, block1_c]); backend.finalize_block(block1_a, None).unwrap(); backend.finalize_block(block2_a, None).unwrap(); - // leaves at same height stay. Leaves at lower heights pruned. - assert_eq!(backend.blockchain().leaves().unwrap(), vec![block2_a, block2_b, block2_c]); + // All leaves are pruned that are known to not belong to canonical branch + assert_eq!(backend.blockchain().leaves().unwrap(), vec![block2_a]); } #[test] diff --git a/substrate/client/executor/Cargo.toml b/substrate/client/executor/Cargo.toml index efe8cc3069ca8be4d797196cbbf6256d248d76a0..1f54b82030ff226b179afe8f167e134417b859e9 100644 --- a/substrate/client/executor/Cargo.toml +++ b/substrate/client/executor/Cargo.toml @@ -21,7 +21,7 @@ parking_lot = "0.12.1" schnellru = "0.2.1" tracing = "0.1.29" -codec = { package = "parity-scale-codec", version = "3.6.1" } +codec = { package = "parity-scale-codec", version = "3.6.12" } sc-executor-common = { path = "common" } sc-executor-polkavm = { path = "polkavm" } sc-executor-wasmtime = { path = "wasmtime" } @@ -36,7 +36,7 @@ sp-version = { path = "../../primitives/version" } sp-wasm-interface = { path = "../../primitives/wasm-interface" } [dev-dependencies] -array-bytes = "6.1" +array-bytes = "6.2.2" assert_matches = "1.3.0" wat = "1.0" sc-runtime-test = { path = "runtime-test" } @@ -50,7 +50,7 @@ sp-tracing = { path = "../../primitives/tracing" } tracing-subscriber = { workspace = true } paste = "1.0" regex = "1.6.0" -criterion = "0.4.0" +criterion = "0.5.1" env_logger = "0.11" num_cpus = "1.13.1" tempfile = "3.3.0" diff --git a/substrate/client/executor/src/executor.rs b/substrate/client/executor/src/executor.rs index d56a3b389ef42868d0543303c5fbd63ea8d2d884..913bcdfcfe591d9f7c8a0b78198102bd5441750e 100644 --- a/substrate/client/executor/src/executor.rs +++ b/substrate/client/executor/src/executor.rs @@ -83,7 +83,7 @@ fn unwrap_heap_pages(pages: Option) -> HeapAllocStrategy { } /// Builder for creating a [`WasmExecutor`] instance. -pub struct WasmExecutorBuilder { +pub struct WasmExecutorBuilder { _phantom: PhantomData, method: WasmExecutionMethod, onchain_heap_alloc_strategy: Option, @@ -218,7 +218,7 @@ impl WasmExecutorBuilder { /// An abstraction over Wasm code executor. Supports selecting execution backend and /// manages runtime cache. -pub struct WasmExecutor { +pub struct WasmExecutor { /// Method used to execute fallback Wasm code. method: WasmExecutionMethod, /// The heap allocation strategy for onchain Wasm calls. @@ -252,10 +252,13 @@ impl Clone for WasmExecutor { } } -impl WasmExecutor -where - H: HostFunctions, -{ +impl Default for WasmExecutor { + fn default() -> Self { + WasmExecutorBuilder::new().build() + } +} + +impl WasmExecutor { /// Create new instance. /// /// # Parameters @@ -312,7 +315,12 @@ where pub fn allow_missing_host_functions(&mut self, allow_missing_host_functions: bool) { self.allow_missing_host_functions = allow_missing_host_functions } +} +impl WasmExecutor +where + H: HostFunctions, +{ /// Execute the given closure `f` with the latest runtime (based on `runtime_code`). /// /// The closure `f` is expected to return `Err(_)` when there happened a `panic!` in native code @@ -558,6 +566,9 @@ where /// A generic `CodeExecutor` implementation that uses a delegate to determine wasm code equivalence /// and dispatch to native code when possible, falling back on `WasmExecutor` when not. +#[deprecated( + note = "Native execution will be deprecated, please replace with `WasmExecutor`. Will be removed at end of 2024." +)] pub struct NativeElseWasmExecutor { /// Native runtime version info. native_version: NativeVersion, @@ -568,6 +579,7 @@ pub struct NativeElseWasmExecutor { use_native: bool, } +#[allow(deprecated)] impl NativeElseWasmExecutor { /// /// Create new instance. @@ -628,6 +640,7 @@ impl NativeElseWasmExecutor { } } +#[allow(deprecated)] impl RuntimeVersionOf for NativeElseWasmExecutor { fn runtime_version( &self, @@ -638,12 +651,14 @@ impl RuntimeVersionOf for NativeElseWasmExecutor } } +#[allow(deprecated)] impl GetNativeVersion for NativeElseWasmExecutor { fn native_version(&self) -> &NativeVersion { &self.native_version } } +#[allow(deprecated)] impl CodeExecutor for NativeElseWasmExecutor { type Error = Error; @@ -718,6 +733,7 @@ impl CodeExecutor for NativeElseWasmExecut } } +#[allow(deprecated)] impl Clone for NativeElseWasmExecutor { fn clone(&self) -> Self { NativeElseWasmExecutor { @@ -728,6 +744,7 @@ impl Clone for NativeElseWasmExecutor { } } +#[allow(deprecated)] impl sp_core::traits::ReadRuntimeVersion for NativeElseWasmExecutor { fn read_runtime_version( &self, @@ -765,6 +782,7 @@ mod tests { } #[test] + #[allow(deprecated)] fn native_executor_registers_custom_interface() { let executor = NativeElseWasmExecutor::::new_with_wasm_executor( WasmExecutor::builder().build(), diff --git a/substrate/client/executor/src/lib.rs b/substrate/client/executor/src/lib.rs index 6b99f0a6ee03b303d2d97ce05040828e3248312b..204f1ff22d74dc96bedb52711308010d59351a27 100644 --- a/substrate/client/executor/src/lib.rs +++ b/substrate/client/executor/src/lib.rs @@ -36,18 +36,17 @@ mod executor; mod integration_tests; mod wasm_runtime; -pub use self::{ - executor::{ - with_externalities_safe, NativeElseWasmExecutor, NativeExecutionDispatch, WasmExecutor, - }, - wasm_runtime::{read_embedded_version, WasmExecutionMethod}, -}; pub use codec::Codec; +#[allow(deprecated)] +pub use executor::NativeElseWasmExecutor; +pub use executor::{with_externalities_safe, NativeExecutionDispatch, WasmExecutor}; #[doc(hidden)] pub use sp_core::traits::Externalities; pub use sp_version::{NativeVersion, RuntimeVersion}; #[doc(hidden)] pub use sp_wasm_interface; +pub use sp_wasm_interface::HostFunctions; +pub use wasm_runtime::{read_embedded_version, WasmExecutionMethod}; pub use sc_executor_common::{ error, diff --git a/substrate/client/executor/wasmtime/Cargo.toml b/substrate/client/executor/wasmtime/Cargo.toml index f3fef4046914128dff2ad0904d445e89cba11c6a..d3d670650db789b2b9b854a5fda8724a506833ee 100644 --- a/substrate/client/executor/wasmtime/Cargo.toml +++ b/substrate/client/executor/wasmtime/Cargo.toml @@ -50,5 +50,5 @@ sc-runtime-test = { path = "../runtime-test" } sp-io = { path = "../../../primitives/io" } tempfile = "3.3.0" paste = "1.0" -codec = { package = "parity-scale-codec", version = "3.6.1" } +codec = { package = "parity-scale-codec", version = "3.6.12" } cargo_metadata = "0.15.4" diff --git a/substrate/client/keystore/Cargo.toml b/substrate/client/keystore/Cargo.toml index 908e0aa8f38ced48facaf99d05c0d7771f03fa26..443ce3507542c155119f2d424d18e9268b4d391b 100644 --- a/substrate/client/keystore/Cargo.toml +++ b/substrate/client/keystore/Cargo.toml @@ -17,7 +17,7 @@ workspace = true targets = ["x86_64-unknown-linux-gnu"] [dependencies] -array-bytes = "6.1" +array-bytes = "6.2.2" parking_lot = "0.12.1" serde_json = { workspace = true, default-features = true } thiserror = { workspace = true } diff --git a/substrate/client/merkle-mountain-range/Cargo.toml b/substrate/client/merkle-mountain-range/Cargo.toml index 46b7a1011c465f1aced062ba6978580a5f85c43c..3cf3cdd15dad9bb30fe2a9a70b6adc9f4541e56e 100644 --- a/substrate/client/merkle-mountain-range/Cargo.toml +++ b/substrate/client/merkle-mountain-range/Cargo.toml @@ -14,7 +14,7 @@ workspace = true # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] -codec = { package = "parity-scale-codec", version = "3.6.1" } +codec = { package = "parity-scale-codec", version = "3.6.12" } futures = "0.3.30" log = { workspace = true, default-features = true } sp-api = { path = "../../primitives/api" } diff --git a/substrate/client/merkle-mountain-range/rpc/Cargo.toml b/substrate/client/merkle-mountain-range/rpc/Cargo.toml index 9b391b76ea00b5e48700b7213afb691c149167ab..25e6e316a8be0ab6ec0ff70f38a05f603ebf8404 100644 --- a/substrate/client/merkle-mountain-range/rpc/Cargo.toml +++ b/substrate/client/merkle-mountain-range/rpc/Cargo.toml @@ -15,8 +15,8 @@ workspace = true targets = ["x86_64-unknown-linux-gnu"] [dependencies] -codec = { package = "parity-scale-codec", version = "3.6.1" } -jsonrpsee = { version = "0.22", features = ["client-core", "macros", "server"] } +codec = { package = "parity-scale-codec", version = "3.6.12" } +jsonrpsee = { version = "0.22.5", features = ["client-core", "macros", "server-core"] } serde = { features = ["derive"], workspace = true, default-features = true } sp-api = { path = "../../../primitives/api" } sp-blockchain = { path = "../../../primitives/blockchain" } diff --git a/substrate/client/merkle-mountain-range/rpc/src/lib.rs b/substrate/client/merkle-mountain-range/rpc/src/lib.rs index b4da9848de54cbc10ee549c3bd8cf1b033559722..41e73a5b8d75d6940c669786533e423fcc81b5ac 100644 --- a/substrate/client/merkle-mountain-range/rpc/src/lib.rs +++ b/substrate/client/merkle-mountain-range/rpc/src/lib.rs @@ -36,7 +36,7 @@ use sp_core::{ offchain::{storage::OffchainDb, OffchainDbExt, OffchainStorage}, Bytes, }; -use sp_mmr_primitives::{Error as MmrError, Proof}; +use sp_mmr_primitives::{Error as MmrError, LeafProof}; use sp_runtime::traits::{Block as BlockT, NumberFor}; pub use sp_mmr_primitives::MmrApi as MmrRuntimeApi; @@ -52,17 +52,17 @@ pub struct LeavesProof { pub block_hash: BlockHash, /// SCALE-encoded vector of `LeafData`. pub leaves: Bytes, - /// SCALE-encoded proof data. See [sp_mmr_primitives::Proof]. + /// SCALE-encoded proof data. See [sp_mmr_primitives::LeafProof]. pub proof: Bytes, } impl LeavesProof { /// Create new `LeavesProof` from a given vector of `Leaf` and a - /// [sp_mmr_primitives::Proof]. + /// [sp_mmr_primitives::LeafProof]. pub fn new( block_hash: BlockHash, leaves: Vec, - proof: Proof, + proof: LeafProof, ) -> Self where Leaf: Encode, @@ -258,7 +258,7 @@ mod tests { fn should_serialize_leaf_proof() { // given let leaf = vec![1_u8, 2, 3, 4]; - let proof = Proof { + let proof = LeafProof { leaf_indices: vec![1], leaf_count: 9, items: vec![H256::repeat_byte(1), H256::repeat_byte(2)], @@ -281,7 +281,7 @@ mod tests { // given let leaf_a = vec![1_u8, 2, 3, 4]; let leaf_b = vec![2_u8, 2, 3, 4]; - let proof = Proof { + let proof = LeafProof { leaf_indices: vec![1, 2], leaf_count: 9, items: vec![H256::repeat_byte(1), H256::repeat_byte(2)], @@ -306,7 +306,7 @@ mod tests { block_hash: H256::repeat_byte(0), leaves: Bytes(vec![vec![1_u8, 2, 3, 4]].encode()), proof: Bytes( - Proof { + LeafProof { leaf_indices: vec![1], leaf_count: 9, items: vec![H256::repeat_byte(1), H256::repeat_byte(2)], @@ -333,7 +333,7 @@ mod tests { block_hash: H256::repeat_byte(0), leaves: Bytes(vec![vec![1_u8, 2, 3, 4], vec![2_u8, 2, 3, 4]].encode()), proof: Bytes( - Proof { + LeafProof { leaf_indices: vec![1, 2], leaf_count: 9, items: vec![H256::repeat_byte(1), H256::repeat_byte(2)], diff --git a/substrate/client/merkle-mountain-range/src/offchain_mmr.rs b/substrate/client/merkle-mountain-range/src/offchain_mmr.rs index 3c3f0beb6c6a9196bfb8bf6d1108b737869d346c..94593f9c2c7ba265fe2ec1b0b50a6e1b962788a7 100644 --- a/substrate/client/merkle-mountain-range/src/offchain_mmr.rs +++ b/substrate/client/merkle-mountain-range/src/offchain_mmr.rs @@ -33,7 +33,7 @@ use sp_runtime::{ traits::{Block, Header, NumberFor, One}, Saturating, }; -use std::{collections::VecDeque, sync::Arc}; +use std::{collections::VecDeque, default::Default, sync::Arc}; /// `OffchainMMR` exposes MMR offchain canonicalization and pruning logic. pub struct OffchainMmr, C> { @@ -273,12 +273,11 @@ where self.write_gadget_state_or_log(); // Remove offchain MMR nodes for stale forks. - let stale_forks = self.client.expand_forks(¬ification.stale_heads).unwrap_or_else( - |(stale_forks, e)| { - warn!(target: LOG_TARGET, "{:?}", e); - stale_forks - }, - ); + let stale_forks = self.client.expand_forks(¬ification.stale_heads).unwrap_or_else(|e| { + warn!(target: LOG_TARGET, "{:?}", e); + + Default::default() + }); for hash in stale_forks.iter() { self.prune_branch(hash); } diff --git a/substrate/client/merkle-mountain-range/src/test_utils.rs b/substrate/client/merkle-mountain-range/src/test_utils.rs index 5775b4cfe67cd49878508521ec72ba9af413a187..fcf9fa25b593c86eb780d8b563e6ecc55ecb50a7 100644 --- a/substrate/client/merkle-mountain-range/src/test_utils.rs +++ b/substrate/client/merkle-mountain-range/src/test_utils.rs @@ -309,11 +309,11 @@ sp_api::mock_impl_runtime_apis! { &self, _block_numbers: Vec, _best_known_block_number: Option, - ) -> Result<(Vec, mmr::Proof), mmr::Error> { + ) -> Result<(Vec, mmr::LeafProof), mmr::Error> { Err(mmr::Error::PalletNotIncluded) } - fn verify_proof(_leaves: Vec, _proof: mmr::Proof) + fn verify_proof(_leaves: Vec, _proof: mmr::LeafProof) -> Result<(), mmr::Error> { Err(mmr::Error::PalletNotIncluded) @@ -322,7 +322,7 @@ sp_api::mock_impl_runtime_apis! { fn verify_proof_stateless( _root: MmrHash, _leaves: Vec, - _proof: mmr::Proof + _proof: mmr::LeafProof ) -> Result<(), mmr::Error> { Err(mmr::Error::PalletNotIncluded) } diff --git a/substrate/client/mixnet/Cargo.toml b/substrate/client/mixnet/Cargo.toml index 65b81bda4b08de83101a01880d1aaac1a358e1ad..1626305639498855148b515e666e1e91a603643f 100644 --- a/substrate/client/mixnet/Cargo.toml +++ b/substrate/client/mixnet/Cargo.toml @@ -4,7 +4,7 @@ name = "sc-mixnet" version = "0.4.0" license = "GPL-3.0-or-later WITH Classpath-exception-2.0" authors = ["Parity Technologies "] -edition = "2021" +edition.workspace = true homepage = "https://substrate.io" repository = "https://github.com/paritytech/substrate/" readme = "README.md" @@ -16,11 +16,11 @@ workspace = true targets = ["x86_64-unknown-linux-gnu"] [dependencies] -array-bytes = "4.1" +array-bytes = "6.2.2" arrayvec = "0.7.2" blake2 = "0.10.4" bytes = "1" -codec = { package = "parity-scale-codec", version = "3.6.1", default-features = false, features = ["derive"] } +codec = { package = "parity-scale-codec", version = "3.6.12", default-features = false, features = ["derive"] } futures = "0.3.30" futures-timer = "3.0.2" log = { workspace = true, default-features = true } diff --git a/substrate/client/network-gossip/Cargo.toml b/substrate/client/network-gossip/Cargo.toml index ad81381edea1800035a96b608681c5f3691d2d05..3eeea6651186162ed2f28bdf12ec08ad184df906 100644 --- a/substrate/client/network-gossip/Cargo.toml +++ b/substrate/client/network-gossip/Cargo.toml @@ -34,6 +34,6 @@ sp-runtime = { path = "../../primitives/runtime" } [dev-dependencies] tokio = "1.37" async-trait = "0.1.79" -codec = { package = "parity-scale-codec", version = "3.0.0", features = ["derive"] } +codec = { package = "parity-scale-codec", version = "3.6.12", features = ["derive"] } quickcheck = { version = "1.0.3", default-features = false } substrate-test-runtime-client = { path = "../../test-utils/runtime/client" } diff --git a/substrate/client/network/Cargo.toml b/substrate/client/network/Cargo.toml index 0879481a419930fae590e3ac68cde17f1ceb2207..5a469469539b2f22e2bcc11322b018aebce164ca 100644 --- a/substrate/client/network/Cargo.toml +++ b/substrate/client/network/Cargo.toml @@ -17,16 +17,16 @@ workspace = true targets = ["x86_64-unknown-linux-gnu"] [build-dependencies] -prost-build = "0.11" +prost-build = "0.12.4" [dependencies] -array-bytes = "6.1" +array-bytes = "6.2.2" async-channel = "1.8.0" async-trait = "0.1.79" asynchronous-codec = "0.6" bytes = "1" cid = "0.9.0" -codec = { package = "parity-scale-codec", version = "3.6.1", features = ["derive"] } +codec = { package = "parity-scale-codec", version = "3.6.12", features = ["derive"] } either = "1.5.3" fnv = "1.0.6" futures = "0.3.30" @@ -49,7 +49,7 @@ tokio-stream = "0.1.7" unsigned-varint = { version = "0.7.2", features = ["asynchronous_codec", "futures"] } zeroize = "1.4.3" prometheus-endpoint = { package = "substrate-prometheus-endpoint", path = "../../utils/prometheus" } -prost = "0.11" +prost = "0.12.4" sc-client-api = { path = "../api" } sc-network-common = { path = "common" } sc-network-types = { path = "types" } @@ -59,7 +59,7 @@ sp-blockchain = { path = "../../primitives/blockchain" } sp-core = { path = "../../primitives/core" } sp-runtime = { path = "../../primitives/runtime" } wasm-timer = "0.2" -litep2p = { git = "https://github.com/paritytech/litep2p", branch = "master" } +litep2p = { git = "https://github.com/paritytech/litep2p", rev = "e03a6023882db111beeb24d8c0ceaac0721d3f0f" } once_cell = "1.18.0" void = "1.0.2" schnellru = "0.2.1" diff --git a/substrate/client/network/common/Cargo.toml b/substrate/client/network/common/Cargo.toml index 4478693456f7e32bcab4cf6ce8a94a48a5e7c727..9a1bf5b88ea1a97cf6bdfe358a44338561500b50 100644 --- a/substrate/client/network/common/Cargo.toml +++ b/substrate/client/network/common/Cargo.toml @@ -16,12 +16,12 @@ workspace = true targets = ["x86_64-unknown-linux-gnu"] [build-dependencies] -prost-build = "0.11" +prost-build = "0.12.4" [dependencies] async-trait = "0.1.79" bitflags = "1.3.2" -codec = { package = "parity-scale-codec", version = "3.6.1", features = [ +codec = { package = "parity-scale-codec", version = "3.6.12", features = [ "derive", ] } futures = "0.3.30" diff --git a/substrate/client/network/light/Cargo.toml b/substrate/client/network/light/Cargo.toml index d75a2a908da54ceb7c27a3ba79e4ac6c0d2ba071..baaed578b884172bdcfba5eb2a66e48ac32c56a5 100644 --- a/substrate/client/network/light/Cargo.toml +++ b/substrate/client/network/light/Cargo.toml @@ -16,17 +16,17 @@ workspace = true targets = ["x86_64-unknown-linux-gnu"] [build-dependencies] -prost-build = "0.11" +prost-build = "0.12.4" [dependencies] async-channel = "1.8.0" -array-bytes = "6.1" -codec = { package = "parity-scale-codec", version = "3.6.1", features = [ +array-bytes = "6.2.2" +codec = { package = "parity-scale-codec", version = "3.6.12", features = [ "derive", ] } futures = "0.3.30" log = { workspace = true, default-features = true } -prost = "0.12" +prost = "0.12.4" sp-blockchain = { path = "../../../primitives/blockchain" } sc-client-api = { path = "../../api" } sc-network-types = { path = "../types" } diff --git a/substrate/client/network/src/discovery.rs b/substrate/client/network/src/discovery.rs index 4e2121c5540d6c7c6d895e2756b266f6b5a945e8..7d4481b0d06f947619b66ab60a5ab60b8fe15a99 100644 --- a/substrate/client/network/src/discovery.rs +++ b/substrate/client/network/src/discovery.rs @@ -105,7 +105,8 @@ pub struct DiscoveryConfig { discovery_only_if_under_num: u64, enable_mdns: bool, kademlia_disjoint_query_paths: bool, - kademlia_protocols: Vec>, + kademlia_protocol: Vec, + kademlia_legacy_protocol: Vec, kademlia_replication_factor: NonZeroUsize, } @@ -121,7 +122,8 @@ impl DiscoveryConfig { discovery_only_if_under_num: std::u64::MAX, enable_mdns: false, kademlia_disjoint_query_paths: false, - kademlia_protocols: Vec::new(), + kademlia_protocol: Vec::new(), + kademlia_legacy_protocol: Vec::new(), kademlia_replication_factor: NonZeroUsize::new(DEFAULT_KADEMLIA_REPLICATION_FACTOR) .expect("value is a constant; constant is non-zero; qed."), } @@ -177,9 +179,8 @@ impl DiscoveryConfig { fork_id: Option<&str>, protocol_id: &ProtocolId, ) -> &mut Self { - self.kademlia_protocols = Vec::new(); - self.kademlia_protocols.push(kademlia_protocol_name(genesis_hash, fork_id)); - self.kademlia_protocols.push(legacy_kademlia_protocol_name(protocol_id)); + self.kademlia_protocol = kademlia_protocol_name(genesis_hash, fork_id); + self.kademlia_legacy_protocol = legacy_kademlia_protocol_name(protocol_id); self } @@ -207,14 +208,19 @@ impl DiscoveryConfig { discovery_only_if_under_num, enable_mdns, kademlia_disjoint_query_paths, - kademlia_protocols, + kademlia_protocol, + kademlia_legacy_protocol, kademlia_replication_factor, } = self; - let kademlia = if !kademlia_protocols.is_empty() { + let kademlia = if !kademlia_protocol.is_empty() { let mut config = KademliaConfig::default(); config.set_replication_factor(kademlia_replication_factor); + // Populate kad with both the legacy and the new protocol names. + // Remove the legacy protocol: + // https://github.com/paritytech/polkadot-sdk/issues/504 + let kademlia_protocols = [kademlia_protocol.clone(), kademlia_legacy_protocol]; config.set_protocol_names(kademlia_protocols.into_iter().map(Into::into).collect()); // By default Kademlia attempts to insert all peers into its routing table once a // dialing attempt succeeds. In order to control which peer is added, disable the @@ -266,6 +272,7 @@ impl DiscoveryConfig { .expect("value is a constant; constant is non-zero; qed."), ), records_to_publish: Default::default(), + kademlia_protocol, } } } @@ -309,6 +316,11 @@ pub struct DiscoveryBehaviour { /// did not return the record(in `FinishedWithNoAdditionalRecord`). We will then put the record /// to these peers. records_to_publish: HashMap, + /// The chain based kademlia protocol name (including genesis hash and fork id). + /// + /// Remove when all nodes are upgraded to genesis hash and fork ID-based Kademlia: + /// . + kademlia_protocol: Vec, } impl DiscoveryBehaviour { @@ -366,23 +378,29 @@ impl DiscoveryBehaviour { return } - if let Some(matching_protocol) = supported_protocols + // The supported protocols must include the chain-based Kademlia protocol. + // + // Extract the chain-based Kademlia protocol from `kademlia.protocol_name()` + // when all nodes are upgraded to genesis hash and fork ID-based Kademlia: + // https://github.com/paritytech/polkadot-sdk/issues/504. + if !supported_protocols .iter() - .find(|p| kademlia.protocol_names().iter().any(|k| k.as_ref() == p.as_ref())) + .any(|p| p.as_ref() == self.kademlia_protocol.as_slice()) { - trace!( - target: "sub-libp2p", - "Adding self-reported address {} from {} to Kademlia DHT {}.", - addr, peer_id, String::from_utf8_lossy(matching_protocol.as_ref()), - ); - kademlia.add_address(peer_id, addr.clone()); - } else { trace!( target: "sub-libp2p", "Ignoring self-reported address {} from {} as remote node is not part of the \ Kademlia DHT supported by the local node.", addr, peer_id, ); + return } + + trace!( + target: "sub-libp2p", + "Adding self-reported address {} from {} to Kademlia DHT.", + addr, peer_id + ); + kademlia.add_address(peer_id, addr.clone()); } } @@ -1075,17 +1093,20 @@ mod tests { .unwrap(); // Test both genesis hash-based and legacy // protocol names. - let protocol_name = if swarm_n % 2 == 0 { - kademlia_protocol_name(genesis_hash, fork_id) + let protocol_names = if swarm_n % 2 == 0 { + vec![kademlia_protocol_name(genesis_hash, fork_id)] } else { - legacy_kademlia_protocol_name(&protocol_id) + vec![ + legacy_kademlia_protocol_name(&protocol_id), + kademlia_protocol_name(genesis_hash, fork_id), + ] }; swarms[swarm_n] .0 .behaviour_mut() .add_self_reported_address( &other, - &[protocol_name], + protocol_names.as_slice(), addr, ); @@ -1181,9 +1202,56 @@ mod tests { &[kademlia_protocol_name(supported_genesis_hash, None)], remote_addr.clone(), ); + { + let kademlia = discovery.kademlia.as_mut().unwrap(); + assert!( + !kademlia + .kbucket(remote_peer_id) + .expect("Remote peer id not to be equal to local peer id.") + .is_empty(), + "Expect peer with supported protocol to be added." + ); + } + + let unsupported_peer_id = predictable_peer_id(b"00000000000000000000000000000002"); + let unsupported_peer_addr: Multiaddr = "/memory/2".parse().unwrap(); + + // Check the unsupported peer is not present before and after the call. + { + let kademlia = discovery.kademlia.as_mut().unwrap(); + assert!( + kademlia + .kbucket(unsupported_peer_id) + .expect("Remote peer id not to be equal to local peer id.") + .is_empty(), + "Expect unsupported peer not to be added." + ); + } + // Note: legacy protocol is not supported without genesis hash and fork ID, + // if the legacy is the only protocol supported, then the peer will not be added. + discovery.add_self_reported_address( + &unsupported_peer_id, + &[legacy_kademlia_protocol_name(&supported_protocol_id)], + unsupported_peer_addr.clone(), + ); + { + let kademlia = discovery.kademlia.as_mut().unwrap(); + assert!( + kademlia + .kbucket(unsupported_peer_id) + .expect("Remote peer id not to be equal to local peer id.") + .is_empty(), + "Expect unsupported peer not to be added." + ); + } + + // Supported legacy and genesis based protocols are allowed to be added. discovery.add_self_reported_address( &another_peer_id, - &[legacy_kademlia_protocol_name(&supported_protocol_id)], + &[ + legacy_kademlia_protocol_name(&supported_protocol_id), + kademlia_protocol_name(supported_genesis_hash, None), + ], another_addr.clone(), ); @@ -1194,6 +1262,13 @@ mod tests { kademlia.kbuckets().fold(0, |acc, bucket| acc + bucket.num_entries()), "Expect peers with supported protocol to be added." ); + assert!( + !kademlia + .kbucket(another_peer_id) + .expect("Remote peer id not to be equal to local peer id.") + .is_empty(), + "Expect peer with supported protocol to be added." + ); } } } diff --git a/substrate/client/network/src/litep2p/discovery.rs b/substrate/client/network/src/litep2p/discovery.rs index b10d11f750b2a42c758421ffc7816bec21bfa368..351380755dbd644abc01ed8c09a094d28b8b8073 100644 --- a/substrate/client/network/src/litep2p/discovery.rs +++ b/substrate/client/network/src/litep2p/discovery.rs @@ -267,10 +267,10 @@ impl Discovery { allow_non_global_addresses: config.allow_non_globals_in_dht, public_addresses: config.public_addresses.iter().cloned().map(Into::into).collect(), next_kad_query: Some(Delay::new(KADEMLIA_QUERY_INTERVAL)), - local_protocols: HashSet::from_iter([ - kademlia_protocol_name(genesis_hash, fork_id), - legacy_kademlia_protocol_name(protocol_id), - ]), + local_protocols: HashSet::from_iter([kademlia_protocol_name( + genesis_hash, + fork_id, + )]), }, ping_config, identify_config, @@ -294,6 +294,11 @@ impl Discovery { addresses: Vec, ) { if self.local_protocols.is_disjoint(&supported_protocols) { + log::trace!( + target: "sub-libp2p", + "Ignoring self-reported address of peer {peer} as remote node is not part of the \ + Kademlia DHT supported by the local node.", + ); return } diff --git a/substrate/client/network/src/protocol/notifications/upgrade/collec.rs b/substrate/client/network/src/protocol/notifications/upgrade/collec.rs index 791821b3f75dab135a34f7478b4c1c808566890e..33c090ae50e9d87b8976f78fc61e751b474b49ec 100644 --- a/substrate/client/network/src/protocol/notifications/upgrade/collec.rs +++ b/substrate/client/network/src/protocol/notifications/upgrade/collec.rs @@ -19,7 +19,6 @@ use futures::prelude::*; use libp2p::core::upgrade::{InboundUpgrade, ProtocolName, UpgradeInfo}; use std::{ - iter::FromIterator, pin::Pin, task::{Context, Poll}, vec, diff --git a/substrate/client/network/statement/Cargo.toml b/substrate/client/network/statement/Cargo.toml index 4ffe6d6e3aedf9154c073f63fa2ddbf4dda12c01..0dfaa491b65c93acb50f44bb002d655043317d99 100644 --- a/substrate/client/network/statement/Cargo.toml +++ b/substrate/client/network/statement/Cargo.toml @@ -16,9 +16,9 @@ workspace = true targets = ["x86_64-unknown-linux-gnu"] [dependencies] -array-bytes = "6.1" +array-bytes = "6.2.2" async-channel = "1.8.0" -codec = { package = "parity-scale-codec", version = "3.6.1", features = ["derive"] } +codec = { package = "parity-scale-codec", version = "3.6.12", features = ["derive"] } futures = "0.3.30" libp2p = "0.51.4" log = { workspace = true, default-features = true } diff --git a/substrate/client/network/sync/Cargo.toml b/substrate/client/network/sync/Cargo.toml index eb79973c2739a3bfd11477b4bbf0979249a741e6..964090444b22afdeca073ebc25d0be71817f1248 100644 --- a/substrate/client/network/sync/Cargo.toml +++ b/substrate/client/network/sync/Cargo.toml @@ -16,19 +16,19 @@ workspace = true targets = ["x86_64-unknown-linux-gnu"] [build-dependencies] -prost-build = "0.11" +prost-build = "0.12.4" [dependencies] -array-bytes = "6.1" +array-bytes = "6.2.2" async-channel = "1.8.0" async-trait = "0.1.79" -codec = { package = "parity-scale-codec", version = "3.6.1", features = ["derive"] } +codec = { package = "parity-scale-codec", version = "3.6.12", features = ["derive"] } futures = "0.3.30" futures-timer = "3.0.2" libp2p = "0.51.4" log = { workspace = true, default-features = true } mockall = "0.11.3" -prost = "0.12" +prost = "0.12.4" schnellru = "0.2.1" smallvec = "1.11.0" thiserror = { workspace = true } diff --git a/substrate/client/network/sync/src/block_announce_validator.rs b/substrate/client/network/sync/src/block_announce_validator.rs index 3c994dd69442a0a7b0f29820b8044f0308436c48..cb1d5ee6b22ee92104faa061fbc8958ce20d316d 100644 --- a/substrate/client/network/sync/src/block_announce_validator.rs +++ b/substrate/client/network/sync/src/block_announce_validator.rs @@ -156,7 +156,7 @@ impl BlockAnnounceValidator { return }, AllocateSlotForBlockAnnounceValidation::MaximumPeerSlotsReached => { - warn!( + debug!( target: LOG_TARGET, "💔 Ignored block (#{} -- {}) announcement from {} because all validation slots for this peer are occupied.", number, diff --git a/substrate/client/network/transactions/Cargo.toml b/substrate/client/network/transactions/Cargo.toml index d74636d60a7da57edff1a14e003b623b252c94bc..d871b59b37bb120783aa2e27a23aa9ee814b3ddf 100644 --- a/substrate/client/network/transactions/Cargo.toml +++ b/substrate/client/network/transactions/Cargo.toml @@ -16,8 +16,8 @@ workspace = true targets = ["x86_64-unknown-linux-gnu"] [dependencies] -array-bytes = "6.1" -codec = { package = "parity-scale-codec", version = "3.6.1", features = ["derive"] } +array-bytes = "6.2.2" +codec = { package = "parity-scale-codec", version = "3.6.12", features = ["derive"] } futures = "0.3.30" libp2p = "0.51.4" log = { workspace = true, default-features = true } diff --git a/substrate/client/network/types/Cargo.toml b/substrate/client/network/types/Cargo.toml index 430adbac50920c3877841fd1c99af25347b33605..f9d9330a439511d9d7a5db4c49f1208fceda7bf3 100644 --- a/substrate/client/network/types/Cargo.toml +++ b/substrate/client/network/types/Cargo.toml @@ -1,7 +1,7 @@ [package] description = "Substrate network types" name = "sc-network-types" -version = "0.10.0-dev" +version = "0.10.0" license = "GPL-3.0-or-later WITH Classpath-exception-2.0" authors.workspace = true edition.workspace = true @@ -10,10 +10,10 @@ repository.workspace = true documentation = "https://docs.rs/sc-network-types" [dependencies] -bs58 = "0.4.0" +bs58 = "0.5.0" ed25519-dalek = "2.1" libp2p-identity = { version = "0.1.3", features = ["ed25519", "peerid"] } -litep2p = { git = "https://github.com/paritytech/litep2p", branch = "master" } +litep2p = { git = "https://github.com/paritytech/litep2p", rev = "e03a6023882db111beeb24d8c0ceaac0721d3f0f" } multiaddr = "0.17.0" multihash = { version = "0.17.0", default-features = false, features = ["identity", "multihash-impl", "sha2", "std"] } rand = "0.8.5" diff --git a/substrate/client/offchain/Cargo.toml b/substrate/client/offchain/Cargo.toml index b834241fe5a7e1b92b1683a92689b6d3de2a2995..2944ff7f4f49dd879b35a1ba70b214824fbdd089 100644 --- a/substrate/client/offchain/Cargo.toml +++ b/substrate/client/offchain/Cargo.toml @@ -16,9 +16,9 @@ workspace = true targets = ["x86_64-unknown-linux-gnu"] [dependencies] -array-bytes = "6.1" +array-bytes = "6.2.2" bytes = "1.1" -codec = { package = "parity-scale-codec", version = "3.6.1", features = ["derive"] } +codec = { package = "parity-scale-codec", version = "3.6.12", features = ["derive"] } fnv = "1.0.6" futures = "0.3.30" futures-timer = "3.0.2" diff --git a/substrate/client/rpc-api/Cargo.toml b/substrate/client/rpc-api/Cargo.toml index 169714d22453d92276b02d949fa86e06862467b4..d8f833e2b8d45eb217fe6f4f9d835038e6167705 100644 --- a/substrate/client/rpc-api/Cargo.toml +++ b/substrate/client/rpc-api/Cargo.toml @@ -16,7 +16,7 @@ workspace = true targets = ["x86_64-unknown-linux-gnu"] [dependencies] -codec = { package = "parity-scale-codec", version = "3.6.1" } +codec = { package = "parity-scale-codec", version = "3.6.12" } scale-info = { version = "2.11.1", default-features = false, features = ["derive"] } serde = { features = ["derive"], workspace = true, default-features = true } serde_json = { workspace = true, default-features = true } @@ -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.22", features = ["client-core", "macros", "server"] } +jsonrpsee = { version = "0.22.5", features = ["client-core", "macros", "server-core"] } diff --git a/substrate/client/rpc-servers/Cargo.toml b/substrate/client/rpc-servers/Cargo.toml index bc21b5b1582f95165ff6d529361c85a413fb915e..7837c852a1c9b73992b9a24f911ce7bba937cdab 100644 --- a/substrate/client/rpc-servers/Cargo.toml +++ b/substrate/client/rpc-servers/Cargo.toml @@ -16,14 +16,16 @@ workspace = true targets = ["x86_64-unknown-linux-gnu"] [dependencies] +forwarded-header-value = "0.1.1" +futures = "0.3.30" +governor = "0.6.0" +http = "0.2.8" +hyper = "0.14.27" +ip_network = "0.4.1" jsonrpsee = { version = "0.22", features = ["server"] } log = { workspace = true, default-features = true } +prometheus-endpoint = { package = "substrate-prometheus-endpoint", path = "../../utils/prometheus" } 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.30" -governor = "0.6.0" +tower-http = { version = "0.4.0", features = ["cors"] } diff --git a/substrate/client/rpc-servers/src/lib.rs b/substrate/client/rpc-servers/src/lib.rs index ad4b444c7ff425ea84ba25e756d61854c3a4569e..ba1fcf5e36771008e139bc69ff492eb645e2bcae 100644 --- a/substrate/client/rpc-servers/src/lib.rs +++ b/substrate/client/rpc-servers/src/lib.rs @@ -21,27 +21,28 @@ #![warn(missing_docs)] pub mod middleware; +pub mod utils; 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::http::{HostFilterLayer, ProxyGetRequestLayer}, - stop_channel, ws, PingConfig, StopHandle, TowerServiceBuilder, + middleware::http::ProxyGetRequestLayer, stop_channel, ws, PingConfig, StopHandle, + TowerServiceBuilder, }, Methods, RpcModule, }; use tokio::net::TcpListener; use tower::Service; -use tower_http::cors::{AllowOrigin, CorsLayer}; +use utils::{build_rpc_api, format_cors, get_proxy_ip, host_filtering, try_into_cors}; +pub use ip_network::IpNetwork; pub use jsonrpsee::{ core::{ id_providers::{RandomIntegerIdProvider, RandomStringIdProvider}, @@ -85,6 +86,10 @@ pub struct Config<'a, M: Send + Sync + 'static> { pub batch_config: BatchRequestConfig, /// Rate limit calls per minute. pub rate_limit: Option, + /// Disable rate limit for certain ips. + pub rate_limit_whitelisted_ips: Vec, + /// Trust proxy headers for rate limiting. + pub rate_limit_trust_proxy_headers: bool, } #[derive(Debug, Clone)] @@ -117,11 +122,13 @@ where tokio_handle, rpc_api, rate_limit, + rate_limit_whitelisted_ips, + rate_limit_trust_proxy_headers, } = 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 host_filter = host_filtering(cors.is_some(), local_addr); let http_middleware = tower::ServiceBuilder::new() .option_layer(host_filter) @@ -160,20 +167,39 @@ where stop_handle: stop_handle.clone(), }; - let make_service = make_service_fn(move |_conn: &AddrStream| { + let make_service = make_service_fn(move |addr: &AddrStream| { let cfg = cfg.clone(); + let rate_limit_whitelisted_ips = rate_limit_whitelisted_ips.clone(); + let ip = addr.remote_addr().ip(); async move { let cfg = cfg.clone(); + let rate_limit_whitelisted_ips = rate_limit_whitelisted_ips.clone(); Ok::<_, Infallible>(service_fn(move |req| { + let proxy_ip = + if rate_limit_trust_proxy_headers { get_proxy_ip(&req) } else { None }; + + let rate_limit_cfg = if rate_limit_whitelisted_ips + .iter() + .any(|ips| ips.contains(proxy_ip.unwrap_or(ip))) + { + log::debug!(target: "rpc", "ip={ip}, proxy_ip={:?} is trusted, disabling rate-limit", proxy_ip); + None + } else { + if !rate_limit_whitelisted_ips.is_empty() { + log::debug!(target: "rpc", "ip={ip}, proxy_ip={:?} is not trusted, rate-limit enabled", proxy_ip); + } + rate_limit + }; + 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) { + let middleware_layer = match (metrics, rate_limit_cfg) { (None, None) => None, (Some(metrics), None) => Some( MiddlewareLayer::new().with_metrics(Metrics::new(metrics, transport_label)), @@ -227,57 +253,3 @@ where Ok(server_handle) } - -fn hosts_filtering(enabled: bool, addr: Option) -> Option { - // If the local_addr failed, fallback to wildcard. - let port = addr.map_or("*".to_string(), |p| p.port().to_string()); - - if enabled { - // NOTE: The listening addresses are whitelisted by default. - let hosts = - [format!("localhost:{port}"), format!("127.0.0.1:{port}"), format!("[::1]:{port}")]; - Some(HostFilterLayer::new(hosts).expect("Valid hosts; qed")) - } else { - None - } -} - -fn build_rpc_api(mut rpc_api: RpcModule) -> RpcModule { - let mut available_methods = rpc_api.method_names().collect::>(); - // The "rpc_methods" is defined below and we want it to be part of the reported methods. - available_methods.push("rpc_methods"); - available_methods.sort(); - - rpc_api - .register_method("rpc_methods", move |_, _| { - serde_json::json!({ - "methods": available_methods, - }) - }) - .expect("infallible all other methods have their own address space; qed"); - - rpc_api -} - -fn try_into_cors( - maybe_cors: Option<&Vec>, -) -> Result> { - if let Some(cors) = maybe_cors { - let mut list = Vec::new(); - for origin in cors { - list.push(HeaderValue::from_str(origin)?); - } - Ok(CorsLayer::new().allow_origin(AllowOrigin::list(list))) - } else { - // allow all cors - Ok(CorsLayer::permissive()) - } -} - -fn format_cors(maybe_cors: Option<&Vec>) -> String { - if let Some(cors) = maybe_cors { - format!("{:?}", cors) - } else { - format!("{:?}", ["*"]) - } -} diff --git a/substrate/client/rpc-servers/src/utils.rs b/substrate/client/rpc-servers/src/utils.rs new file mode 100644 index 0000000000000000000000000000000000000000..d99b8e637d9df3f1322ee8083342f449f958a311 --- /dev/null +++ b/substrate/client/rpc-servers/src/utils.rs @@ -0,0 +1,189 @@ +// This file is part of Substrate. + +// Copyright (C) Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 + +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +//! Substrate RPC server utils. + +use std::{ + error::Error as StdError, + net::{IpAddr, SocketAddr}, + str::FromStr, +}; + +use forwarded_header_value::ForwardedHeaderValue; +use hyper::{ + header::{HeaderName, HeaderValue}, + Request, +}; +use jsonrpsee::{server::middleware::http::HostFilterLayer, RpcModule}; +use tower_http::cors::{AllowOrigin, CorsLayer}; + +const X_FORWARDED_FOR: HeaderName = HeaderName::from_static("x-forwarded-for"); +const X_REAL_IP: HeaderName = HeaderName::from_static("x-real-ip"); +const FORWARDED: HeaderName = HeaderName::from_static("forwarded"); + +pub(crate) fn host_filtering(enabled: bool, addr: Option) -> Option { + // If the local_addr failed, fallback to wildcard. + let port = addr.map_or("*".to_string(), |p| p.port().to_string()); + + if enabled { + // NOTE: The listening addresses are whitelisted by default. + let hosts = + [format!("localhost:{port}"), format!("127.0.0.1:{port}"), format!("[::1]:{port}")]; + Some(HostFilterLayer::new(hosts).expect("Valid hosts; qed")) + } else { + None + } +} + +pub(crate) fn build_rpc_api(mut rpc_api: RpcModule) -> RpcModule { + let mut available_methods = rpc_api.method_names().collect::>(); + // The "rpc_methods" is defined below and we want it to be part of the reported methods. + available_methods.push("rpc_methods"); + available_methods.sort(); + + rpc_api + .register_method("rpc_methods", move |_, _| { + serde_json::json!({ + "methods": available_methods, + }) + }) + .expect("infallible all other methods have their own address space; qed"); + + rpc_api +} + +pub(crate) fn try_into_cors( + maybe_cors: Option<&Vec>, +) -> Result> { + if let Some(cors) = maybe_cors { + let mut list = Vec::new(); + for origin in cors { + list.push(HeaderValue::from_str(origin)?); + } + Ok(CorsLayer::new().allow_origin(AllowOrigin::list(list))) + } else { + // allow all cors + Ok(CorsLayer::permissive()) + } +} + +pub(crate) fn format_cors(maybe_cors: Option<&Vec>) -> String { + if let Some(cors) = maybe_cors { + format!("{:?}", cors) + } else { + format!("{:?}", ["*"]) + } +} + +/// Extracts the IP addr from the HTTP request. +/// +/// It is extracted in the following order: +/// 1. `Forwarded` header. +/// 2. `X-Forwarded-For` header. +/// 3. `X-Real-Ip`. +pub(crate) fn get_proxy_ip(req: &Request) -> Option { + if let Some(ip) = req + .headers() + .get(&FORWARDED) + .and_then(|v| v.to_str().ok()) + .and_then(|v| ForwardedHeaderValue::from_forwarded(v).ok()) + .and_then(|v| v.remotest_forwarded_for_ip()) + { + return Some(ip); + } + + if let Some(ip) = req + .headers() + .get(&X_FORWARDED_FOR) + .and_then(|v| v.to_str().ok()) + .and_then(|v| ForwardedHeaderValue::from_x_forwarded_for(v).ok()) + .and_then(|v| v.remotest_forwarded_for_ip()) + { + return Some(ip); + } + + if let Some(ip) = req + .headers() + .get(&X_REAL_IP) + .and_then(|v| v.to_str().ok()) + .and_then(|v| IpAddr::from_str(v).ok()) + { + return Some(ip); + } + + None +} + +#[cfg(test)] +mod tests { + use super::*; + use hyper::header::HeaderValue; + + fn request() -> hyper::Request { + hyper::Request::builder().body(hyper::Body::empty()).unwrap() + } + + #[test] + fn empty_works() { + let req = request(); + let host = get_proxy_ip(&req); + assert!(host.is_none()) + } + + #[test] + fn host_from_x_real_ip() { + let mut req = request(); + + req.headers_mut().insert(&X_REAL_IP, HeaderValue::from_static("127.0.0.1")); + let ip = get_proxy_ip(&req); + assert_eq!(Some(IpAddr::from_str("127.0.0.1").unwrap()), ip); + } + + #[test] + fn ip_from_forwarded_works() { + let mut req = request(); + + req.headers_mut().insert( + &FORWARDED, + HeaderValue::from_static("for=192.0.2.60;proto=http;by=203.0.113.43;host=example.com"), + ); + let ip = get_proxy_ip(&req); + assert_eq!(Some(IpAddr::from_str("192.0.2.60").unwrap()), ip); + } + + #[test] + fn ip_from_forwarded_multiple() { + let mut req = request(); + + req.headers_mut().append(&FORWARDED, HeaderValue::from_static("for=127.0.0.1")); + req.headers_mut().append(&FORWARDED, HeaderValue::from_static("for=192.0.2.60")); + req.headers_mut().append(&FORWARDED, HeaderValue::from_static("for=192.0.2.61")); + let ip = get_proxy_ip(&req); + assert_eq!(Some(IpAddr::from_str("127.0.0.1").unwrap()), ip); + } + + #[test] + fn ip_from_x_forwarded_works() { + let mut req = request(); + + req.headers_mut() + .insert(&X_FORWARDED_FOR, HeaderValue::from_static("127.0.0.1,192.0.2.60,0.0.0.1")); + let ip = get_proxy_ip(&req); + assert_eq!(Some(IpAddr::from_str("127.0.0.1").unwrap()), ip); + } +} diff --git a/substrate/client/rpc-spec-v2/Cargo.toml b/substrate/client/rpc-spec-v2/Cargo.toml index e2612d914542ecd74758fadaa9ac3dc4b01bc7c1..8977c842d03806c50372fc58452d5c35206ae163 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.22", features = ["client-core", "macros", "server"] } +jsonrpsee = { version = "0.22.5", features = ["client-core", "macros", "server-core"] } # Internal chain structures for "chain_spec". sc-chain-spec = { path = "../chain-spec" } # Pool for submitting extrinsics required by "transaction" @@ -30,7 +30,7 @@ sp-version = { path = "../../primitives/version" } sc-client-api = { path = "../api" } sc-utils = { path = "../utils" } sc-rpc = { path = "../rpc" } -codec = { package = "parity-scale-codec", version = "3.6.1" } +codec = { package = "parity-scale-codec", version = "3.6.12" } thiserror = { workspace = true } serde = { workspace = true, default-features = true } hex = "0.4" @@ -38,10 +38,11 @@ futures = "0.3.30" parking_lot = "0.12.1" tokio-stream = { version = "0.1.14", features = ["sync"] } tokio = { version = "1.22.0", features = ["sync"] } -array-bytes = "6.1" +array-bytes = "6.2.2" log = { workspace = true, default-features = true } futures-util = { version = "0.3.30", default-features = false } rand = "0.8.5" +schnellru = "0.2.1" [dev-dependencies] jsonrpsee = { version = "0.22", features = ["server", "ws-client"] } 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 3851adac2644d09b824383dba2e80d6877eff01a..23cb0bbf54585383e797a452d9747cac36649ad1 100644 --- a/substrate/client/rpc-spec-v2/src/chain_head/api.rs +++ b/substrate/client/rpc-spec-v2/src/chain_head/api.rs @@ -37,15 +37,15 @@ pub trait ChainHeadApi { /// /// This method is unstable and subject to change in the future. #[subscription( - name = "chainHead_unstable_follow" => "chainHead_unstable_followEvent", - unsubscribe = "chainHead_unstable_unfollow", + name = "chainHead_v1_follow" => "chainHead_v1_followEvent", + unsubscribe = "chainHead_v1_unfollow", item = FollowEvent, )] fn chain_head_unstable_follow(&self, with_runtime: bool); /// Retrieves the body (list of transactions) of a pinned block. /// - /// This method should be seen as a complement to `chainHead_unstable_follow`, + /// This method should be seen as a complement to `chainHead_v1_follow`, /// allowing the JSON-RPC client to retrieve more information about a block /// that has been reported. /// @@ -54,7 +54,7 @@ pub trait ChainHeadApi { /// # Unstable /// /// This method is unstable and subject to change in the future. - #[method(name = "chainHead_unstable_body", raw_method)] + #[method(name = "chainHead_v1_body", raw_method)] async fn chain_head_unstable_body( &self, follow_subscription: String, @@ -63,7 +63,7 @@ pub trait ChainHeadApi { /// Retrieves the header of a pinned block. /// - /// This method should be seen as a complement to `chainHead_unstable_follow`, + /// This method should be seen as a complement to `chainHead_v1_follow`, /// allowing the JSON-RPC client to retrieve more information about a block /// that has been reported. /// @@ -73,7 +73,7 @@ pub trait ChainHeadApi { /// # Unstable /// /// This method is unstable and subject to change in the future. - #[method(name = "chainHead_unstable_header", raw_method)] + #[method(name = "chainHead_v1_header", raw_method)] async fn chain_head_unstable_header( &self, follow_subscription: String, @@ -85,7 +85,7 @@ pub trait ChainHeadApi { /// # Unstable /// /// This method is unstable and subject to change in the future. - #[method(name = "chainHead_unstable_storage", raw_method)] + #[method(name = "chainHead_v1_storage", raw_method)] async fn chain_head_unstable_storage( &self, follow_subscription: String, @@ -99,7 +99,7 @@ pub trait ChainHeadApi { /// # Unstable /// /// This method is unstable and subject to change in the future. - #[method(name = "chainHead_unstable_call", raw_method)] + #[method(name = "chainHead_v1_call", raw_method)] async fn chain_head_unstable_call( &self, follow_subscription: String, @@ -118,7 +118,7 @@ pub trait ChainHeadApi { /// # Unstable /// /// This method is unstable and subject to change in the future. - #[method(name = "chainHead_unstable_unpin", raw_method)] + #[method(name = "chainHead_v1_unpin", raw_method)] async fn chain_head_unstable_unpin( &self, follow_subscription: String, @@ -131,21 +131,21 @@ pub trait ChainHeadApi { /// # Unstable /// /// This method is unstable and subject to change in the future. - #[method(name = "chainHead_unstable_continue", raw_method)] + #[method(name = "chainHead_v1_continue", raw_method)] async fn chain_head_unstable_continue( &self, follow_subscription: String, operation_id: String, ) -> Result<(), Error>; - /// Stops an operation started with chainHead_unstable_body, chainHead_unstable_call, or - /// chainHead_unstable_storage. If the operation was still in progress, this interrupts it. If + /// Stops an operation started with chainHead_v1_body, chainHead_v1_call, or + /// chainHead_v1_storage. If the operation was still in progress, this interrupts it. If /// the operation was already finished, this call has no effect. /// /// # Unstable /// /// This method is unstable and subject to change in the future. - #[method(name = "chainHead_unstable_stopOperation", raw_method)] + #[method(name = "chainHead_v1_stopOperation", raw_method)] async fn chain_head_unstable_stop_operation( &self, follow_subscription: String, 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 86d9a726d7bec371c157014adac0dfb1a926fb7e..6779180a414661eac923afca9a3917b340bc5487 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 @@ -75,7 +75,7 @@ pub struct ChainHeadConfig { /// Maximum pinned blocks across all connections. /// This number is large enough to consider immediate blocks. /// Note: This should never exceed the `PINNING_CACHE_SIZE` from client/db. -const MAX_PINNED_BLOCKS: usize = 512; +pub(crate) const MAX_PINNED_BLOCKS: usize = 512; /// Any block of any subscription should not be pinned more than /// this constant. When a subscription contains a block older than this, 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 0d87a45c07e295784bef4c946ef05d3641234ce4..a753896b24c238f949a8f4698ea7b4c63e39746f 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 @@ -19,7 +19,7 @@ //! Implementation of the `chainHead_follow` method. use crate::chain_head::{ - chain_head::LOG_TARGET, + chain_head::{LOG_TARGET, MAX_PINNED_BLOCKS}, event::{ BestBlockChanged, Finalized, FollowEvent, Initialized, NewBlock, RuntimeEvent, RuntimeVersionEvent, @@ -37,6 +37,7 @@ use sc_client_api::{ Backend, BlockBackend, BlockImportNotification, BlockchainEvents, FinalityNotification, }; use sc_rpc::utils::to_sub_message; +use schnellru::{ByLength, LruMap}; use sp_api::CallApiAt; use sp_blockchain::{ Backend as BlockChainBackend, Error as BlockChainError, HeaderBackend, HeaderMetadata, Info, @@ -68,7 +69,9 @@ pub struct ChainHeadFollower, Block: BlockT, Client> { /// Subscription ID. sub_id: String, /// The best reported block by this subscription. - best_block_cache: Option, + current_best_block: Option, + /// LRU cache of pruned blocks. + pruned_blocks: LruMap, /// Stop all subscriptions if the distance between the leaves and the current finalized /// block is larger than this value. max_lagging_distance: usize, @@ -90,7 +93,10 @@ impl, Block: BlockT, Client> ChainHeadFollower, - ) -> Result<(Vec>, HashSet), SubscriptionManagementError> - { + ) -> Result>, SubscriptionManagementError> { 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; + // These are the pruned blocks that we should not report again. + for pruned in init.pruned_forks { + self.pruned_blocks.insert(pruned, ()); + } let finalized_block_hash = startup_point.finalized_hash; let finalized_block_runtime = self.generate_runtime_event(finalized_block_hash, None); @@ -345,11 +353,11 @@ where let best_block_hash = startup_point.best_hash; if best_block_hash != finalized_block_hash { let best_block = FollowEvent::BestBlockChanged(BestBlockChanged { best_block_hash }); - self.best_block_cache = Some(best_block_hash); + self.current_best_block = Some(best_block_hash); finalized_block_descendants.push(best_block); }; - Ok((finalized_block_descendants, init.pruned_forks)) + Ok(finalized_block_descendants) } /// Generate the "NewBlock" event and potentially the "BestBlockChanged" event for the @@ -377,19 +385,19 @@ where let best_block_event = FollowEvent::BestBlockChanged(BestBlockChanged { best_block_hash: block_hash }); - match self.best_block_cache { + match self.current_best_block { Some(block_cache) => { // The RPC layer has not reported this block as best before. // Note: This handles the race with the finalized branch. if block_cache != block_hash { - self.best_block_cache = Some(block_hash); + self.current_best_block = Some(block_hash); vec![new_block, best_block_event] } else { vec![new_block] } }, None => { - self.best_block_cache = Some(block_hash); + self.current_best_block = Some(block_hash); vec![new_block, best_block_event] }, } @@ -458,7 +466,7 @@ where // When the node falls out of sync and then syncs up to the tip of the chain, it can // happen that we skip notifications. Then it is better to terminate the connection // instead of trying to send notifications for all missed blocks. - if let Some(best_block_hash) = self.best_block_cache { + if let Some(best_block_hash) = self.current_best_block { let ancestor = sp_blockchain::lowest_common_ancestor( &*self.client, *hash, @@ -481,13 +489,10 @@ where } /// Get all pruned block hashes from the provided stale heads. - /// - /// The result does not include hashes from `to_ignore`. fn get_pruned_hashes( - &self, + &mut self, stale_heads: &[Block::Hash], last_finalized: Block::Hash, - to_ignore: &mut HashSet, ) -> Result, SubscriptionManagementError> { let blockchain = self.backend.blockchain(); let mut pruned = Vec::new(); @@ -497,11 +502,13 @@ where // Collect only blocks that are not part of the canonical chain. pruned.extend(tree_route.enacted().iter().filter_map(|block| { - if !to_ignore.remove(&block.hash) { - Some(block.hash) - } else { - None + if self.pruned_blocks.get(&block.hash).is_some() { + // The block was already reported as pruned. + return None } + + self.pruned_blocks.insert(block.hash, ()); + Some(block.hash) })) } @@ -515,7 +522,6 @@ where fn handle_finalized_blocks( &mut self, notification: FinalityNotification, - to_ignore: &mut HashSet, startup_point: &StartupPoint, ) -> Result>, SubscriptionManagementError> { let last_finalized = notification.hash; @@ -536,25 +542,32 @@ where // Report all pruned blocks from the notification that are not // part of the fork we need to ignore. let pruned_block_hashes = - self.get_pruned_hashes(¬ification.stale_heads, last_finalized, to_ignore)?; + self.get_pruned_hashes(¬ification.stale_heads, last_finalized)?; let finalized_event = FollowEvent::Finalized(Finalized { finalized_block_hashes, pruned_block_hashes: pruned_block_hashes.clone(), }); - match self.best_block_cache { - Some(block_cache) => { - // If the best block wasn't pruned, we are done here. - if !pruned_block_hashes.iter().any(|hash| *hash == block_cache) { - events.push(finalized_event); - return Ok(events) - } - - // The best block is reported as pruned. Therefore, we need to signal a new - // best block event before submitting the finalized event. + if let Some(current_best_block) = self.current_best_block { + // The best reported block is in the pruned list. Report a new best block. + let is_in_pruned_list = + pruned_block_hashes.iter().any(|hash| *hash == current_best_block); + // The block is not the last finalized block. + // + // It can be either: + // - a descendant of the last finalized block + // - a block on a fork that will be pruned in the future. + // + // In those cases, we emit a new best block. + let is_not_last_finalized = current_best_block != last_finalized; + + if is_in_pruned_list || is_not_last_finalized { + // We need to generate a best block event. let best_block_hash = self.client.info().best_hash; - if best_block_hash == block_cache { + + // Defensive check against state missmatch. + if best_block_hash == current_best_block { // The client doest not have any new information about the best block. // The information from `.info()` is updated from the DB as the last // step of the finalization and it should be up to date. @@ -564,23 +577,18 @@ where "[follow][id={:?}] Client does not contain different best block", self.sub_id, ); - events.push(finalized_event); - Ok(events) } else { // The RPC needs to also submit a new best block changed before the // finalized event. - self.best_block_cache = Some(best_block_hash); - let best_block_event = - FollowEvent::BestBlockChanged(BestBlockChanged { best_block_hash }); - events.extend([best_block_event, finalized_event]); - Ok(events) + self.current_best_block = Some(best_block_hash); + events + .push(FollowEvent::BestBlockChanged(BestBlockChanged { best_block_hash })); } - }, - None => { - events.push(finalized_event); - Ok(events) - }, + } } + + events.push(finalized_event); + Ok(events) } /// Submit the events from the provided stream to the RPC client @@ -589,7 +597,6 @@ where &mut self, startup_point: &StartupPoint, mut stream: EventStream, - mut to_ignore: HashSet, sink: SubscriptionSink, rx_stop: oneshot::Receiver<()>, ) -> Result<(), SubscriptionManagementError> @@ -612,7 +619,7 @@ where NotificationType::NewBlock(notification) => self.handle_import_blocks(notification, &startup_point), NotificationType::Finalized(notification) => - self.handle_finalized_blocks(notification, &mut to_ignore, &startup_point), + self.handle_finalized_blocks(notification, &startup_point), NotificationType::MethodResponse(notification) => Ok(vec![notification]), }; @@ -682,7 +689,7 @@ where .map(|response| NotificationType::MethodResponse(response)); let startup_point = StartupPoint::from(self.client.info()); - let (initial_events, pruned_forks) = match self.generate_init_events(&startup_point) { + let initial_events = match self.generate_init_events(&startup_point) { Ok(blocks) => blocks, Err(err) => { debug!( @@ -702,7 +709,6 @@ where let merged = tokio_stream::StreamExt::merge(merged, stream_responses); let stream = stream::once(futures::future::ready(initial)).chain(merged); - self.submit_events(&startup_point, stream.boxed(), pruned_forks, sink, sub_data.rx_stop) - .await + self.submit_events(&startup_point, stream.boxed(), sink, sub_data.rx_stop).await } } 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 0e5ccb91d39a61a76a850119590699d563d88df8..a6edc344bc63fda4cb04caa21dfd20b2df8bd0ad 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 @@ -186,7 +186,7 @@ impl OperationState { /// Stops the operation if `waitingForContinue` event was emitted for the associated /// operation ID. /// - /// Returns nothing in accordance with `chainHead_unstable_stopOperation`. + /// Returns nothing in accordance with `chainHead_v1_stopOperation`. pub fn stop_operation(&self) { // `waitingForContinue` not generated. if !self.shared_state.requested_continue.load(std::sync::atomic::Ordering::Acquire) { @@ -864,7 +864,7 @@ mod tests { Arc>>, ) { let backend = Arc::new(sc_client_api::in_mem::Backend::new()); - let executor = substrate_test_runtime_client::new_native_or_wasm_executor(); + let executor = substrate_test_runtime_client::WasmExecutor::default(); let client_config = sc_service::ClientConfig::default(); let genesis_block_builder = sc_service::GenesisBlockBuilder::new( &substrate_test_runtime_client::GenesisParameters::default().genesis_storage(), 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 c2bff7c50d5ebd951596f15e9e7423a77b889c0b..b195e05b6649abb524c973b350b52833a34fd794 100644 --- a/substrate/client/rpc-spec-v2/src/chain_head/tests.rs +++ b/substrate/client/rpc-spec-v2/src/chain_head/tests.rs @@ -16,13 +16,12 @@ // You should have received a copy of the GNU General Public License // along with this program. If not, see . +use super::*; use crate::{ chain_head::{api::ChainHeadApiClient, event::MethodResponse, test_utils::ChainHeadMockClient}, common::events::{StorageQuery, StorageQueryType, StorageResultType}, hex_string, }; - -use super::*; use assert_matches::assert_matches; use codec::{Decode, Encode}; use futures::Future; @@ -32,7 +31,6 @@ use jsonrpsee::{ }, rpc_params, MethodsError as Error, RpcModule, }; - use sc_block_builder::BlockBuilderBuilder; use sc_client_api::ChildInfo; use sc_service::client::new_in_mem; @@ -156,7 +154,7 @@ async fn setup_api() -> ( ) .into_rpc(); - let mut sub = api.subscribe_unbounded("chainHead_unstable_follow", [true]).await.unwrap(); + let mut sub = api.subscribe_unbounded("chainHead_v1_follow", [true]).await.unwrap(); let sub_id = sub.subscription_id(); let sub_id = serde_json::to_string(&sub_id).unwrap(); @@ -187,6 +185,62 @@ async fn setup_api() -> ( (client, api, sub, sub_id, block) } +async fn import_block( + mut client: Arc>, + parent_hash: ::Hash, + parent_number: u64, +) -> Block { + let block = BlockBuilderBuilder::new(&*client) + .on_parent_block(parent_hash) + .with_parent_block_number(parent_number) + .build() + .unwrap() + .build() + .unwrap() + .block; + client.import(BlockOrigin::Own, block.clone()).await.unwrap(); + block +} + +async fn import_best_block_with_tx( + mut client: Arc>, + parent_hash: ::Hash, + parent_number: u64, + tx: Transfer, +) -> Block { + let mut block_builder = BlockBuilderBuilder::new(&*client) + .on_parent_block(parent_hash) + .with_parent_block_number(parent_number) + .build() + .unwrap(); + block_builder.push_transfer(tx).unwrap(); + let block = block_builder.build().unwrap().block; + client.import_as_best(BlockOrigin::Own, block.clone()).await.unwrap(); + block +} + +/// Check the subscription produces a new block and a best block event. +/// +/// The macro is used instead of a fn to preserve the lines of code in case of panics. +macro_rules! check_new_and_best_block_events { + ($sub:expr, $block_hash:expr, $parent_hash:expr) => { + let event: FollowEvent = get_next_event($sub).await; + let expected = FollowEvent::NewBlock(NewBlock { + block_hash: format!("{:?}", $block_hash), + parent_block_hash: format!("{:?}", $parent_hash), + new_runtime: None, + with_runtime: false, + }); + assert_eq!(event, expected); + + let event: FollowEvent = get_next_event($sub).await; + let expected = FollowEvent::BestBlockChanged(BestBlockChanged { + best_block_hash: format!("{:?}", $block_hash), + }); + assert_eq!(event, expected); + }; +} + #[tokio::test] async fn follow_subscription_produces_blocks() { let builder = TestClientBuilder::new(); @@ -210,7 +264,7 @@ async fn follow_subscription_produces_blocks() { .into_rpc(); let finalized_hash = client.info().finalized_hash; - let mut sub = api.subscribe_unbounded("chainHead_unstable_follow", [false]).await.unwrap(); + let mut sub = api.subscribe_unbounded("chainHead_v1_follow", [false]).await.unwrap(); // Initialized must always be reported first. let event: FollowEvent = get_next_event(&mut sub).await; @@ -281,7 +335,7 @@ async fn follow_with_runtime() { .into_rpc(); let finalized_hash = client.info().finalized_hash; - let mut sub = api.subscribe_unbounded("chainHead_unstable_follow", [true]).await.unwrap(); + let mut sub = api.subscribe_unbounded("chainHead_v1_follow", [true]).await.unwrap(); // Initialized must always be reported first. let event: FollowEvent = get_next_event(&mut sub).await; @@ -392,14 +446,14 @@ async fn get_header() { // Invalid subscription ID must produce no results. let res: Option = api - .call("chainHead_unstable_header", ["invalid_sub_id", &invalid_hash]) + .call("chainHead_v1_header", ["invalid_sub_id", &invalid_hash]) .await .unwrap(); assert!(res.is_none()); // Valid subscription with invalid block hash will error. let err = api - .call::<_, serde_json::Value>("chainHead_unstable_header", [&sub_id, &invalid_hash]) + .call::<_, serde_json::Value>("chainHead_v1_header", [&sub_id, &invalid_hash]) .await .unwrap_err(); assert_matches!(err, @@ -407,7 +461,7 @@ async fn get_header() { ); // Obtain the valid header. - let res: String = api.call("chainHead_unstable_header", [&sub_id, &block_hash]).await.unwrap(); + let res: String = api.call("chainHead_v1_header", [&sub_id, &block_hash]).await.unwrap(); let bytes = array_bytes::hex2bytes(&res).unwrap(); let header: Header = Decode::decode(&mut &bytes[..]).unwrap(); assert_eq!(header, block.header); @@ -420,15 +474,13 @@ async fn get_body() { let invalid_hash = hex_string(&INVALID_HASH); // Subscription ID is invalid. - let response: MethodResponse = api - .call("chainHead_unstable_body", ["invalid_sub_id", &invalid_hash]) - .await - .unwrap(); + let response: MethodResponse = + api.call("chainHead_v1_body", ["invalid_sub_id", &invalid_hash]).await.unwrap(); assert_matches!(response, MethodResponse::LimitReached); // Block hash is invalid. let err = api - .call::<_, serde_json::Value>("chainHead_unstable_body", [&sub_id, &invalid_hash]) + .call::<_, serde_json::Value>("chainHead_v1_body", [&sub_id, &invalid_hash]) .await .unwrap_err(); assert_matches!(err, @@ -437,7 +489,7 @@ async fn get_body() { // Valid call. let response: MethodResponse = - api.call("chainHead_unstable_body", [&sub_id, &block_hash]).await.unwrap(); + api.call("chainHead_v1_body", [&sub_id, &block_hash]).await.unwrap(); let operation_id = match response { MethodResponse::Started(started) => started.operation_id, MethodResponse::LimitReached => panic!("Expected started response"), @@ -478,7 +530,7 @@ async fn get_body() { // Valid call to a block with extrinsics. let response: MethodResponse = - api.call("chainHead_unstable_body", [&sub_id, &block_hash]).await.unwrap(); + api.call("chainHead_v1_body", [&sub_id, &block_hash]).await.unwrap(); let operation_id = match response { MethodResponse::Started(started) => started.operation_id, MethodResponse::LimitReached => panic!("Expected started response"), @@ -500,10 +552,7 @@ async fn call_runtime() { // Subscription ID is invalid. let response: MethodResponse = api - .call( - "chainHead_unstable_call", - ["invalid_sub_id", &block_hash, "BabeApi_current_epoch", "0x00"], - ) + .call("chainHead_v1_call", ["invalid_sub_id", &block_hash, "BabeApi_current_epoch", "0x00"]) .await .unwrap(); assert_matches!(response, MethodResponse::LimitReached); @@ -511,7 +560,7 @@ async fn call_runtime() { // Block hash is invalid. let err = api .call::<_, serde_json::Value>( - "chainHead_unstable_call", + "chainHead_v1_call", [&sub_id, &invalid_hash, "BabeApi_current_epoch", "0x00"], ) .await @@ -523,7 +572,7 @@ async fn call_runtime() { // Pass an invalid parameters that cannot be decode. let err = api .call::<_, serde_json::Value>( - "chainHead_unstable_call", + "chainHead_v1_call", // 0x0 is invalid. [&sub_id, &block_hash, "BabeApi_current_epoch", "0x0"], ) @@ -539,7 +588,7 @@ async fn call_runtime() { let call_parameters = hex_string(&alice_id.encode()); let response: MethodResponse = api .call( - "chainHead_unstable_call", + "chainHead_v1_call", [&sub_id, &block_hash, "AccountNonceApi_account_nonce", &call_parameters], ) .await @@ -558,7 +607,7 @@ async fn call_runtime() { // The `current_epoch` takes no parameters and not draining the input buffer // will cause the execution to fail. let response: MethodResponse = api - .call("chainHead_unstable_call", [&sub_id, &block_hash, "BabeApi_current_epoch", "0x00"]) + .call("chainHead_v1_call", [&sub_id, &block_hash, "BabeApi_current_epoch", "0x00"]) .await .unwrap(); let operation_id = match response { @@ -595,7 +644,7 @@ async fn call_runtime_without_flag() { ) .into_rpc(); - let mut sub = api.subscribe_unbounded("chainHead_unstable_follow", [false]).await.unwrap(); + let mut sub = api.subscribe_unbounded("chainHead_v1_follow", [false]).await.unwrap(); let sub_id = sub.subscription_id(); let sub_id = serde_json::to_string(&sub_id).unwrap(); @@ -629,7 +678,7 @@ async fn call_runtime_without_flag() { let call_parameters = hex_string(&alice_id.encode()); let err = api .call::<_, serde_json::Value>( - "chainHead_unstable_call", + "chainHead_v1_call", [&sub_id, &block_hash, "AccountNonceApi_account_nonce", &call_parameters], ) .await @@ -650,7 +699,7 @@ async fn get_storage_hash() { // Subscription ID is invalid. let response: MethodResponse = api .call( - "chainHead_unstable_storage", + "chainHead_v1_storage", rpc_params![ "invalid_sub_id", &invalid_hash, @@ -664,7 +713,7 @@ async fn get_storage_hash() { // Block hash is invalid. let err = api .call::<_, serde_json::Value>( - "chainHead_unstable_storage", + "chainHead_v1_storage", rpc_params![ &sub_id, &invalid_hash, @@ -680,7 +729,7 @@ async fn get_storage_hash() { // Valid call without storage at the key. let response: MethodResponse = api .call( - "chainHead_unstable_storage", + "chainHead_v1_storage", rpc_params![ &sub_id, &block_hash, @@ -723,7 +772,7 @@ async fn get_storage_hash() { // Valid call with storage at the key. let response: MethodResponse = api .call( - "chainHead_unstable_storage", + "chainHead_v1_storage", rpc_params![ &sub_id, &block_hash, @@ -756,7 +805,7 @@ async fn get_storage_hash() { // Valid call with storage at the key. let response: MethodResponse = api .call( - "chainHead_unstable_storage", + "chainHead_v1_storage", rpc_params![ &sub_id, &genesis_hash, @@ -813,7 +862,7 @@ async fn get_storage_multi_query_iter() { // Valid call with storage at the key. let response: MethodResponse = api .call( - "chainHead_unstable_storage", + "chainHead_v1_storage", rpc_params![ &sub_id, &block_hash, @@ -864,7 +913,7 @@ async fn get_storage_multi_query_iter() { let expected_value = hex_string(&CHILD_VALUE); let response: MethodResponse = api .call( - "chainHead_unstable_storage", + "chainHead_v1_storage", rpc_params![ &sub_id, &genesis_hash, @@ -918,7 +967,7 @@ async fn get_storage_value() { // Subscription ID is invalid. let response: MethodResponse = api .call( - "chainHead_unstable_storage", + "chainHead_v1_storage", rpc_params![ "invalid_sub_id", &invalid_hash, @@ -932,7 +981,7 @@ async fn get_storage_value() { // Block hash is invalid. let err = api .call::<_, serde_json::Value>( - "chainHead_unstable_storage", + "chainHead_v1_storage", rpc_params![ &sub_id, &invalid_hash, @@ -948,7 +997,7 @@ async fn get_storage_value() { // Valid call without storage at the key. let response: MethodResponse = api .call( - "chainHead_unstable_storage", + "chainHead_v1_storage", rpc_params![ &sub_id, &block_hash, @@ -991,7 +1040,7 @@ async fn get_storage_value() { // Valid call with storage at the key. let response: MethodResponse = api .call( - "chainHead_unstable_storage", + "chainHead_v1_storage", rpc_params![ &sub_id, &block_hash, @@ -1023,7 +1072,7 @@ async fn get_storage_value() { let response: MethodResponse = api .call( - "chainHead_unstable_storage", + "chainHead_v1_storage", rpc_params![ &sub_id, &genesis_hash, @@ -1065,7 +1114,7 @@ async fn get_storage_non_queryable_key() { let response: MethodResponse = api .call( - "chainHead_unstable_storage", + "chainHead_v1_storage", rpc_params![ &sub_id, &block_hash, @@ -1090,7 +1139,7 @@ async fn get_storage_non_queryable_key() { let prefixed_key = hex_string(&prefixed_key); let response: MethodResponse = api .call( - "chainHead_unstable_storage", + "chainHead_v1_storage", rpc_params![ &sub_id, &block_hash, @@ -1115,7 +1164,7 @@ async fn get_storage_non_queryable_key() { let prefixed_key = hex_string(&prefixed_key); let response: MethodResponse = api .call( - "chainHead_unstable_storage", + "chainHead_v1_storage", rpc_params![ &sub_id, &block_hash, @@ -1141,7 +1190,7 @@ async fn get_storage_non_queryable_key() { let prefixed_key = hex_string(&prefixed_key); let response: MethodResponse = api .call( - "chainHead_unstable_storage", + "chainHead_v1_storage", rpc_params![ &sub_id, &block_hash, @@ -1171,9 +1220,9 @@ async fn unique_operation_ids() { // Ensure that operation IDs are unique for multiple method calls. for _ in 0..5 { - // Valid `chainHead_unstable_body` call. + // Valid `chainHead_v1_body` call. let response: MethodResponse = - api.call("chainHead_unstable_body", [&sub_id, &block_hash]).await.unwrap(); + api.call("chainHead_v1_body", [&sub_id, &block_hash]).await.unwrap(); let operation_id = match response { MethodResponse::Started(started) => started.operation_id, MethodResponse::LimitReached => panic!("Expected started response"), @@ -1185,11 +1234,11 @@ async fn unique_operation_ids() { // Ensure uniqueness. assert!(op_ids.insert(operation_id)); - // Valid `chainHead_unstable_storage` call. + // Valid `chainHead_v1_storage` call. let key = hex_string(&KEY); let response: MethodResponse = api .call( - "chainHead_unstable_storage", + "chainHead_v1_storage", rpc_params![ &sub_id, &block_hash, @@ -1210,12 +1259,12 @@ async fn unique_operation_ids() { // Ensure uniqueness. assert!(op_ids.insert(operation_id)); - // Valid `chainHead_unstable_call` call. + // Valid `chainHead_v1_call` call. let alice_id = AccountKeyring::Alice.to_account_id(); let call_parameters = hex_string(&alice_id.encode()); let response: MethodResponse = api .call( - "chainHead_unstable_call", + "chainHead_v1_call", [&sub_id, &block_hash, "AccountNonceApi_account_nonce", &call_parameters], ) .await @@ -1257,12 +1306,11 @@ async fn separate_operation_ids_for_subscriptions() { .into_rpc(); // Create two separate subscriptions. - let mut sub_first = api.subscribe_unbounded("chainHead_unstable_follow", [true]).await.unwrap(); + let mut sub_first = api.subscribe_unbounded("chainHead_v1_follow", [true]).await.unwrap(); let sub_id_first = sub_first.subscription_id(); let sub_id_first = serde_json::to_string(&sub_id_first).unwrap(); - let mut sub_second = - api.subscribe_unbounded("chainHead_unstable_follow", [true]).await.unwrap(); + let mut sub_second = api.subscribe_unbounded("chainHead_v1_follow", [true]).await.unwrap(); let sub_id_second = sub_second.subscription_id(); let sub_id_second = serde_json::to_string(&sub_id_second).unwrap(); @@ -1306,17 +1354,15 @@ async fn separate_operation_ids_for_subscriptions() { // Each `chainHead_follow` subscription receives a separate operation ID. let response: MethodResponse = - api.call("chainHead_unstable_body", [&sub_id_first, &block_hash]).await.unwrap(); + api.call("chainHead_v1_body", [&sub_id_first, &block_hash]).await.unwrap(); let operation_id: String = match response { MethodResponse::Started(started) => started.operation_id, MethodResponse::LimitReached => panic!("Expected started response"), }; assert_eq!(operation_id, "0"); - let response: MethodResponse = api - .call("chainHead_unstable_body", [&sub_id_second, &block_hash]) - .await - .unwrap(); + let response: MethodResponse = + api.call("chainHead_v1_body", [&sub_id_second, &block_hash]).await.unwrap(); let operation_id_second: String = match response { MethodResponse::Started(started) => started.operation_id, MethodResponse::LimitReached => panic!("Expected started response"), @@ -1393,7 +1439,7 @@ async fn follow_generates_initial_blocks() { let block_2_f_hash = block_2_f.header.hash(); client.import(BlockOrigin::Own, block_2_f.clone()).await.unwrap(); - let mut sub = api.subscribe_unbounded("chainHead_unstable_follow", [false]).await.unwrap(); + let mut sub = api.subscribe_unbounded("chainHead_v1_follow", [false]).await.unwrap(); // Initialized must always be reported first. let event: FollowEvent = get_next_event(&mut sub).await; @@ -1505,7 +1551,7 @@ async fn follow_exceeding_pinned_blocks() { ) .into_rpc(); - let mut sub = api.subscribe_unbounded("chainHead_unstable_follow", [false]).await.unwrap(); + let mut sub = api.subscribe_unbounded("chainHead_v1_follow", [false]).await.unwrap(); let block = BlockBuilderBuilder::new(&*client) .on_parent_block(client.chain_info().genesis_hash) @@ -1584,7 +1630,7 @@ async fn follow_with_unpin() { ) .into_rpc(); - let mut sub = api.subscribe_unbounded("chainHead_unstable_follow", [false]).await.unwrap(); + let mut sub = api.subscribe_unbounded("chainHead_v1_follow", [false]).await.unwrap(); let sub_id = sub.subscription_id(); let sub_id = serde_json::to_string(&sub_id).unwrap(); @@ -1616,17 +1662,14 @@ async fn follow_with_unpin() { // Unpin an invalid subscription ID must return Ok(()). let invalid_hash = hex_string(&INVALID_HASH); let _res: () = api - .call("chainHead_unstable_unpin", rpc_params!["invalid_sub_id", &invalid_hash]) + .call("chainHead_v1_unpin", rpc_params!["invalid_sub_id", &invalid_hash]) .await .unwrap(); // Valid subscription with invalid block hash. let invalid_hash = hex_string(&INVALID_HASH); let err = api - .call::<_, serde_json::Value>( - "chainHead_unstable_unpin", - rpc_params![&sub_id, &invalid_hash], - ) + .call::<_, serde_json::Value>("chainHead_v1_unpin", rpc_params![&sub_id, &invalid_hash]) .await .unwrap_err(); assert_matches!(err, @@ -1634,10 +1677,7 @@ async fn follow_with_unpin() { ); // To not exceed the number of pinned blocks, we need to unpin before the next import. - let _res: () = api - .call("chainHead_unstable_unpin", rpc_params![&sub_id, &block_hash]) - .await - .unwrap(); + let _res: () = api.call("chainHead_v1_unpin", rpc_params![&sub_id, &block_hash]).await.unwrap(); // Block tree: // finalized_block -> block -> block2 @@ -1698,7 +1738,7 @@ async fn unpin_duplicate_hashes() { ) .into_rpc(); - let mut sub = api.subscribe_unbounded("chainHead_unstable_follow", [false]).await.unwrap(); + let mut sub = api.subscribe_unbounded("chainHead_v1_follow", [false]).await.unwrap(); let sub_id = sub.subscription_id(); let sub_id = serde_json::to_string(&sub_id).unwrap(); @@ -1730,7 +1770,7 @@ async fn unpin_duplicate_hashes() { // Try to unpin duplicate hashes. let err = api .call::<_, serde_json::Value>( - "chainHead_unstable_unpin", + "chainHead_v1_unpin", rpc_params![&sub_id, vec![&block_hash, &block_hash]], ) .await @@ -1765,7 +1805,7 @@ async fn unpin_duplicate_hashes() { // Try to unpin duplicate hashes. let err = api .call::<_, serde_json::Value>( - "chainHead_unstable_unpin", + "chainHead_v1_unpin", rpc_params![&sub_id, vec![&block_hash, &block_hash_2, &block_hash]], ) .await @@ -1776,7 +1816,7 @@ async fn unpin_duplicate_hashes() { // Can unpin blocks. let _res: () = api - .call("chainHead_unstable_unpin", rpc_params![&sub_id, vec![&block_hash, &block_hash_2]]) + .call("chainHead_v1_unpin", rpc_params![&sub_id, vec![&block_hash, &block_hash_2]]) .await .unwrap(); } @@ -1803,7 +1843,7 @@ async fn follow_with_multiple_unpin_hashes() { ) .into_rpc(); - let mut sub = api.subscribe_unbounded("chainHead_unstable_follow", [false]).await.unwrap(); + let mut sub = api.subscribe_unbounded("chainHead_v1_follow", [false]).await.unwrap(); let sub_id = sub.subscription_id(); let sub_id = serde_json::to_string(&sub_id).unwrap(); @@ -1874,16 +1914,13 @@ async fn follow_with_multiple_unpin_hashes() { // Unpin an invalid subscription ID must return Ok(()). let invalid_hash = hex_string(&INVALID_HASH); let _res: () = api - .call("chainHead_unstable_unpin", rpc_params!["invalid_sub_id", &invalid_hash]) + .call("chainHead_v1_unpin", rpc_params!["invalid_sub_id", &invalid_hash]) .await .unwrap(); // Valid subscription with invalid block hash. let err = api - .call::<_, serde_json::Value>( - "chainHead_unstable_unpin", - rpc_params![&sub_id, &invalid_hash], - ) + .call::<_, serde_json::Value>("chainHead_v1_unpin", rpc_params![&sub_id, &invalid_hash]) .await .unwrap_err(); assert_matches!(err, @@ -1891,14 +1928,14 @@ async fn follow_with_multiple_unpin_hashes() { ); let _res: () = api - .call("chainHead_unstable_unpin", rpc_params![&sub_id, &block_1_hash]) + .call("chainHead_v1_unpin", rpc_params![&sub_id, &block_1_hash]) .await .unwrap(); // One block hash is invalid. Block 1 is already unpinned. let err = api .call::<_, serde_json::Value>( - "chainHead_unstable_unpin", + "chainHead_v1_unpin", rpc_params![&sub_id, vec![&block_1_hash, &block_2_hash, &block_3_hash]], ) .await @@ -1909,16 +1946,13 @@ async fn follow_with_multiple_unpin_hashes() { // Unpin multiple blocks. let _res: () = api - .call("chainHead_unstable_unpin", rpc_params![&sub_id, vec![&block_2_hash, &block_3_hash]]) + .call("chainHead_v1_unpin", rpc_params![&sub_id, vec![&block_2_hash, &block_3_hash]]) .await .unwrap(); // Check block 2 and 3 are unpinned. let err = api - .call::<_, serde_json::Value>( - "chainHead_unstable_unpin", - rpc_params![&sub_id, &block_2_hash], - ) + .call::<_, serde_json::Value>("chainHead_v1_unpin", rpc_params![&sub_id, &block_2_hash]) .await .unwrap_err(); assert_matches!(err, @@ -1926,10 +1960,7 @@ async fn follow_with_multiple_unpin_hashes() { ); let err = api - .call::<_, serde_json::Value>( - "chainHead_unstable_unpin", - rpc_params![&sub_id, &block_3_hash], - ) + .call::<_, serde_json::Value>("chainHead_v1_unpin", rpc_params![&sub_id, &block_3_hash]) .await .unwrap_err(); assert_matches!(err, @@ -1960,7 +1991,7 @@ async fn follow_prune_best_block() { .into_rpc(); let finalized_hash = client.info().finalized_hash; - let mut sub = api.subscribe_unbounded("chainHead_unstable_follow", [false]).await.unwrap(); + let mut sub = api.subscribe_unbounded("chainHead_v1_follow", [false]).await.unwrap(); // Initialized must always be reported first. let event: FollowEvent = get_next_event(&mut sub).await; @@ -2122,7 +2153,7 @@ async fn follow_prune_best_block() { let sub_id = sub.subscription_id(); let sub_id = serde_json::to_string(&sub_id).unwrap(); let hash = format!("{:?}", block_2_hash); - let _res: () = api.call("chainHead_unstable_unpin", rpc_params![&sub_id, &hash]).await.unwrap(); + let _res: () = api.call("chainHead_v1_unpin", rpc_params![&sub_id, &hash]).await.unwrap(); } #[tokio::test] @@ -2226,7 +2257,7 @@ async fn follow_forks_pruned_block() { // Block 2_f and 3_f are not pruned, pruning happens at height (N - 1). client.finalize_block(block_3_hash, None).unwrap(); - let mut sub = api.subscribe_unbounded("chainHead_unstable_follow", [false]).await.unwrap(); + let mut sub = api.subscribe_unbounded("chainHead_v1_follow", [false]).await.unwrap(); // Initialized must always be reported first. let event: FollowEvent = get_next_event(&mut sub).await; @@ -2388,7 +2419,7 @@ async fn follow_report_multiple_pruned_block() { let block_3_f = block_builder.build().unwrap().block; let block_3_f_hash = block_3_f.hash(); client.import(BlockOrigin::Own, block_3_f.clone()).await.unwrap(); - let mut sub = api.subscribe_unbounded("chainHead_unstable_follow", [false]).await.unwrap(); + let mut sub = api.subscribe_unbounded("chainHead_v1_follow", [false]).await.unwrap(); // Initialized must always be reported first. let event: FollowEvent = get_next_event(&mut sub).await; @@ -2456,6 +2487,7 @@ async fn follow_report_multiple_pruned_block() { client.finalize_block(block_3_hash, None).unwrap(); // Finalizing block 3 directly will also result in block 1 and 2 being finalized. + // It will also mark block 2 and block 3 from the fork as pruned. let event: FollowEvent = get_next_event(&mut sub).await; let expected = FollowEvent::Finalized(Finalized { finalized_block_hashes: vec![ @@ -2463,7 +2495,7 @@ async fn follow_report_multiple_pruned_block() { format!("{:?}", block_2_hash), format!("{:?}", block_3_hash), ], - pruned_block_hashes: vec![], + pruned_block_hashes: vec![format!("{:?}", block_2_f_hash), format!("{:?}", block_3_f_hash)], }); assert_eq!(event, expected); @@ -2473,7 +2505,6 @@ async fn follow_report_multiple_pruned_block() { // ^^^ finalized // -> block 1 -> block 2_f -> block 3_f // - // Mark block 4 as finalized to force block 2_f and 3_f to get pruned. let block_4 = BlockBuilderBuilder::new(&*client) .on_parent_block(block_3.hash()) @@ -2504,11 +2535,11 @@ async fn follow_report_multiple_pruned_block() { }); assert_eq!(event, expected); - // Block 4 and 5 be reported as pruned, not just the stale head (block 5). + // Blocks from the fork were pruned earlier. let event: FollowEvent = get_next_event(&mut sub).await; let expected = FollowEvent::Finalized(Finalized { finalized_block_hashes: vec![format!("{:?}", block_4_hash)], - pruned_block_hashes: vec![format!("{:?}", block_2_f_hash), format!("{:?}", block_3_f_hash)], + pruned_block_hashes: vec![], }); assert_eq!(event, expected); } @@ -2517,7 +2548,7 @@ async fn follow_report_multiple_pruned_block() { async fn pin_block_references() { // Manually construct an in-memory backend and client. let backend = Arc::new(sc_client_api::in_mem::Backend::new()); - let executor = substrate_test_runtime_client::new_native_or_wasm_executor(); + let executor = substrate_test_runtime_client::WasmExecutor::default(); let client_config = sc_service::ClientConfig::default(); let genesis_block_builder = sc_service::GenesisBlockBuilder::new( @@ -2574,7 +2605,7 @@ async fn pin_block_references() { } } - let mut sub = api.subscribe_unbounded("chainHead_unstable_follow", [false]).await.unwrap(); + let mut sub = api.subscribe_unbounded("chainHead_v1_follow", [false]).await.unwrap(); let sub_id = sub.subscription_id(); let sub_id = serde_json::to_string(&sub_id).unwrap(); @@ -2613,10 +2644,7 @@ async fn pin_block_references() { wait_pinned_references(&backend, &hash, 1).await; // To not exceed the number of pinned blocks, we need to unpin before the next import. - let _res: () = api - .call("chainHead_unstable_unpin", rpc_params![&sub_id, &block_hash]) - .await - .unwrap(); + let _res: () = api.call("chainHead_v1_unpin", rpc_params![&sub_id, &block_hash]).await.unwrap(); // Make sure unpin clears out the reference. let refs = backend.pin_refs(&hash).unwrap(); @@ -2709,7 +2737,7 @@ async fn follow_finalized_before_new_block() { let block_1_hash = block_1.header.hash(); client.import(BlockOrigin::Own, block_1.clone()).await.unwrap(); - let mut sub = api.subscribe_unbounded("chainHead_unstable_follow", [false]).await.unwrap(); + let mut sub = api.subscribe_unbounded("chainHead_v1_follow", [false]).await.unwrap(); // Trigger the `FinalizedNotification` for block 1 before the `BlockImportNotification`, and // expect for the `chainHead` to generate `NewBlock`, `BestBlock` and `Finalized` events. @@ -2814,7 +2842,7 @@ async fn ensure_operation_limits_works() { ) .into_rpc(); - let mut sub = api.subscribe_unbounded("chainHead_unstable_follow", [true]).await.unwrap(); + let mut sub = api.subscribe_unbounded("chainHead_v1_follow", [true]).await.unwrap(); let sub_id = sub.subscription_id(); let sub_id = serde_json::to_string(&sub_id).unwrap(); @@ -2853,7 +2881,7 @@ async fn ensure_operation_limits_works() { ]; let response: MethodResponse = api - .call("chainHead_unstable_storage", rpc_params![&sub_id, &block_hash, items]) + .call("chainHead_v1_storage", rpc_params![&sub_id, &block_hash, items]) .await .unwrap(); let operation_id = match response { @@ -2876,7 +2904,7 @@ async fn ensure_operation_limits_works() { let call_parameters = hex_string(&alice_id.encode()); let response: MethodResponse = api .call( - "chainHead_unstable_call", + "chainHead_v1_call", [&sub_id, &block_hash, "AccountNonceApi_account_nonce", &call_parameters], ) .await @@ -2921,7 +2949,7 @@ async fn check_continue_operation() { ) .into_rpc(); - let mut sub = api.subscribe_unbounded("chainHead_unstable_follow", [true]).await.unwrap(); + let mut sub = api.subscribe_unbounded("chainHead_v1_follow", [true]).await.unwrap(); let sub_id = sub.subscription_id(); let sub_id = serde_json::to_string(&sub_id).unwrap(); @@ -2958,17 +2986,17 @@ async fn check_continue_operation() { // Invalid subscription ID must produce no results. let _res: () = api - .call("chainHead_unstable_continue", ["invalid_sub_id", &invalid_hash]) + .call("chainHead_v1_continue", ["invalid_sub_id", &invalid_hash]) .await .unwrap(); // Invalid operation ID must produce no results. - let _res: () = api.call("chainHead_unstable_continue", [&sub_id, &invalid_hash]).await.unwrap(); + let _res: () = api.call("chainHead_v1_continue", [&sub_id, &invalid_hash]).await.unwrap(); // Valid call with storage at the key. let response: MethodResponse = api .call( - "chainHead_unstable_storage", + "chainHead_v1_storage", rpc_params![ &sub_id, &block_hash, @@ -3004,7 +3032,7 @@ async fn check_continue_operation() { std::time::Duration::from_secs(DOES_NOT_PRODUCE_EVENTS_SECONDS), ) .await; - let _res: () = api.call("chainHead_unstable_continue", [&sub_id, &operation_id]).await.unwrap(); + let _res: () = api.call("chainHead_v1_continue", [&sub_id, &operation_id]).await.unwrap(); assert_matches!( get_next_event::>(&mut sub).await, FollowEvent::OperationStorageItems(res) if res.operation_id == operation_id && @@ -3023,7 +3051,7 @@ async fn check_continue_operation() { std::time::Duration::from_secs(DOES_NOT_PRODUCE_EVENTS_SECONDS), ) .await; - let _res: () = api.call("chainHead_unstable_continue", [&sub_id, &operation_id]).await.unwrap(); + let _res: () = api.call("chainHead_v1_continue", [&sub_id, &operation_id]).await.unwrap(); assert_matches!( get_next_event::>(&mut sub).await, FollowEvent::OperationStorageItems(res) if res.operation_id == operation_id && @@ -3043,7 +3071,7 @@ async fn check_continue_operation() { std::time::Duration::from_secs(DOES_NOT_PRODUCE_EVENTS_SECONDS), ) .await; - let _res: () = api.call("chainHead_unstable_continue", [&sub_id, &operation_id]).await.unwrap(); + let _res: () = api.call("chainHead_v1_continue", [&sub_id, &operation_id]).await.unwrap(); assert_matches!( get_next_event::>(&mut sub).await, FollowEvent::OperationStorageItems(res) if res.operation_id == operation_id && @@ -3062,7 +3090,7 @@ async fn check_continue_operation() { std::time::Duration::from_secs(DOES_NOT_PRODUCE_EVENTS_SECONDS), ) .await; - let _res: () = api.call("chainHead_unstable_continue", [&sub_id, &operation_id]).await.unwrap(); + let _res: () = api.call("chainHead_v1_continue", [&sub_id, &operation_id]).await.unwrap(); assert_matches!( get_next_event::>(&mut sub).await, FollowEvent::OperationStorageItems(res) if res.operation_id == operation_id && @@ -3106,7 +3134,7 @@ async fn stop_storage_operation() { ) .into_rpc(); - let mut sub = api.subscribe_unbounded("chainHead_unstable_follow", [true]).await.unwrap(); + let mut sub = api.subscribe_unbounded("chainHead_v1_follow", [true]).await.unwrap(); let sub_id = sub.subscription_id(); let sub_id = serde_json::to_string(&sub_id).unwrap(); @@ -3140,20 +3168,17 @@ async fn stop_storage_operation() { // Invalid subscription ID must produce no results. let _res: () = api - .call("chainHead_unstable_stopOperation", ["invalid_sub_id", &invalid_hash]) + .call("chainHead_v1_stopOperation", ["invalid_sub_id", &invalid_hash]) .await .unwrap(); // Invalid operation ID must produce no results. - let _res: () = api - .call("chainHead_unstable_stopOperation", [&sub_id, &invalid_hash]) - .await - .unwrap(); + let _res: () = api.call("chainHead_v1_stopOperation", [&sub_id, &invalid_hash]).await.unwrap(); // Valid call with storage at the key. let response: MethodResponse = api .call( - "chainHead_unstable_storage", + "chainHead_v1_storage", rpc_params![ &sub_id, &block_hash, @@ -3185,10 +3210,7 @@ async fn stop_storage_operation() { ); // Stop the operation. - let _res: () = api - .call("chainHead_unstable_stopOperation", [&sub_id, &operation_id]) - .await - .unwrap(); + let _res: () = api.call("chainHead_v1_stopOperation", [&sub_id, &operation_id]).await.unwrap(); does_not_produce_event::>( &mut sub, @@ -3216,7 +3238,7 @@ async fn storage_closest_merkle_value() { // Valid call with storage at the keys. let response: MethodResponse = api .call( - "chainHead_unstable_storage", + "chainHead_v1_storage", rpc_params![ &sub_id, &block_hash, @@ -3410,7 +3432,7 @@ async fn chain_head_stop_all_subscriptions() { ) .into_rpc(); - let mut sub = api.subscribe_unbounded("chainHead_unstable_follow", [true]).await.unwrap(); + let mut sub = api.subscribe_unbounded("chainHead_v1_follow", [true]).await.unwrap(); // Ensure the imported block is propagated and pinned for this subscription. assert_matches!( @@ -3444,8 +3466,7 @@ async fn chain_head_stop_all_subscriptions() { ); } - let mut second_sub = - api.subscribe_unbounded("chainHead_unstable_follow", [true]).await.unwrap(); + let mut second_sub = api.subscribe_unbounded("chainHead_v1_follow", [true]).await.unwrap(); // Lagging detected, the stop event is delivered immediately. assert_matches!( get_next_event::>(&mut second_sub).await, @@ -3456,14 +3477,14 @@ async fn chain_head_stop_all_subscriptions() { assert_matches!(get_next_event::>(&mut sub).await, FollowEvent::Stop); // Other subscriptions cannot be started until the suspension period is over. - let mut sub = api.subscribe_unbounded("chainHead_unstable_follow", [true]).await.unwrap(); + let mut sub = api.subscribe_unbounded("chainHead_v1_follow", [true]).await.unwrap(); // Should receive the stop event immediately. assert_matches!(get_next_event::>(&mut sub).await, FollowEvent::Stop); // For the next subscription, lagging distance must be smaller. client.finalize_block(parent_hash, None).unwrap(); - let mut sub = api.subscribe_unbounded("chainHead_unstable_follow", [true]).await.unwrap(); + let mut sub = api.subscribe_unbounded("chainHead_v1_follow", [true]).await.unwrap(); assert_matches!( get_next_event::>(&mut sub).await, FollowEvent::Initialized(_) @@ -3625,12 +3646,12 @@ async fn chain_head_limit_reached() { ) .into_rpc(); - let mut sub = api.subscribe_unbounded("chainHead_unstable_follow", [true]).await.unwrap(); + let mut sub = api.subscribe_unbounded("chainHead_v1_follow", [true]).await.unwrap(); // Initialized must always be reported first. let _event: FollowEvent = get_next_event(&mut sub).await; - let error = api.subscribe_unbounded("chainHead_unstable_follow", [true]).await.unwrap_err(); + let error = api.subscribe_unbounded("chainHead_v1_follow", [true]).await.unwrap_err(); assert!(error .to_string() .contains("Maximum number of chainHead_follow has been reached")); @@ -3640,7 +3661,175 @@ async fn chain_head_limit_reached() { // Ensure the `chainHead_unfollow` is propagated to the server. tokio::time::sleep(std::time::Duration::from_secs(5)).await; - let mut sub = api.subscribe_unbounded("chainHead_unstable_follow", [true]).await.unwrap(); + let mut sub = api.subscribe_unbounded("chainHead_v1_follow", [true]).await.unwrap(); // Initialized must always be reported first. let _event: FollowEvent = get_next_event(&mut sub).await; } + +#[tokio::test] +async fn follow_unique_pruned_blocks() { + let builder = TestClientBuilder::new(); + let backend = builder.backend(); + let client = Arc::new(builder.build()); + + let api = ChainHead::new( + client.clone(), + backend, + Arc::new(TaskExecutor::default()), + ChainHeadConfig { + global_max_pinned_blocks: MAX_PINNED_BLOCKS, + subscription_max_pinned_duration: Duration::from_secs(MAX_PINNED_SECS), + subscription_max_ongoing_operations: MAX_OPERATIONS, + operation_max_storage_items: MAX_PAGINATION_LIMIT, + max_follow_subscriptions_per_connection: MAX_FOLLOW_SUBSCRIPTIONS_PER_CONNECTION, + max_lagging_distance: MAX_LAGGING_DISTANCE, + }, + ) + .into_rpc(); + + let finalized_hash = client.info().finalized_hash; + let mut sub = api.subscribe_unbounded("chainHead_v1_follow", [false]).await.unwrap(); + + // Initialized must always be reported first. + let event: FollowEvent = get_next_event(&mut sub).await; + let expected = FollowEvent::Initialized(Initialized { + finalized_block_hashes: vec![format!("{:?}", finalized_hash)], + finalized_block_runtime: None, + with_runtime: false, + }); + assert_eq!(event, expected); + + // Block tree: + // + // finalized -> block 1 -> block 2 -> block 3 + // + // -> block 2 -> block 4 -> block 5 + // + // -> block 1 -> block 2_f -> block 6 + // ^^^ finalized + // -> block 7 + // ^^^ finalized + // -> block 8 + // ^^^ finalized + // The chainHead will see block 5 as the best block. However, the + // client will finalize the block 6, which is on another fork. + // + // When the block 6 is finalized all blocks from the stale forks (2, 3, 4, 5) are pruned. + // + + // Initial setup steps: + let block_1_hash = + import_block(client.clone(), client.chain_info().genesis_hash, 0).await.hash(); + let block_2_f_hash = import_block(client.clone(), block_1_hash, 1).await.hash(); + let block_6_hash = import_block(client.clone(), block_2_f_hash, 2).await.hash(); + // Import block 2 as best on the fork. + let mut tx_alice_ferdie = Transfer { + from: AccountKeyring::Alice.into(), + to: AccountKeyring::Ferdie.into(), + amount: 41, + nonce: 0, + }; + let block_2_hash = + import_best_block_with_tx(client.clone(), block_1_hash, 1, tx_alice_ferdie.clone()) + .await + .hash(); + + let block_3_hash = import_block(client.clone(), block_2_hash, 2).await.hash(); + // Fork block 4. + tx_alice_ferdie.nonce = 1; + let block_4_hash = import_best_block_with_tx(client.clone(), block_2_hash, 2, tx_alice_ferdie) + .await + .hash(); + let block_5_hash = import_block(client.clone(), block_4_hash, 3).await.hash(); + + // Check expected events generated by the setup. + { + // Check block 1 -> block 2f -> block 6. + check_new_and_best_block_events!(&mut sub, block_1_hash, finalized_hash); + check_new_and_best_block_events!(&mut sub, block_2_f_hash, block_1_hash); + check_new_and_best_block_events!(&mut sub, block_6_hash, block_2_f_hash); + + // Check (block 1 ->) block 2 -> block 3. + check_new_and_best_block_events!(&mut sub, block_2_hash, block_1_hash); + check_new_and_best_block_events!(&mut sub, block_3_hash, block_2_hash); + + // Check (block 1 -> block 2 ->) block 4 -> block 5. + check_new_and_best_block_events!(&mut sub, block_4_hash, block_2_hash); + check_new_and_best_block_events!(&mut sub, block_5_hash, block_4_hash); + } + + // Finalize the block 6 from the fork. + client.finalize_block(block_6_hash, None).unwrap(); + + // Expect to report the best block changed before the finalized event. + let event: FollowEvent = get_next_event(&mut sub).await; + let expected = FollowEvent::BestBlockChanged(BestBlockChanged { + best_block_hash: format!("{:?}", block_6_hash), + }); + assert_eq!(event, expected); + + // All blocks from stale forks are pruned when we finalize block 6. + let mut event: FollowEvent = get_next_event(&mut sub).await; + + // Sort pruned block hashes to counter flaky test caused by event generation (get_pruned_hashes) + if let FollowEvent::Finalized(Finalized { pruned_block_hashes, .. }) = &mut event { + pruned_block_hashes.sort(); + } + let expected_pruned_block_hashes = { + let mut hashes = vec![ + format!("{:?}", block_2_hash), + format!("{:?}", block_3_hash), + format!("{:?}", block_4_hash), + format!("{:?}", block_5_hash), + ]; + hashes.sort(); + hashes + }; + + let expected = FollowEvent::Finalized(Finalized { + finalized_block_hashes: vec![ + format!("{:?}", block_1_hash), + format!("{:?}", block_2_f_hash), + format!("{:?}", block_6_hash), + ], + pruned_block_hashes: expected_pruned_block_hashes, + }); + + assert_eq!(event, expected); + + // Pruned hash can be unpinned. + let sub_id = sub.subscription_id(); + let sub_id = serde_json::to_string(&sub_id).unwrap(); + let hash = format!("{:?}", block_2_hash); + let _res: () = api.call("chainHead_v1_unpin", rpc_params![&sub_id, &hash]).await.unwrap(); + + // Import block 7 and check it. + let block_7_hash = import_block(client.clone(), block_6_hash, 3).await.hash(); + check_new_and_best_block_events!(&mut sub, block_7_hash, block_6_hash); + + // Finalize the block 7. + client.finalize_block(block_7_hash, None).unwrap(); + + let event: FollowEvent = get_next_event(&mut sub).await; + // All necessary blocks were pruned on block 6 finalization. + let expected = FollowEvent::Finalized(Finalized { + finalized_block_hashes: vec![format!("{:?}", block_7_hash)], + pruned_block_hashes: vec![], + }); + assert_eq!(event, expected); + + // Check block 8. + let block_8_hash = import_block(client.clone(), block_7_hash, 4).await.hash(); + check_new_and_best_block_events!(&mut sub, block_8_hash, block_7_hash); + + // Finalize the block 8. + client.finalize_block(block_8_hash, None).unwrap(); + + // All necessary blocks were pruned on block 6 finalization. + let event: FollowEvent = get_next_event(&mut sub).await; + let expected = FollowEvent::Finalized(Finalized { + finalized_block_hashes: vec![format!("{:?}", block_8_hash)], + pruned_block_hashes: vec![], + }); + assert_eq!(event, expected); +} diff --git a/substrate/client/rpc-spec-v2/src/transaction/api.rs b/substrate/client/rpc-spec-v2/src/transaction/api.rs index 33af9c9533388a1e4d5832a390c8eb96da756905..ed358922d53ed0d087a2693b55a9b4f51635c1c0 100644 --- a/substrate/client/rpc-spec-v2/src/transaction/api.rs +++ b/substrate/client/rpc-spec-v2/src/transaction/api.rs @@ -33,8 +33,8 @@ pub trait TransactionApi { /// /// This method is unstable and subject to change in the future. #[subscription( - name = "transactionWatch_unstable_submitAndWatch" => "transactionWatch_unstable_watchEvent", - unsubscribe = "transactionWatch_unstable_unwatch", + name = "transactionWatch_v1_submitAndWatch" => "transactionWatch_v1_watchEvent", + unsubscribe = "transactionWatch_v1_unwatch", item = TransactionEvent, )] fn submit_and_watch(&self, bytes: Bytes); @@ -47,14 +47,15 @@ pub trait TransactionBroadcastApi { /// # Unstable /// /// This method is unstable and subject to change in the future. - #[method(name = "transaction_unstable_broadcast")] - fn broadcast(&self, bytes: Bytes) -> RpcResult>; + + #[method(name = "transaction_v1_broadcast", raw_method)] + async 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>; + #[method(name = "transaction_v1_stop", raw_method)] + async fn stop_broadcast(&self, operation_id: String) -> Result<(), ErrorBroadcast>; } diff --git a/substrate/client/rpc-spec-v2/src/transaction/tests/setup.rs b/substrate/client/rpc-spec-v2/src/transaction/tests/setup.rs index 4a15657a7f69e290e0d1cccdf7fc3082671a9ede..570174a3db6434fec278225fbb6b390cd3a5f07a 100644 --- a/substrate/client/rpc-spec-v2/src/transaction/tests/setup.rs +++ b/substrate/client/rpc-spec-v2/src/transaction/tests/setup.rs @@ -67,6 +67,7 @@ fn maintained_pool( pub fn setup_api( options: Options, + max_tx_per_connection: usize, ) -> ( Arc, Arc, @@ -85,9 +86,13 @@ pub fn setup_api( let (task_executor, executor_recv) = TaskExecutorBroadcast::new(); - let tx_api = - RpcTransactionBroadcast::new(client_mock.clone(), pool.clone(), Arc::new(task_executor)) - .into_rpc(); + let tx_api = RpcTransactionBroadcast::new( + client_mock.clone(), + pool.clone(), + Arc::new(task_executor), + max_tx_per_connection, + ) + .into_rpc(); (api, pool, client_mock, tx_api, executor_recv, pool_state) } diff --git a/substrate/client/rpc-spec-v2/src/transaction/tests/transaction_broadcast_tests.rs b/substrate/client/rpc-spec-v2/src/transaction/tests/transaction_broadcast_tests.rs index 77a28968aedf8cfeefc7964ca29b972a856d618e..efb3bd94ddbfd2df8af96a49eb4d704e5f86af26 100644 --- a/substrate/client/rpc-spec-v2/src/transaction/tests/transaction_broadcast_tests.rs +++ b/substrate/client/rpc-spec-v2/src/transaction/tests/transaction_broadcast_tests.rs @@ -26,6 +26,8 @@ use std::sync::Arc; use substrate_test_runtime_client::AccountKeyring::*; use substrate_test_runtime_transaction_pool::uxt; +const MAX_TX_PER_CONNECTION: usize = 4; + // Test helpers. use crate::transaction::tests::{ middleware_pool::{MiddlewarePoolEvent, TxStatusTypeTest}, @@ -35,7 +37,7 @@ use crate::transaction::tests::{ #[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()); + setup_api(Default::default(), MAX_TX_PER_CONNECTION); // Start at block 1. let block_1_header = api.push_block(1, vec![], true); @@ -44,12 +46,12 @@ async fn tx_broadcast_enters_pool() { let xt = hex_string(&uxt.encode()); let operation_id: String = - tx_api.call("transaction_unstable_broadcast", rpc_params![&xt]).await.unwrap(); + tx_api.call("transaction_v1_broadcast", rpc_params![&xt]).await.unwrap(); - // Announce block 1 to `transaction_unstable_broadcast`. + // Announce block 1 to `transaction_v1_broadcast`. client_mock.trigger_import_stream(block_1_header).await; - // Ensure the tx propagated from `transaction_unstable_broadcast` to the transaction pool. + // Ensure the tx propagated from `transaction_v1_broadcast` to the transaction pool. let event = get_next_event!(&mut pool_middleware); assert_eq!( event, @@ -82,10 +84,7 @@ async fn tx_broadcast_enters_pool() { // 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(); + let _: () = tx_api.call("transaction_v1_stop", rpc_params![&operation_id]).await.unwrap(); // Ensure the broadcast future finishes. let _ = get_next_event!(&mut exec_middleware.recv); @@ -94,11 +93,12 @@ async fn tx_broadcast_enters_pool() { #[tokio::test] async fn tx_broadcast_invalid_tx() { - let (_, pool, _, tx_api, mut exec_middleware, _) = setup_api(Default::default()); + let (_, pool, _, tx_api, exec_middleware, _) = + setup_api(Default::default(), MAX_TX_PER_CONNECTION); // Invalid parameters. let err = tx_api - .call::<_, serde_json::Value>("transaction_unstable_broadcast", [1u8]) + .call::<_, serde_json::Value>("transaction_v1_broadcast", [1u8]) .await .unwrap_err(); assert_matches!(err, @@ -110,21 +110,18 @@ async fn tx_broadcast_invalid_tx() { // 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(); + tx_api.call("transaction_v1_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); + // The broadcast future should never be spawned when the tx decoding fails. assert_eq!(0, exec_middleware.num_tasks()); - // The broadcast future was dropped, and the operation is no longer active. + // The operation ID 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]) + .call::<_, serde_json::Value>("transaction_v1_stop", rpc_params![&operation_id]) .await .unwrap_err(); assert_matches!(err, @@ -134,11 +131,11 @@ async fn tx_broadcast_invalid_tx() { #[tokio::test] async fn tx_stop_with_invalid_operation_id() { - let (_, _, _, tx_api, _, _) = setup_api(Default::default()); + let (_, _, _, tx_api, _, _) = setup_api(Default::default(), MAX_TX_PER_CONNECTION); // Make an invalid stop call. let err = tx_api - .call::<_, serde_json::Value>("transaction_unstable_stop", ["invalid_operation_id"]) + .call::<_, serde_json::Value>("transaction_v1_stop", ["invalid_operation_id"]) .await .unwrap_err(); assert_matches!(err, @@ -149,7 +146,7 @@ async fn tx_stop_with_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()); + setup_api(Default::default(), MAX_TX_PER_CONNECTION); // Start at block 1. let block_1_header = api.push_block(1, vec![], true); @@ -161,15 +158,13 @@ async fn tx_broadcast_resubmits_future_nonce_tx() { 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(); + let future_operation_id: String = + tx_api.call("transaction_v1_broadcast", rpc_params![&future_xt]).await.unwrap(); - // Announce block 1 to `transaction_unstable_broadcast`. + // Announce block 1 to `transaction_v1_broadcast`. client_mock.trigger_import_stream(block_1_header).await; - // Ensure the tx propagated from `transaction_unstable_broadcast` to the transaction pool. + // Ensure the tx propagated from `transaction_v1_broadcast` to the transaction pool. let event = get_next_event!(&mut pool_middleware); assert_eq!( event, @@ -188,13 +183,11 @@ async fn tx_broadcast_resubmits_future_nonce_tx() { 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(); + let operation_id: String = + tx_api.call("transaction_v1_broadcast", rpc_params![¤t_xt]).await.unwrap(); assert_ne!(future_operation_id, operation_id); - // Announce block 2 to `transaction_unstable_broadcast`. + // Announce block 2 to `transaction_v1_broadcast`. client_mock.trigger_import_stream(block_2_header).await; // Collect the events of both transactions. @@ -240,7 +233,7 @@ async fn tx_broadcast_resubmits_future_nonce_tx() { #[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()); + setup_api(Default::default(), MAX_TX_PER_CONNECTION); // Start at block 1. let block_1_header = api.push_block(1, vec![], true); @@ -249,12 +242,12 @@ async fn tx_broadcast_stop_after_broadcast_finishes() { let xt = hex_string(&uxt.encode()); let operation_id: String = - tx_api.call("transaction_unstable_broadcast", rpc_params![&xt]).await.unwrap(); + tx_api.call("transaction_v1_broadcast", rpc_params![&xt]).await.unwrap(); - // Announce block 1 to `transaction_unstable_broadcast`. + // Announce block 1 to `transaction_v1_broadcast`. client_mock.trigger_import_stream(block_1_header).await; - // Ensure the tx propagated from `transaction_unstable_broadcast` to the transaction + // Ensure the tx propagated from `transaction_v1_broadcast` to the transaction // pool.inner_pool. let event = get_next_event!(&mut pool_middleware); assert_eq!( @@ -303,7 +296,7 @@ async fn tx_broadcast_stop_after_broadcast_finishes() { // 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]) + .call::<_, serde_json::Value>("transaction_v1_stop", rpc_params![&operation_id]) .await .unwrap_err(); assert_matches!(err, @@ -323,19 +316,19 @@ async fn tx_broadcast_resubmits_invalid_tx() { }; let (api, pool, client_mock, tx_api, mut exec_middleware, mut pool_middleware) = - setup_api(options); + setup_api(options, MAX_TX_PER_CONNECTION); 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(); + tx_api.call("transaction_v1_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`. + // Announce block 1 to `transaction_v1_broadcast`. client_mock.trigger_import_stream(block_1_header).await; - // Ensure the tx propagated from `transaction_unstable_broadcast` to the transaction pool. + // Ensure the tx propagated from `transaction_v1_broadcast` to the transaction pool. let event = get_next_event!(&mut pool_middleware); assert_eq!( event, @@ -355,7 +348,7 @@ async fn tx_broadcast_resubmits_invalid_tx() { 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. + // Ensure the `transaction_v1_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. @@ -388,7 +381,7 @@ async fn tx_broadcast_resubmits_invalid_tx() { pool.inner_pool.maintain(event).await; assert_eq!(0, pool.inner_pool.status().ready); - // Announce block to `transaction_unstable_broadcast`. + // Announce block to `transaction_v1_broadcast`. client_mock.trigger_import_stream(block_3_header).await; let event = get_next_event!(&mut pool_middleware); @@ -442,7 +435,8 @@ async fn tx_broadcast_resubmits_dropped_tx() { ban_time: std::time::Duration::ZERO, }; - let (api, pool, client_mock, tx_api, _, mut pool_middleware) = setup_api(options); + let (api, pool, client_mock, tx_api, _, mut pool_middleware) = + setup_api(options, MAX_TX_PER_CONNECTION); let current_uxt = uxt(Alice, ALICE_NONCE); let current_xt = hex_string(¤t_uxt.encode()); @@ -455,12 +449,10 @@ async fn tx_broadcast_resubmits_dropped_tx() { // 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(); + let current_operation_id: String = + tx_api.call("transaction_v1_broadcast", rpc_params![¤t_xt]).await.unwrap(); - // Announce block 1 to `transaction_unstable_broadcast`. + // Announce block 1 to `transaction_v1_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![]) }; @@ -479,10 +471,8 @@ async fn tx_broadcast_resubmits_dropped_tx() { // 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(); + let future_operation_id: String = + tx_api.call("transaction_v1_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); @@ -521,3 +511,50 @@ async fn tx_broadcast_resubmits_dropped_tx() { // The dropped transaction was resubmitted. assert_eq!(events.get(&future_xt).unwrap(), &vec![TxStatusTypeTest::Ready]); } + +#[tokio::test] +async fn tx_broadcast_limit_reached() { + // One operation per connection. + let (api, _pool, client_mock, tx_api, mut exec_middleware, mut pool_middleware) = + setup_api(Default::default(), 1); + + // 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_v1_broadcast", rpc_params![&xt]).await.unwrap(); + + // Announce block 1 to `transaction_v1_broadcast`. + client_mock.trigger_import_stream(block_1_header).await; + + // Ensure the tx propagated from `transaction_v1_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, exec_middleware.num_tasks()); + + let operation_id_limit_reached: Option = + tx_api.call("transaction_v1_broadcast", rpc_params![&xt]).await.unwrap(); + assert!(operation_id_limit_reached.is_none(), "No operation ID => tx was rejected"); + + // We still have in flight one operation. + assert_eq!(1, exec_middleware.num_tasks()); + + // Force the future to exit by calling stop. + let _: () = tx_api.call("transaction_v1_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()); + + // Can resubmit again now. + let _operation_id: String = + tx_api.call("transaction_v1_broadcast", rpc_params![&xt]).await.unwrap(); +} diff --git a/substrate/client/rpc-spec-v2/src/transaction/tests/transaction_tests.rs b/substrate/client/rpc-spec-v2/src/transaction/tests/transaction_tests.rs index c83bc948c437c99e767be09d4f351718140fcb89..7ce85b9feafe3ed2840321aee6c614962789707f 100644 --- a/substrate/client/rpc-spec-v2/src/transaction/tests/transaction_tests.rs +++ b/substrate/client/rpc-spec-v2/src/transaction/tests/transaction_tests.rs @@ -38,7 +38,7 @@ async fn tx_invalid_bytes() { // This should not rely on the tx pool state. let mut sub = tx_api - .subscribe_unbounded("transactionWatch_unstable_submitAndWatch", rpc_params![&"0xdeadbeef"]) + .subscribe_unbounded("transactionWatch_v1_submitAndWatch", rpc_params![&"0xdeadbeef"]) .await .unwrap(); @@ -56,7 +56,7 @@ async fn tx_in_finalized() { let xt = hex_string(&uxt.encode()); let mut sub = tx_api - .subscribe_unbounded("transactionWatch_unstable_submitAndWatch", rpc_params![&xt]) + .subscribe_unbounded("transactionWatch_v1_submitAndWatch", rpc_params![&xt]) .await .unwrap(); @@ -95,7 +95,7 @@ async fn tx_with_pruned_best_block() { let xt = hex_string(&uxt.encode()); let mut sub = tx_api - .subscribe_unbounded("transactionWatch_unstable_submitAndWatch", rpc_params![&xt]) + .subscribe_unbounded("transactionWatch_v1_submitAndWatch", rpc_params![&xt]) .await .unwrap(); diff --git a/substrate/client/rpc-spec-v2/src/transaction/transaction.rs b/substrate/client/rpc-spec-v2/src/transaction/transaction.rs index 6a7c69b8f7d1e765d0ce64ff590e191e97935d30..723440d1b11101b71bcc1602e4da3d15ac0e931e 100644 --- a/substrate/client/rpc-spec-v2/src/transaction/transaction.rs +++ b/substrate/client/rpc-spec-v2/src/transaction/transaction.rs @@ -26,6 +26,7 @@ use crate::{ }, SubscriptionTaskExecutor, }; + use codec::Decode; use futures::{StreamExt, TryFutureExt}; use jsonrpsee::{core::async_trait, PendingSubscriptionSink}; diff --git a/substrate/client/rpc-spec-v2/src/transaction/transaction_broadcast.rs b/substrate/client/rpc-spec-v2/src/transaction/transaction_broadcast.rs index 6eaf50d6b2e2822d766f4f131f4bd6f1ba04d5cd..68c19010e31c5653509c380f6be69c072e6fe9bb 100644 --- a/substrate/client/rpc-spec-v2/src/transaction/transaction_broadcast.rs +++ b/substrate/client/rpc-spec-v2/src/transaction/transaction_broadcast.rs @@ -18,11 +18,17 @@ //! API implementation for broadcasting transactions. -use crate::{transaction::api::TransactionBroadcastApiServer, SubscriptionTaskExecutor}; +use crate::{ + common::connections::RpcConnections, transaction::api::TransactionBroadcastApiServer, + SubscriptionTaskExecutor, +}; use codec::Decode; use futures::{FutureExt, Stream, StreamExt}; use futures_util::stream::AbortHandle; -use jsonrpsee::core::{async_trait, RpcResult}; +use jsonrpsee::{ + core::{async_trait, RpcResult}, + ConnectionDetails, +}; use parking_lot::RwLock; use rand::{distributions::Alphanumeric, Rng}; use sc_client_api::BlockchainEvents; @@ -37,7 +43,7 @@ use std::{collections::HashMap, sync::Arc}; use super::error::ErrorBroadcast; /// An API for transaction RPC calls. -pub struct TransactionBroadcast { +pub struct TransactionBroadcast { /// Substrate client. client: Arc, /// Transactions pool. @@ -45,19 +51,34 @@ pub struct TransactionBroadcast { /// Executor to spawn subscriptions. executor: SubscriptionTaskExecutor, /// The broadcast operation IDs. - broadcast_ids: Arc>>, + broadcast_ids: Arc>>>, + /// Keep track of how many concurrent operations are active for each connection. + rpc_connections: RpcConnections, } /// The state of a broadcast operation. -struct BroadcastState { +struct BroadcastState { /// Handle to abort the running future that broadcasts the transaction. handle: AbortHandle, + /// Associated tx hash. + tx_hash: ::Hash, } -impl TransactionBroadcast { +impl TransactionBroadcast { /// Creates a new [`TransactionBroadcast`]. - pub fn new(client: Arc, pool: Arc, executor: SubscriptionTaskExecutor) -> Self { - TransactionBroadcast { client, pool, executor, broadcast_ids: Default::default() } + pub fn new( + client: Arc, + pool: Arc, + executor: SubscriptionTaskExecutor, + max_transactions_per_connection: usize, + ) -> Self { + TransactionBroadcast { + client, + pool, + executor, + broadcast_ids: Default::default(), + rpc_connections: RpcConnections::new(max_transactions_per_connection), + } } /// Generate an unique operation ID for the `transaction_broadcast` RPC method. @@ -100,23 +121,46 @@ where ::Hash: Unpin, Client: HeaderBackend + BlockchainEvents + Send + Sync + 'static, { - fn broadcast(&self, bytes: Bytes) -> RpcResult> { + async fn broadcast( + &self, + connection_details: ConnectionDetails, + 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 = + // Ensure that the connection has not reached the maximum number of active operations. + let Some(reserved_connection) = self.rpc_connections.reserve_space(connection_details.id()) + else { + return Ok(None) + }; + let Some(reserved_identifier) = reserved_connection.register(id.clone()) else { + // This can only happen if the generated operation ID is not unique. + return Ok(None) + }; + + // The JSON-RPC server might check whether the transaction is valid before broadcasting it. + // If it does so and if the transaction is invalid, the server should silently do nothing + // and the JSON-RPC client is not informed of the problem. Invalid transactions should still + // count towards the limit to the number of simultaneously broadcasted transactions. + let Ok(decoded_extrinsic) = TransactionFor::::decode(&mut &bytes[..]) else { + return Ok(Some(id)); + }; + // Save the tx hash to remove it later. + let tx_hash = pool.hash_of(&decoded_extrinsic); + + // The compiler can no longer deduce the type of the stream and complains + // about `one type is more general than the other`. + let mut best_block_import_stream: std::pin::Pin< + Box::Hash> + Send>, + > = 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; @@ -169,17 +213,29 @@ where let (fut, handle) = futures::future::abortable(broadcast_transaction_fut); let broadcast_ids = self.broadcast_ids.clone(); let drop_id = id.clone(); + let pool = self.pool.clone(); // The future expected by the executor must be `Future` instead of // `Future>`. - let fut = fut.map(move |_| { + let fut = fut.map(move |result| { + // Connection space is cleaned when this object is dropped. + drop(reserved_identifier); + // Remove the entry from the broadcast IDs map. - broadcast_ids.write().remove(&drop_id); + let Some(broadcast_state) = broadcast_ids.write().remove(&drop_id) else { return }; + + // The broadcast was not stopped. + if result.is_ok() { + return + } + + // Best effort pool removal (tx can already be finalized). + pool.remove_invalid(&[broadcast_state.tx_hash]); }); // Keep track of this entry and the abortable handle. { let mut broadcast_ids = self.broadcast_ids.write(); - broadcast_ids.insert(id.clone(), BroadcastState { handle }); + broadcast_ids.insert(id.clone(), BroadcastState { handle, tx_hash }); } sc_rpc::utils::spawn_subscription_task(&self.executor, fut); @@ -187,7 +243,16 @@ where Ok(Some(id)) } - fn stop_broadcast(&self, operation_id: String) -> Result<(), ErrorBroadcast> { + async fn stop_broadcast( + &self, + connection_details: ConnectionDetails, + operation_id: String, + ) -> Result<(), ErrorBroadcast> { + // The operation ID must correlate to the same connection ID. + if !self.rpc_connections.contains_identifier(connection_details.id(), &operation_id) { + return Err(ErrorBroadcast::InvalidOperationID) + } + let mut broadcast_ids = self.broadcast_ids.write(); let Some(broadcast_state) = broadcast_ids.remove(&operation_id) else { diff --git a/substrate/client/rpc/Cargo.toml b/substrate/client/rpc/Cargo.toml index dff34215b025c26fa3e6f4fa2949dcd0d2e4203a..7dd46b2ab4c31e7be4168e588a8c95e900cb213a 100644 --- a/substrate/client/rpc/Cargo.toml +++ b/substrate/client/rpc/Cargo.toml @@ -16,7 +16,7 @@ workspace = true targets = ["x86_64-unknown-linux-gnu"] [dependencies] -codec = { package = "parity-scale-codec", version = "3.6.1" } +codec = { package = "parity-scale-codec", version = "3.6.12" } futures = "0.3.30" jsonrpsee = { version = "0.22", features = ["server"] } log = { workspace = true, default-features = true } diff --git a/substrate/client/service/Cargo.toml b/substrate/client/service/Cargo.toml index b93196e86f1d3674b2894a21783e269831a27656..dfdd485f15c00550119d9aebf8594b33cdba4df1 100644 --- a/substrate/client/service/Cargo.toml +++ b/substrate/client/service/Cargo.toml @@ -63,7 +63,7 @@ sc-chain-spec = { path = "../chain-spec" } sc-client-api = { path = "../api" } sp-api = { path = "../../primitives/api" } sc-client-db = { path = "../db", default-features = false } -codec = { package = "parity-scale-codec", version = "3.6.1" } +codec = { package = "parity-scale-codec", version = "3.6.12" } sc-executor = { path = "../executor" } sc-transaction-pool = { path = "../transaction-pool" } sp-transaction-pool = { path = "../../primitives/transaction-pool" } diff --git a/substrate/client/service/src/builder.rs b/substrate/client/service/src/builder.rs index 830f9884719dcf1fd1b024906f830b18a154a323..06fc2ea3b3049492c3755603f661dc378797cc6e 100644 --- a/substrate/client/service/src/builder.rs +++ b/substrate/client/service/src/builder.rs @@ -37,8 +37,8 @@ use sc_client_api::{ use sc_client_db::{Backend, DatabaseSettings}; use sc_consensus::import_queue::ImportQueue; use sc_executor::{ - sp_wasm_interface::HostFunctions, HeapAllocStrategy, NativeElseWasmExecutor, - NativeExecutionDispatch, RuntimeVersionOf, WasmExecutor, DEFAULT_HEAP_ALLOC_STRATEGY, + sp_wasm_interface::HostFunctions, HeapAllocStrategy, NativeExecutionDispatch, RuntimeVersionOf, + WasmExecutor, DEFAULT_HEAP_ALLOC_STRATEGY, }; use sc_keystore::LocalKeystore; use sc_network::{ @@ -262,11 +262,15 @@ where Ok((client, backend, keystore_container, task_manager)) } -/// Creates a [`NativeElseWasmExecutor`] according to [`Configuration`]. +/// Creates a [`NativeElseWasmExecutor`](sc_executor::NativeElseWasmExecutor) according to +/// [`Configuration`]. +#[deprecated(note = "Please switch to `new_wasm_executor`. Will be removed at end of 2024.")] +#[allow(deprecated)] pub fn new_native_or_wasm_executor( config: &Configuration, -) -> NativeElseWasmExecutor { - NativeElseWasmExecutor::new_with_wasm_executor(new_wasm_executor(config)) +) -> sc_executor::NativeElseWasmExecutor { + #[allow(deprecated)] + sc_executor::NativeElseWasmExecutor::new_with_wasm_executor(new_wasm_executor(config)) } /// Creates a [`WasmExecutor`] according to [`Configuration`]. @@ -644,10 +648,13 @@ where (chain, state, child_state) }; + const MAX_TRANSACTION_PER_CONNECTION: usize = 16; + let transaction_broadcast_rpc_v2 = sc_rpc_spec_v2::transaction::TransactionBroadcast::new( client.clone(), transaction_pool.clone(), task_executor.clone(), + MAX_TRANSACTION_PER_CONNECTION, ) .into_rpc(); diff --git a/substrate/client/service/src/client/call_executor.rs b/substrate/client/service/src/client/call_executor.rs index 86b5c7c61fcd2cbe062784fe53f8e9ba30adf6e0..9da4d2192576909f95428933623a1e3160e1f9ad 100644 --- a/substrate/client/service/src/client/call_executor.rs +++ b/substrate/client/service/src/client/call_executor.rs @@ -337,26 +337,17 @@ mod tests { use super::*; use backend::Backend; use sc_client_api::in_mem; - use sc_executor::{NativeElseWasmExecutor, WasmExecutor}; + use sc_executor::WasmExecutor; use sp_core::{ testing::TaskExecutor, traits::{FetchRuntimeCode, WrappedRuntimeCode}, }; use std::collections::HashMap; - use substrate_test_runtime_client::{runtime, GenesisInit, LocalExecutorDispatch}; - - fn executor() -> NativeElseWasmExecutor { - NativeElseWasmExecutor::new_with_wasm_executor( - WasmExecutor::builder() - .with_max_runtime_instances(1) - .with_runtime_cache_size(2) - .build(), - ) - } + use substrate_test_runtime_client::{runtime, GenesisInit}; #[test] fn should_get_override_if_exists() { - let executor = executor(); + let executor = WasmExecutor::default(); let overrides = crate::client::wasm_override::dummy_overrides(); let onchain_code = WrappedRuntimeCode(substrate_test_runtime::wasm_binary_unwrap().into()); @@ -425,7 +416,7 @@ mod tests { fn returns_runtime_version_from_substitute() { const SUBSTITUTE_SPEC_NAME: &str = "substitute-spec-name-cool"; - let executor = executor(); + let executor = WasmExecutor::default(); let backend = Arc::new(in_mem::Backend::::new()); diff --git a/substrate/client/service/src/client/client.rs b/substrate/client/service/src/client/client.rs index 35e8b53a09cf2d802a0c4a873f7ecb8099764e83..3c25c233775bea6ed8297d144bcadf823b918e7e 100644 --- a/substrate/client/service/src/client/client.rs +++ b/substrate/client/service/src/client/client.rs @@ -978,8 +978,12 @@ where // The stale heads are the leaves that will be displaced after the // block is finalized. - let stale_heads = - self.backend.blockchain().displaced_leaves_after_finalizing(block_number)?; + let stale_heads = self + .backend + .blockchain() + .displaced_leaves_after_finalizing(hash, block_number)? + .hashes() + .collect(); let header = self .backend diff --git a/substrate/client/service/src/client/wasm_override.rs b/substrate/client/service/src/client/wasm_override.rs index 725c8ab9429aca18998c4e94c467ff5851348a7c..678ae22bec11117ddfbf1815422638625e602085 100644 --- a/substrate/client/service/src/client/wasm_override.rs +++ b/substrate/client/service/src/client/wasm_override.rs @@ -264,24 +264,21 @@ pub fn dummy_overrides() -> WasmOverride { #[cfg(test)] mod tests { use super::*; - use sc_executor::{HeapAllocStrategy, NativeElseWasmExecutor, WasmExecutor}; + use sc_executor::{HeapAllocStrategy, WasmExecutor}; use std::fs::{self, File}; - use substrate_test_runtime_client::LocalExecutorDispatch; - - fn executor() -> NativeElseWasmExecutor { - NativeElseWasmExecutor::::new_with_wasm_executor( - WasmExecutor::builder() - .with_onchain_heap_alloc_strategy(HeapAllocStrategy::Static {extra_pages: 128}) - .with_offchain_heap_alloc_strategy(HeapAllocStrategy::Static {extra_pages: 128}) - .with_max_runtime_instances(1) - .with_runtime_cache_size(2) - .build() - ) + + fn executor() -> WasmExecutor { + WasmExecutor::builder() + .with_onchain_heap_alloc_strategy(HeapAllocStrategy::Static { extra_pages: 128 }) + .with_offchain_heap_alloc_strategy(HeapAllocStrategy::Static { extra_pages: 128 }) + .with_max_runtime_instances(1) + .with_runtime_cache_size(2) + .build() } fn wasm_test(fun: F) where - F: Fn(&Path, &[u8], &NativeElseWasmExecutor), + F: Fn(&Path, &[u8], &WasmExecutor), { let exec = executor(); let bytes = substrate_test_runtime::wasm_binary_unwrap(); diff --git a/substrate/client/service/src/config.rs b/substrate/client/service/src/config.rs index 59e307d7f93b529f37ab457dd6bfe0b312065444..187e18aa3cace20c9fe9ffe2e9f3fdcbb6658bbd 100644 --- a/substrate/client/service/src/config.rs +++ b/substrate/client/service/src/config.rs @@ -34,6 +34,7 @@ pub use sc_network::{ }, Multiaddr, }; +pub use sc_rpc_server::IpNetwork; pub use sc_telemetry::TelemetryEndpoints; pub use sc_transaction_pool::Options as TransactionPoolOptions; use sp_core::crypto::SecretString; @@ -108,6 +109,10 @@ pub struct Configuration { pub rpc_batch_config: RpcBatchRequestConfig, /// RPC rate limit per minute. pub rpc_rate_limit: Option, + /// RPC rate limit whitelisted ip addresses. + pub rpc_rate_limit_whitelisted_ips: Vec, + /// RPC rate limit trust proxy headers. + pub rpc_rate_limit_trust_proxy_headers: bool, /// 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 e46cfab50a3ebdcb4e6eb8f746ec27751cd77847..d251fd2b58fa7252f2b7a797da0228af1d89cafe 100644 --- a/substrate/client/service/src/lib.rs +++ b/substrate/client/service/src/lib.rs @@ -54,15 +54,17 @@ use sp_runtime::traits::{Block as BlockT, Header as HeaderT}; pub use self::{ builder::{ - build_network, new_client, new_db_backend, new_full_client, new_full_parts, - new_full_parts_record_import, new_full_parts_with_genesis_builder, - new_native_or_wasm_executor, new_wasm_executor, spawn_tasks, BuildNetworkParams, + build_network, gen_rpc_module, init_telemetry, new_client, new_db_backend, new_full_client, + new_full_parts, new_full_parts_record_import, new_full_parts_with_genesis_builder, + new_wasm_executor, propagate_transaction_notifications, spawn_tasks, BuildNetworkParams, KeystoreContainer, NetworkStarter, SpawnTasksParams, TFullBackend, TFullCallExecutor, TFullClient, }, client::{ClientConfig, LocalCallExecutor}, error::Error, }; +#[allow(deprecated)] +pub use builder::new_native_or_wasm_executor; pub use sc_chain_spec::{ construct_genesis_block, resolve_state_version_from_wasm, BuildGenesisBlock, @@ -406,6 +408,8 @@ where cors: config.rpc_cors.as_ref(), tokio_handle: config.tokio_handle.clone(), rate_limit: config.rpc_rate_limit, + rate_limit_whitelisted_ips: config.rpc_rate_limit_whitelisted_ips.clone(), + rate_limit_trust_proxy_headers: config.rpc_rate_limit_trust_proxy_headers, }; // 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 2de984689badbacae254c7a596e996baa491dda5..e95e06cee267e68ca4b87f7179c8c66b9de40f61 100644 --- a/substrate/client/service/test/Cargo.toml +++ b/substrate/client/service/test/Cargo.toml @@ -16,11 +16,11 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] async-channel = "1.8.0" -array-bytes = "6.1" +array-bytes = "6.2.2" fdlimit = "0.3.0" futures = "0.3.30" log = { workspace = true, default-features = true } -parity-scale-codec = "3.6.1" +parity-scale-codec = "3.6.12" parking_lot = "0.12.1" tempfile = "3.1.0" tokio = { version = "1.22.0", features = ["time"] } diff --git a/substrate/client/service/test/src/client/mod.rs b/substrate/client/service/test/src/client/mod.rs index 51dcc4966e58838a4055f59ff033e16010c1d585..6542830c998b3a4f29df2f6a32f9d71c0aee688a 100644 --- a/substrate/client/service/test/src/client/mod.rs +++ b/substrate/client/service/test/src/client/mod.rs @@ -28,6 +28,7 @@ use sc_client_db::{Backend, BlocksPruning, DatabaseSettings, DatabaseSource, Pru use sc_consensus::{ BlockCheckParams, BlockImport, BlockImportParams, ForkChoiceStrategy, ImportResult, }; +use sc_executor::WasmExecutor; use sc_service::client::{new_in_mem, Client, LocalCallExecutor}; use sp_api::ProvideRuntimeApi; use sp_consensus::{BlockOrigin, Error as ConsensusError, SelectChain}; @@ -42,8 +43,6 @@ use sp_storage::{ChildInfo, StorageKey}; use std::{collections::HashSet, sync::Arc}; use substrate_test_runtime::TestAPI; use substrate_test_runtime_client::{ - new_native_or_wasm_executor, - prelude::*, runtime::{ currency::DOLLARS, genesismap::{insert_genesis_block, GenesisStorageBuilder}, @@ -79,7 +78,7 @@ fn construct_block( StateMachine::new( backend, &mut overlay, - &new_native_or_wasm_executor(), + &WasmExecutor::default(), "Core_initialize_block", &header.encode(), &mut Default::default(), @@ -93,7 +92,7 @@ fn construct_block( StateMachine::new( backend, &mut overlay, - &new_native_or_wasm_executor(), + &WasmExecutor::default(), "BlockBuilder_apply_extrinsic", &tx.encode(), &mut Default::default(), @@ -107,7 +106,7 @@ fn construct_block( let ret_data = StateMachine::new( backend, &mut overlay, - &new_native_or_wasm_executor(), + &WasmExecutor::default(), "BlockBuilder_finalize_block", &[], &mut Default::default(), @@ -175,7 +174,7 @@ fn construct_genesis_should_work_with_native() { let _ = StateMachine::new( &backend, &mut overlay, - &new_native_or_wasm_executor(), + &WasmExecutor::default(), "Core_execute_block", &b1data, &mut Default::default(), @@ -206,7 +205,7 @@ fn construct_genesis_should_work_with_wasm() { let _ = StateMachine::new( &backend, &mut overlay, - &new_native_or_wasm_executor(), + &WasmExecutor::default(), "Core_execute_block", &b1data, &mut Default::default(), @@ -1165,7 +1164,7 @@ fn finalizing_diverged_block_should_trigger_reorg() { // G -> A1 -> A2 // \ - // -> B1 -> B2 + // -> B1 -> B2 -> B3 let mut finality_notifications = client.finality_notification_stream(); @@ -1250,8 +1249,8 @@ fn finalizing_diverged_block_should_trigger_reorg() { ClientExt::finalize_block(&client, b3.hash(), None).unwrap(); - finality_notification_check(&mut finality_notifications, &[b1.hash()], &[]); - finality_notification_check(&mut finality_notifications, &[b2.hash(), b3.hash()], &[a2.hash()]); + finality_notification_check(&mut finality_notifications, &[b1.hash()], &[a2.hash()]); + finality_notification_check(&mut finality_notifications, &[b2.hash(), b3.hash()], &[]); assert!(matches!(finality_notifications.try_recv().unwrap_err(), TryRecvError::Empty)); } @@ -1372,8 +1371,12 @@ fn finality_notifications_content() { // Import and finalize D4 block_on(client.import_as_final(BlockOrigin::Own, d4.clone())).unwrap(); - finality_notification_check(&mut finality_notifications, &[a1.hash(), a2.hash()], &[c1.hash()]); - finality_notification_check(&mut finality_notifications, &[d3.hash(), d4.hash()], &[b2.hash()]); + finality_notification_check( + &mut finality_notifications, + &[a1.hash(), a2.hash()], + &[c1.hash(), b2.hash()], + ); + finality_notification_check(&mut finality_notifications, &[d3.hash(), d4.hash()], &[a3.hash()]); assert!(matches!(finality_notifications.try_recv().unwrap_err(), TryRecvError::Empty)); } @@ -1602,9 +1605,9 @@ fn doesnt_import_blocks_that_revert_finality() { block_on(client.import(BlockOrigin::Own, a3.clone())).unwrap(); ClientExt::finalize_block(&client, a3.hash(), None).unwrap(); - finality_notification_check(&mut finality_notifications, &[a1.hash(), a2.hash()], &[]); + finality_notification_check(&mut finality_notifications, &[a1.hash(), a2.hash()], &[b2.hash()]); - finality_notification_check(&mut finality_notifications, &[a3.hash()], &[b2.hash()]); + finality_notification_check(&mut finality_notifications, &[a3.hash()], &[]); assert!(matches!(finality_notifications.try_recv().unwrap_err(), TryRecvError::Empty)); } @@ -2072,7 +2075,7 @@ fn cleans_up_closed_notification_sinks_on_block_import() { use substrate_test_runtime_client::GenesisInit; let backend = Arc::new(sc_client_api::in_mem::Backend::new()); - let executor = new_native_or_wasm_executor(); + let executor = WasmExecutor::default(); let client_config = sc_service::ClientConfig::default(); let genesis_block_builder = sc_service::GenesisBlockBuilder::new( @@ -2099,11 +2102,7 @@ fn cleans_up_closed_notification_sinks_on_block_import() { type TestClient = Client< in_mem::Backend, - LocalCallExecutor< - Block, - in_mem::Backend, - sc_executor::NativeElseWasmExecutor, - >, + LocalCallExecutor, WasmExecutor>, Block, RuntimeApi, >; diff --git a/substrate/client/service/test/src/lib.rs b/substrate/client/service/test/src/lib.rs index b9abd8446f7dd6b24f12813b6716d4697f2bdf19..f19b5a19739e2b9c90f5848e2332e487d0ccd5fe 100644 --- a/substrate/client/service/test/src/lib.rs +++ b/substrate/client/service/test/src/lib.rs @@ -252,6 +252,8 @@ fn node_config< rpc_message_buffer_capacity: Default::default(), rpc_batch_config: RpcBatchRequestConfig::Unlimited, rpc_rate_limit: None, + rpc_rate_limit_whitelisted_ips: Default::default(), + rpc_rate_limit_trust_proxy_headers: Default::default(), 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 400dda20c223443687292315b4974e5125570553..e203eb5a3282fa1ed73c75426b6039f046bef7d7 100644 --- a/substrate/client/state-db/Cargo.toml +++ b/substrate/client/state-db/Cargo.toml @@ -16,7 +16,7 @@ workspace = true targets = ["x86_64-unknown-linux-gnu"] [dependencies] -codec = { package = "parity-scale-codec", version = "3.6.1", features = ["derive"] } +codec = { package = "parity-scale-codec", version = "3.6.12", features = ["derive"] } log = { workspace = true, default-features = true } parking_lot = "0.12.1" sp-core = { path = "../../primitives/core" } diff --git a/substrate/client/sync-state-rpc/Cargo.toml b/substrate/client/sync-state-rpc/Cargo.toml index 09dc611caa044debeabce4f15686465535f076ed..d5bdc920f7c9b48991354f5df917a3b3d72c86fa 100644 --- a/substrate/client/sync-state-rpc/Cargo.toml +++ b/substrate/client/sync-state-rpc/Cargo.toml @@ -15,8 +15,8 @@ workspace = true targets = ["x86_64-unknown-linux-gnu"] [dependencies] -codec = { package = "parity-scale-codec", version = "3.6.1" } -jsonrpsee = { version = "0.22", features = ["client-core", "macros", "server"] } +codec = { package = "parity-scale-codec", version = "3.6.12" } +jsonrpsee = { version = "0.22.5", features = ["client-core", "macros", "server-core"] } serde = { features = ["derive"], workspace = true, default-features = true } serde_json = { workspace = true, default-features = true } thiserror = { workspace = true } diff --git a/substrate/client/tracing/Cargo.toml b/substrate/client/tracing/Cargo.toml index ba1a7c51ab8d837206551b5088f4a6a83640ed65..df674d24c6dd79b36ef7aa7aa36d389a7702678d 100644 --- a/substrate/client/tracing/Cargo.toml +++ b/substrate/client/tracing/Cargo.toml @@ -19,7 +19,7 @@ targets = ["x86_64-unknown-linux-gnu"] ansi_term = "0.12.1" is-terminal = "0.4.9" chrono = "0.4.31" -codec = { package = "parity-scale-codec", version = "3.6.1" } +codec = { package = "parity-scale-codec", version = "3.6.12" } lazy_static = "1.4.0" libc = "0.2.152" log = { workspace = true, default-features = true } @@ -29,8 +29,8 @@ rustc-hash = "1.1.0" serde = { workspace = true, default-features = true } thiserror = { workspace = true } tracing = "0.1.29" -tracing-log = "0.1.3" -tracing-subscriber = { workspace = true, features = ["parking_lot"] } +tracing-log = "0.2.0" +tracing-subscriber = { workspace = true, features = ["env-filter", "parking_lot"] } sc-client-api = { path = "../api" } sc-tracing-proc-macro = { path = "proc-macro" } sp-api = { path = "../../primitives/api" } @@ -41,7 +41,7 @@ sp-runtime = { path = "../../primitives/runtime" } sp-tracing = { path = "../../primitives/tracing" } [dev-dependencies] -criterion = "0.4.0" +criterion = "0.5.1" tracing-subscriber = { workspace = true, features = ["chrono", "parking_lot"] } [[bench]] diff --git a/substrate/client/tracing/src/logging/event_format.rs b/substrate/client/tracing/src/logging/event_format.rs index 9589c1dfee28d11fe0dd7d409f9cec6e3563b812..8d875427841e94c933ed0a704050409c7e23552a 100644 --- a/substrate/client/tracing/src/logging/event_format.rs +++ b/substrate/client/tracing/src/logging/event_format.rs @@ -21,6 +21,7 @@ use ansi_term::Colour; use regex::Regex; use std::fmt::{self, Write}; use tracing::{Event, Level, Subscriber}; +use tracing_log::NormalizeEvent; use tracing_subscriber::{ fmt::{format, time::FormatTime, FmtContext, FormatEvent, FormatFields}, registry::LookupSpan, @@ -60,10 +61,12 @@ where N: for<'a> FormatFields<'a> + 'static, { let mut writer = &mut ControlCodeSanitizer::new(!self.enable_color, writer); + let normalized_meta = event.normalized_metadata(); + let meta = normalized_meta.as_ref().unwrap_or_else(|| event.metadata()); time::write(&self.timer, &mut format::Writer::new(&mut writer), self.enable_color)?; if self.display_level { - let fmt_level = FmtLevel::new(event.metadata().level(), self.enable_color); + let fmt_level = FmtLevel::new(meta.level(), self.enable_color); write!(writer, "{} ", fmt_level)?; } @@ -81,7 +84,7 @@ where } if self.display_target { - write!(writer, "{}: ", event.metadata().target())?; + write!(writer, "{}: ", meta.target())?; } // Custom code to display node name diff --git a/substrate/client/tracing/src/logging/mod.rs b/substrate/client/tracing/src/logging/mod.rs index 8b2ad9b598b5be905ccb97c15817f249022f2b78..46fd4efb339a363a69929dba7091bc9bb685a5bd 100644 --- a/substrate/client/tracing/src/logging/mod.rs +++ b/substrate/client/tracing/src/logging/mod.rs @@ -141,6 +141,10 @@ where .add_directive( parse_default_directive("libp2p_mdns::behaviour::iface=off") .expect("provided directive is valid"), + ) + .add_directive( + parse_default_directive("rustls::common_state=off") + .expect("provided directive is valid"), ); if let Ok(lvl) = std::env::var("RUST_LOG") { diff --git a/substrate/client/transaction-pool/Cargo.toml b/substrate/client/transaction-pool/Cargo.toml index e2a0b87eaabb79383299036f92f5b3899b1b4e04..351650297ffc599a0081dff9cf0514dc6c6fc810 100644 --- a/substrate/client/transaction-pool/Cargo.toml +++ b/substrate/client/transaction-pool/Cargo.toml @@ -17,7 +17,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] async-trait = "0.1.79" -codec = { package = "parity-scale-codec", version = "3.6.1" } +codec = { package = "parity-scale-codec", version = "3.6.12" } futures = "0.3.30" futures-timer = "3.0.2" linked-hash-map = "0.5.4" @@ -38,9 +38,9 @@ sp-tracing = { path = "../../primitives/tracing" } sp-transaction-pool = { path = "../../primitives/transaction-pool" } [dev-dependencies] -array-bytes = "6.1" +array-bytes = "6.2.2" assert_matches = "1.3.0" -criterion = "0.4.0" +criterion = "0.5.1" sc-block-builder = { path = "../block-builder" } sp-consensus = { path = "../../primitives/consensus/common" } substrate-test-runtime = { path = "../../test-utils/runtime" } diff --git a/substrate/client/transaction-pool/api/Cargo.toml b/substrate/client/transaction-pool/api/Cargo.toml index 1bb72ef55442216e321c564838a93a75a44f62eb..be80a7706b3efe653ceaf071f42a4e017bc428db 100644 --- a/substrate/client/transaction-pool/api/Cargo.toml +++ b/substrate/client/transaction-pool/api/Cargo.toml @@ -13,7 +13,7 @@ workspace = true [dependencies] async-trait = "0.1.79" -codec = { package = "parity-scale-codec", version = "3.6.1" } +codec = { package = "parity-scale-codec", version = "3.6.12" } futures = "0.3.30" log = { workspace = true, default-features = true } serde = { features = ["derive"], workspace = true, default-features = true } diff --git a/substrate/frame/Cargo.toml b/substrate/frame/Cargo.toml index 919d6d17ce8b128c03a28d9bf502919aba833176..3942f06ce6eec966dd2883e679e3cfe570251b35 100644 --- a/substrate/frame/Cargo.toml +++ b/substrate/frame/Cargo.toml @@ -2,12 +2,11 @@ name = "polkadot-sdk-frame" version = "0.1.0" authors = ["Parity Technologies "] -edition = "2021" +edition.workspace = true license = "Apache-2.0" -homepage = "paritytech.github.io" +homepage = "https://paritytech.github.io" repository.workspace = true -description = "The single package to get you started with building frame pallets and runtimes" -publish = false +description = "Experimental: The single package to get you started with building frame pallets and runtimes" [lints] workspace = true @@ -19,7 +18,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] # external deps -parity-scale-codec = { version = "3.2.2", default-features = false, features = [ +parity-scale-codec = { version = "3.6.12", default-features = false, features = [ "derive", ] } scale-info = { version = "2.11.1", default-features = false, features = [ @@ -47,10 +46,18 @@ sp-session = { default-features = false, path = "../primitives/session", optiona sp-consensus-aura = { default-features = false, path = "../primitives/consensus/aura", optional = true } sp-consensus-grandpa = { default-features = false, path = "../primitives/consensus/grandpa", optional = true } sp-inherents = { default-features = false, path = "../primitives/inherents", optional = true } +sp-storage = { default-features = false, path = "../primitives/storage", optional = true } frame-executive = { default-features = false, path = "../frame/executive", optional = true } frame-system-rpc-runtime-api = { default-features = false, path = "../frame/system/rpc/runtime-api", optional = true } +# Used for runtime benchmarking +frame-benchmarking = { default-features = false, path = "../frame/benchmarking", optional = true } +frame-system-benchmarking = { default-features = false, path = "../frame/system/benchmarking", optional = true } + +# Used for try-runtime +frame-try-runtime = { default-features = false, path = "../frame/try-runtime", optional = true } + docify = "0.2.8" log = { workspace = true } @@ -68,6 +75,7 @@ runtime = [ "sp-inherents", "sp-offchain", "sp-session", + "sp-storage", "sp-transaction-pool", "sp-version", @@ -75,10 +83,13 @@ runtime = [ "frame-system-rpc-runtime-api", ] 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", "log/std", "parity-scale-codec/std", "scale-info/std", @@ -94,6 +105,22 @@ std = [ "sp-runtime/std", "sp-session?/std", "sp-std/std", + "sp-storage/std", "sp-transaction-pool?/std", "sp-version?/std", ] +runtime-benchmarks = [ + "frame-benchmarking/runtime-benchmarks", + "frame-support/runtime-benchmarks", + "frame-system-benchmarking/runtime-benchmarks", + "frame-system/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-examples/try-runtime", + "sp-runtime/try-runtime", +] diff --git a/substrate/frame/alliance/Cargo.toml b/substrate/frame/alliance/Cargo.toml index af1fcb296f6726983c654238dbc2d2161e4eec1a..10e2feba62376d9cd8346f44531dbd3e6bc47870 100644 --- a/substrate/frame/alliance/Cargo.toml +++ b/substrate/frame/alliance/Cargo.toml @@ -16,10 +16,10 @@ workspace = true targets = ["x86_64-unknown-linux-gnu"] [dependencies] -array-bytes = { version = "6.1", optional = true } +array-bytes = { version = "6.2.2", optional = true } log = { workspace = true } -codec = { package = "parity-scale-codec", version = "3.6.1", default-features = false, features = ["derive"] } +codec = { package = "parity-scale-codec", version = "3.6.12", default-features = false, features = ["derive"] } scale-info = { version = "2.11.1", default-features = false, features = ["derive"] } sp-std = { path = "../../primitives/std", default-features = false } @@ -36,7 +36,7 @@ pallet-identity = { path = "../identity", default-features = false } pallet-collective = { path = "../collective", default-features = false, optional = true } [dev-dependencies] -array-bytes = "6.1" +array-bytes = "6.2.2" sp-crypto-hashing = { path = "../../primitives/crypto/hashing", default-features = false } pallet-balances = { path = "../balances" } pallet-collective = { path = "../collective" } diff --git a/substrate/frame/alliance/src/benchmarking.rs b/substrate/frame/alliance/src/benchmarking.rs index 710c32a848dd152b4ae4cf02c1be87e295ae7da4..09e2045555b65b857614f3c14be669b1c6ffdd3c 100644 --- a/substrate/frame/alliance/src/benchmarking.rs +++ b/substrate/frame/alliance/src/benchmarking.rs @@ -19,11 +19,7 @@ #![cfg(feature = "runtime-benchmarks")] -use core::{ - cmp, - convert::{TryFrom, TryInto}, - mem::size_of, -}; +use core::{cmp, mem::size_of}; use sp_runtime::traits::{Bounded, Hash, StaticLookup}; use frame_benchmarking::{account, v2::*, BenchmarkError}; diff --git a/substrate/frame/alliance/src/lib.rs b/substrate/frame/alliance/src/lib.rs index 1f06241e9c83b088137547ec47372aa8e84142d7..ed771c7226ea9d9c43a94b906722f5379e7c0174 100644 --- a/substrate/frame/alliance/src/lib.rs +++ b/substrate/frame/alliance/src/lib.rs @@ -101,7 +101,7 @@ use sp_runtime::{ traits::{Dispatchable, Saturating, StaticLookup, Zero}, DispatchError, RuntimeDebug, }; -use sp_std::{convert::TryInto, prelude::*}; +use sp_std::prelude::*; use frame_support::{ dispatch::{DispatchResult, DispatchResultWithPostInfo, GetDispatchInfo, PostDispatchInfo}, diff --git a/substrate/frame/alliance/src/mock.rs b/substrate/frame/alliance/src/mock.rs index b183e412bed779291ef2bf3d94c0790295420e02..7116e69efa17ec88134699570b2235b8b0973d7c 100644 --- a/substrate/frame/alliance/src/mock.rs +++ b/substrate/frame/alliance/src/mock.rs @@ -17,7 +17,6 @@ //! Test utilities -use core::convert::{TryFrom, TryInto}; pub use sp_core::H256; use sp_runtime::traits::Hash; pub use sp_runtime::{ diff --git a/substrate/frame/alliance/src/types.rs b/substrate/frame/alliance/src/types.rs index 784993b2bc1334a26bd7430661e3481d7b6041d8..149030b52c674a8007ea19f77ec1356fb44a49b3 100644 --- a/substrate/frame/alliance/src/types.rs +++ b/substrate/frame/alliance/src/types.rs @@ -19,7 +19,7 @@ use codec::{Decode, Encode, MaxEncodedLen}; use frame_support::{traits::ConstU32, BoundedVec}; use scale_info::TypeInfo; use sp_runtime::RuntimeDebug; -use sp_std::{convert::TryInto, prelude::*}; +use sp_std::prelude::*; /// A Multihash instance that only supports the basic functionality and no hashing. #[derive( diff --git a/substrate/frame/asset-conversion/Cargo.toml b/substrate/frame/asset-conversion/Cargo.toml index 1a8e8eea4849ad76f5185ccb6a76745db07d4513..bfcda2299d5a116eca62a5870a84823876bc89f5 100644 --- a/substrate/frame/asset-conversion/Cargo.toml +++ b/substrate/frame/asset-conversion/Cargo.toml @@ -16,7 +16,8 @@ workspace = true targets = ["x86_64-unknown-linux-gnu"] [dependencies] -codec = { package = "parity-scale-codec", version = "3.6.1", default-features = false } +codec = { package = "parity-scale-codec", version = "3.6.12", default-features = false } +log = { version = "0.4.20", default-features = false } frame-support = { path = "../support", default-features = false } frame-system = { path = "../system", default-features = false } frame-benchmarking = { path = "../benchmarking", default-features = false, optional = true } @@ -40,6 +41,7 @@ std = [ "frame-benchmarking?/std", "frame-support/std", "frame-system/std", + "log/std", "pallet-assets/std", "pallet-balances/std", "primitive-types/std", diff --git a/substrate/frame/asset-conversion/ops/Cargo.toml b/substrate/frame/asset-conversion/ops/Cargo.toml new file mode 100644 index 0000000000000000000000000000000000000000..c5efbf9f6f442b0430cecab10badb4ca13e49d0a --- /dev/null +++ b/substrate/frame/asset-conversion/ops/Cargo.toml @@ -0,0 +1,71 @@ +[package] +name = "pallet-asset-conversion-ops" +version = "0.1.0" +authors.workspace = true +edition.workspace = true +license = "Apache-2.0" +homepage = "https://substrate.io" +repository.workspace = true +description = "FRAME asset conversion pallet's operations suite" + +[lints] +workspace = true + +[package.metadata.docs.rs] +targets = ["x86_64-unknown-linux-gnu"] + +[dependencies] +codec = { package = "parity-scale-codec", version = "3.6.12", default-features = false } +log = { version = "0.4.20", default-features = false } +frame-support = { path = "../../support", default-features = false } +frame-system = { path = "../../system", default-features = false } +frame-benchmarking = { path = "../../benchmarking", default-features = false, optional = true } +pallet-asset-conversion = { path = "..", default-features = false } +scale-info = { version = "2.10.0", default-features = false, features = ["derive"] } +sp-core = { path = "../../../primitives/core", default-features = false } +sp-io = { path = "../../../primitives/io", default-features = false } +sp-std = { path = "../../../primitives/std", default-features = false } +sp-runtime = { path = "../../../primitives/runtime", default-features = false } +sp-arithmetic = { path = "../../../primitives/arithmetic", default-features = false } + +[dev-dependencies] +pallet-balances = { path = "../../balances" } +pallet-assets = { path = "../../assets" } +primitive-types = { version = "0.12.0", default-features = false, features = ["codec", "num-traits", "scale-info"] } + +[features] +default = ["std"] +std = [ + "codec/std", + "frame-benchmarking?/std", + "frame-support/std", + "frame-system/std", + "log/std", + "pallet-asset-conversion/std", + "pallet-assets/std", + "pallet-balances/std", + "primitive-types/std", + "scale-info/std", + "sp-arithmetic/std", + "sp-core/std", + "sp-io/std", + "sp-runtime/std", + "sp-std/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", + "sp-runtime/runtime-benchmarks", +] +try-runtime = [ + "frame-support/try-runtime", + "frame-system/try-runtime", + "pallet-asset-conversion/try-runtime", + "pallet-assets/try-runtime", + "pallet-balances/try-runtime", + "sp-runtime/try-runtime", +] diff --git a/substrate/frame/asset-conversion/ops/src/benchmarking.rs b/substrate/frame/asset-conversion/ops/src/benchmarking.rs new file mode 100644 index 0000000000000000000000000000000000000000..a7370f38bc4b0472c4baea94bffc0d26b3169efe --- /dev/null +++ b/substrate/frame/asset-conversion/ops/src/benchmarking.rs @@ -0,0 +1,167 @@ +// This file is part of Substrate. + +// Copyright (C) Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +//! Asset Conversion Ops pallet benchmarking. + +use super::*; +use crate::Pallet as AssetConversionOps; +use frame_benchmarking::{v2::*, whitelisted_caller}; +use frame_support::{ + assert_ok, + traits::fungibles::{Create, Inspect, Mutate}, +}; +use frame_system::RawOrigin as SystemOrigin; +use pallet_asset_conversion::{BenchmarkHelper, Pallet as AssetConversion}; +use sp_core::Get; +use sp_runtime::traits::One; +use sp_std::prelude::*; + +/// Provides a pair of amounts expected to serve as sufficient initial liquidity for a pool. +fn valid_liquidity_amount(ed1: T::Balance, ed2: T::Balance) -> (T::Balance, T::Balance) +where + T::Assets: Inspect, +{ + let l = + ed1.max(ed2) + T::MintMinLiquidity::get() + T::MintMinLiquidity::get() + T::Balance::one(); + (l, l) +} + +/// Create the `asset` and mint the `amount` for the `caller`. +fn create_asset(caller: &T::AccountId, asset: &T::AssetKind, amount: T::Balance) +where + T::Assets: Create + Mutate, +{ + if !T::Assets::asset_exists(asset.clone()) { + assert_ok!(T::Assets::create(asset.clone(), caller.clone(), true, T::Balance::one())); + } + assert_ok!(T::Assets::mint_into( + asset.clone(), + &caller, + amount + T::Assets::minimum_balance(asset.clone()) + )); +} + +/// Create the designated fee asset for pool creation. +fn create_fee_asset(caller: &T::AccountId) +where + T::Assets: Create + Mutate, +{ + let fee_asset = T::PoolSetupFeeAsset::get(); + if !T::Assets::asset_exists(fee_asset.clone()) { + assert_ok!(T::Assets::create(fee_asset.clone(), caller.clone(), true, T::Balance::one())); + } + assert_ok!(T::Assets::mint_into( + fee_asset.clone(), + &caller, + T::Assets::minimum_balance(fee_asset) + )); +} + +/// Mint the fee asset for the `caller` sufficient to cover the fee for creating a new pool. +fn mint_setup_fee_asset( + caller: &T::AccountId, + asset1: &T::AssetKind, + asset2: &T::AssetKind, + lp_token: &T::PoolAssetId, +) where + T::Assets: Create + Mutate, +{ + assert_ok!(T::Assets::mint_into( + T::PoolSetupFeeAsset::get(), + &caller, + T::PoolSetupFee::get() + + T::Assets::deposit_required(asset1.clone()) + + T::Assets::deposit_required(asset2.clone()) + + T::PoolAssets::deposit_required(lp_token.clone()) + )); +} + +/// Creates a pool for a given asset pair. +/// +/// This action mints the necessary amounts of the given assets for the `caller` to provide initial +/// liquidity. It returns the LP token ID along with a pair of amounts sufficient for the pool's +/// initial liquidity. +fn create_asset_and_pool( + caller: &T::AccountId, + asset1: &T::AssetKind, + asset2: &T::AssetKind, +) -> (T::PoolAssetId, T::Balance, T::Balance) +where + T::Assets: Create + Mutate, +{ + let (liquidity1, liquidity2) = valid_liquidity_amount::( + T::Assets::minimum_balance(asset1.clone()), + T::Assets::minimum_balance(asset2.clone()), + ); + create_asset::(caller, asset1, liquidity1); + create_asset::(caller, asset2, liquidity2); + let lp_token = AssetConversion::::get_next_pool_asset_id(); + + mint_setup_fee_asset::(caller, asset1, asset2, &lp_token); + + assert_ok!(AssetConversion::::create_pool( + SystemOrigin::Signed(caller.clone()).into(), + Box::new(asset1.clone()), + Box::new(asset2.clone()) + )); + + (lp_token, liquidity1, liquidity2) +} + +fn assert_last_event(generic_event: ::RuntimeEvent) { + let events = frame_system::Pallet::::events(); + let system_event: ::RuntimeEvent = generic_event.into(); + // compare to the last event record + let frame_system::EventRecord { event, .. } = &events[events.len() - 1]; + assert_eq!(event, &system_event); +} + +#[benchmarks(where T::Assets: Create + Mutate, T::PoolAssetId: Into,)] +mod benchmarks { + use super::*; + + #[benchmark] + fn migrate_to_new_account() { + let caller: T::AccountId = whitelisted_caller(); + let (asset1, asset2) = T::BenchmarkHelper::create_pair(0, 1); + + create_fee_asset::(&caller); + let (_, liquidity1, liquidity2) = create_asset_and_pool::(&caller, &asset1, &asset2); + + assert_ok!(AssetConversion::::add_liquidity( + SystemOrigin::Signed(caller.clone()).into(), + Box::new(asset1.clone()), + Box::new(asset2.clone()), + liquidity1, + liquidity2, + T::Balance::one(), + T::Balance::zero(), + caller.clone(), + )); + + #[extrinsic_call] + _(SystemOrigin::Signed(caller.clone()), Box::new(asset1.clone()), Box::new(asset2.clone())); + + let pool_id = T::PoolLocator::pool_id(&asset1, &asset2).unwrap(); + let (prior_account, new_account) = AssetConversionOps::::addresses(&pool_id).unwrap(); + assert_last_event::( + Event::MigratedToNewAccount { pool_id, new_account, prior_account }.into(), + ); + } + + impl_benchmark_test_suite!(AssetConversionOps, crate::mock::new_test_ext(), crate::mock::Test); +} diff --git a/substrate/frame/asset-conversion/ops/src/lib.rs b/substrate/frame/asset-conversion/ops/src/lib.rs new file mode 100644 index 0000000000000000000000000000000000000000..a655a9cb44525fe58bf07f283c0cf3cdf2c9fd42 --- /dev/null +++ b/substrate/frame/asset-conversion/ops/src/lib.rs @@ -0,0 +1,334 @@ +// 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. + +//! # Asset Conversion Operations Suite. +//! +//! This pallet provides operational functionalities for the Asset Conversion pallet, +//! allowing you to perform various migration and one-time-use operations. These operations +//! are designed to facilitate updates and changes to the Asset Conversion pallet without +//! breaking its API. +//! +//! ## Overview +//! +//! This suite allows you to perform the following operations: +//! - Perform migration to update account ID derivation methods for existing pools. The migration +//! operation ensures that the required accounts are created, existing account deposits are +//! transferred, and liquidity is moved to the new accounts. + +#![deny(missing_docs)] +#![cfg_attr(not(feature = "std"), no_std)] + +#[cfg(feature = "runtime-benchmarks")] +mod benchmarking; +#[cfg(test)] +mod mock; +#[cfg(test)] +mod tests; +pub mod weights; +pub use pallet::*; +pub use weights::WeightInfo; + +use frame_support::traits::{ + fungible::{Inspect as FungibleInspect, Mutate as FungibleMutate}, + fungibles::{roles::ResetTeam, Inspect, Mutate, Refund}, + tokens::{Fortitude, Precision, Preservation}, + AccountTouch, +}; +use pallet_asset_conversion::{PoolLocator, Pools}; +use sp_runtime::traits::{TryConvert, Zero}; +use sp_std::boxed::Box; + +#[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: + pallet_asset_conversion::Config< + PoolId = ( + ::AssetKind, + ::AssetKind, + ), + > + frame_system::Config + { + /// Overarching event type. + type RuntimeEvent: From> + IsType<::RuntimeEvent>; + + /// Type previously used to derive the account ID for a pool. Indicates that the pool's + /// liquidity assets are located at this account before the migration. + type PriorAccountIdConverter: for<'a> TryConvert< + &'a (Self::AssetKind, Self::AssetKind), + Self::AccountId, + >; + + /// Retrieves information about an existing deposit for a given account ID and asset from + /// the [`pallet_asset_conversion::Config::Assets`] registry and can initiate the refund. + type AssetsRefund: Refund< + Self::AccountId, + AssetId = Self::AssetKind, + Balance = >::Balance, + >; + + /// Retrieves information about an existing deposit for a given account ID and asset from + /// the [`pallet_asset_conversion::Config::PoolAssets`] registry and can initiate the + /// refund. + type PoolAssetsRefund: Refund< + Self::AccountId, + AssetId = Self::PoolAssetId, + Balance = >::Balance, + >; + + /// Means to reset the team for assets from the + /// [`pallet_asset_conversion::Config::PoolAssets`] registry. + type PoolAssetsTeam: ResetTeam; + + /// Registry of an asset used as an account deposit for the + /// [`pallet_asset_conversion::Config::Assets`] and + /// [`pallet_asset_conversion::Config::PoolAssets`] registries. + type DepositAsset: FungibleMutate; + + /// Weight information for extrinsics in this pallet. + type WeightInfo: WeightInfo; + } + + // Pallet's events. + #[pallet::event] + #[pallet::generate_deposit(pub(super) fn deposit_event)] + pub enum Event { + /// Indicates that a pool has been migrated to the new account ID. + MigratedToNewAccount { + /// Pool's ID. + pool_id: T::PoolId, + /// Pool's prior account ID. + prior_account: T::AccountId, + /// Pool's new account ID. + new_account: T::AccountId, + }, + } + + #[pallet::error] + pub enum Error { + /// Provided asset pair is not supported for pool. + InvalidAssetPair, + /// The pool doesn't exist. + PoolNotFound, + /// Pool's balance cannot be zero. + ZeroBalance, + /// Indicates a partial transfer of balance to the new account during a migration. + PartialTransfer, + } + + /// Pallet's callable functions. + #[pallet::call] + impl Pallet { + /// Migrates an existing pool to a new account ID derivation method for a given asset pair. + /// If the migration is successful, transaction fees are refunded to the caller. + /// + /// Must be signed. + #[pallet::call_index(0)] + #[pallet::weight(::WeightInfo::migrate_to_new_account())] + pub fn migrate_to_new_account( + origin: OriginFor, + asset1: Box, + asset2: Box, + ) -> DispatchResultWithPostInfo { + let _ = ensure_signed(origin)?; + + let pool_id = T::PoolLocator::pool_id(&asset1, &asset2) + .map_err(|_| Error::::InvalidAssetPair)?; + let info = Pools::::get(&pool_id).ok_or(Error::::PoolNotFound)?; + + let (prior_account, new_account) = + Self::addresses(&pool_id).ok_or(Error::::InvalidAssetPair)?; + + let (asset1, asset2) = pool_id.clone(); + + // Assets that must be transferred to the new account id. + let balance1 = T::Assets::total_balance(asset1.clone(), &prior_account); + let balance2 = T::Assets::total_balance(asset2.clone(), &prior_account); + let lp_balance = T::PoolAssets::total_balance(info.lp_token.clone(), &prior_account); + + ensure!(!balance1.is_zero(), Error::::ZeroBalance); + ensure!(!balance2.is_zero(), Error::::ZeroBalance); + ensure!(!lp_balance.is_zero(), Error::::ZeroBalance); + + // Check if a deposit needs to be placed for the new account. If so, mint the + // required deposit amount to the depositor's account to ensure the deposit can be + // provided. Once the deposit from the prior account is returned, the minted assets will + // be burned. Touching the new account is necessary because it's not possible to + // transfer assets to the new account if it's required. Additionally, the deposit cannot + // be refunded from the prior account until its balance is zero. + + let deposit_asset_ed = T::DepositAsset::minimum_balance(); + + if let Some((depositor, deposit)) = + T::AssetsRefund::deposit_held(asset1.clone(), prior_account.clone()) + { + T::DepositAsset::mint_into(&depositor, deposit + deposit_asset_ed)?; + T::Assets::touch(asset1.clone(), &new_account, &depositor)?; + } + + if let Some((depositor, deposit)) = + T::AssetsRefund::deposit_held(asset2.clone(), prior_account.clone()) + { + T::DepositAsset::mint_into(&depositor, deposit + deposit_asset_ed)?; + T::Assets::touch(asset2.clone(), &new_account, &depositor)?; + } + + if let Some((depositor, deposit)) = + T::PoolAssetsRefund::deposit_held(info.lp_token.clone(), prior_account.clone()) + { + T::DepositAsset::mint_into(&depositor, deposit + deposit_asset_ed)?; + T::PoolAssets::touch(info.lp_token.clone(), &new_account, &depositor)?; + } + + // Transfer all pool related assets to the new account. + + ensure!( + balance1 == + T::Assets::transfer( + asset1.clone(), + &prior_account, + &new_account, + balance1, + Preservation::Expendable, + )?, + Error::::PartialTransfer + ); + + ensure!( + balance2 == + T::Assets::transfer( + asset2.clone(), + &prior_account, + &new_account, + balance2, + Preservation::Expendable, + )?, + Error::::PartialTransfer + ); + + ensure!( + lp_balance == + T::PoolAssets::transfer( + info.lp_token.clone(), + &prior_account, + &new_account, + lp_balance, + Preservation::Expendable, + )?, + Error::::PartialTransfer + ); + + // Refund deposits from prior accounts and burn previously minted assets. + + if let Some((depositor, deposit)) = + T::AssetsRefund::deposit_held(asset1.clone(), prior_account.clone()) + { + T::AssetsRefund::refund(asset1.clone(), prior_account.clone())?; + T::DepositAsset::burn_from( + &depositor, + deposit + deposit_asset_ed, + Preservation::Expendable, + Precision::Exact, + Fortitude::Force, + )?; + } + + if let Some((depositor, deposit)) = + T::AssetsRefund::deposit_held(asset2.clone(), prior_account.clone()) + { + T::AssetsRefund::refund(asset2.clone(), prior_account.clone())?; + T::DepositAsset::burn_from( + &depositor, + deposit + deposit_asset_ed, + Preservation::Expendable, + Precision::Exact, + Fortitude::Force, + )?; + } + + if let Some((depositor, deposit)) = + T::PoolAssetsRefund::deposit_held(info.lp_token.clone(), prior_account.clone()) + { + T::PoolAssetsRefund::refund(info.lp_token.clone(), prior_account.clone())?; + T::DepositAsset::burn_from( + &depositor, + deposit + deposit_asset_ed, + Preservation::Expendable, + Precision::Exact, + Fortitude::Force, + )?; + } + + T::PoolAssetsTeam::reset_team( + info.lp_token, + new_account.clone(), + new_account.clone(), + new_account.clone(), + new_account.clone(), + )?; + + Self::deposit_event(Event::MigratedToNewAccount { + pool_id, + prior_account, + new_account, + }); + + Ok(Pays::No.into()) + } + } + + impl Pallet { + /// Returns the prior and new account IDs for a given pool ID. The prior account ID comes + /// first in the tuple. + #[cfg(not(any(test, feature = "runtime-benchmarks")))] + fn addresses(pool_id: &T::PoolId) -> Option<(T::AccountId, T::AccountId)> { + match ( + T::PriorAccountIdConverter::try_convert(pool_id), + T::PoolLocator::address(pool_id), + ) { + (Ok(a), Ok(b)) if a != b => Some((a, b)), + _ => None, + } + } + + /// Returns the prior and new account IDs for a given pool ID. The prior account ID comes + /// first in the tuple. + /// + /// This function is intended for use only in test and benchmark environments. The prior + /// account ID represents the new account ID from [`Config::PoolLocator`], allowing the use + /// of the main pallet's calls to set up a pool with liquidity placed in that account and + /// migrate it to another account, which in this case is the result of + /// [`Config::PriorAccountIdConverter`]. + #[cfg(any(test, feature = "runtime-benchmarks"))] + pub(crate) fn addresses(pool_id: &T::PoolId) -> Option<(T::AccountId, T::AccountId)> { + match ( + T::PoolLocator::address(pool_id), + T::PriorAccountIdConverter::try_convert(pool_id), + ) { + (Ok(a), Ok(b)) if a != b => Some((a, b)), + _ => None, + } + } + } +} diff --git a/substrate/frame/asset-conversion/ops/src/mock.rs b/substrate/frame/asset-conversion/ops/src/mock.rs new file mode 100644 index 0000000000000000000000000000000000000000..9454b3a9ad448af4b47d9fd974e6ec8ad5ed4e59 --- /dev/null +++ b/substrate/frame/asset-conversion/ops/src/mock.rs @@ -0,0 +1,147 @@ +// 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 environment for Asset Conversion Ops pallet. + +use super::*; +use crate as pallet_asset_conversion_ops; +use core::default::Default; +use frame_support::{ + construct_runtime, derive_impl, + instances::{Instance1, Instance2}, + ord_parameter_types, parameter_types, + traits::{ + tokens::{ + fungible::{NativeFromLeft, NativeOrWithId, UnionOf}, + imbalance::ResolveAssetTo, + }, + AsEnsureOriginWithArg, ConstU32, ConstU64, + }, + PalletId, +}; +use frame_system::{EnsureSigned, EnsureSignedBy}; +use pallet_asset_conversion::{self, AccountIdConverter, AccountIdConverterNoSeed, Ascending}; +use sp_arithmetic::Permill; +use sp_runtime::{traits::AccountIdConversion, BuildStorage}; + +type Block = frame_system::mocking::MockBlock; + +construct_runtime!( + pub enum Test + { + System: frame_system, + Balances: pallet_balances, + Assets: pallet_assets::, + PoolAssets: pallet_assets::, + AssetConversion: pallet_asset_conversion, + AssetConversionOps: pallet_asset_conversion_ops, + } +); + +#[derive_impl(frame_system::config_preludes::TestDefaultConfig as frame_system::DefaultConfig)] +impl frame_system::Config for Test { + type Block = Block; + type AccountData = pallet_balances::AccountData; +} + +#[derive_impl(pallet_balances::config_preludes::TestDefaultConfig)] +impl pallet_balances::Config for Test { + type ReserveIdentifier = [u8; 8]; + type AccountStore = System; +} + +#[derive_impl(pallet_assets::config_preludes::TestDefaultConfig)] +impl pallet_assets::Config for Test { + type Currency = Balances; + type CreateOrigin = AsEnsureOriginWithArg>; + type ForceOrigin = frame_system::EnsureRoot; + type Freezer = (); +} + +#[derive_impl(pallet_assets::config_preludes::TestDefaultConfig)] +impl pallet_assets::Config for Test { + type Currency = Balances; + type CreateOrigin = + AsEnsureOriginWithArg>; + type ForceOrigin = frame_system::EnsureRoot; + type Freezer = (); +} + +parameter_types! { + pub const AssetConversionPalletId: PalletId = PalletId(*b"py/ascon"); + pub const Native: NativeOrWithId = NativeOrWithId::Native; + pub storage LiquidityWithdrawalFee: Permill = Permill::from_percent(0); +} + +ord_parameter_types! { + pub const AssetConversionOrigin: u64 = AccountIdConversion::::into_account_truncating(&AssetConversionPalletId::get()); +} + +pub type NativeAndAssets = UnionOf, u64>; +pub type PoolIdToAccountId = + AccountIdConverter, NativeOrWithId)>; +pub type AscendingLocator = Ascending, PoolIdToAccountId>; + +impl pallet_asset_conversion::Config for Test { + type RuntimeEvent = RuntimeEvent; + type Balance = ::Balance; + type HigherPrecisionBalance = sp_core::U256; + type AssetKind = NativeOrWithId; + type Assets = NativeAndAssets; + type PoolId = (Self::AssetKind, Self::AssetKind); + type PoolLocator = AscendingLocator; + type PoolAssetId = u32; + type PoolAssets = PoolAssets; + type PoolSetupFee = ConstU64<100>; + type PoolSetupFeeAsset = Native; + type PoolSetupFeeTarget = ResolveAssetTo; + type PalletId = AssetConversionPalletId; + type WeightInfo = (); + type LPFee = ConstU32<3>; + type LiquidityWithdrawalFee = LiquidityWithdrawalFee; + type MaxSwapPathLength = ConstU32<4>; + type MintMinLiquidity = ConstU64<100>; + #[cfg(feature = "runtime-benchmarks")] + type BenchmarkHelper = (); +} + +pub type OldPoolIdToAccountId = + AccountIdConverterNoSeed<(NativeOrWithId, NativeOrWithId)>; + +impl pallet_asset_conversion_ops::Config for Test { + type RuntimeEvent = RuntimeEvent; + type PriorAccountIdConverter = OldPoolIdToAccountId; + type AssetsRefund = NativeAndAssets; + type PoolAssetsRefund = PoolAssets; + type PoolAssetsTeam = PoolAssets; + type DepositAsset = Balances; + type WeightInfo = (); +} + +pub(crate) fn new_test_ext() -> sp_io::TestExternalities { + let mut t = frame_system::GenesisConfig::::default().build_storage().unwrap(); + + pallet_balances::GenesisConfig:: { + balances: vec![(1, 10000), (2, 20000), (3, 30000), (4, 40000)], + } + .assimilate_storage(&mut t) + .unwrap(); + + let mut ext = sp_io::TestExternalities::new(t); + ext.execute_with(|| System::set_block_number(1)); + ext +} diff --git a/substrate/frame/asset-conversion/ops/src/tests.rs b/substrate/frame/asset-conversion/ops/src/tests.rs new file mode 100644 index 0000000000000000000000000000000000000000..84bbe6336747316967935737ed22f0794d21cdda --- /dev/null +++ b/substrate/frame/asset-conversion/ops/src/tests.rs @@ -0,0 +1,308 @@ +// 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. + +//! Asset Conversion Ops pallet tests. + +use crate::{mock::*, *}; +use frame_support::{ + assert_noop, assert_ok, + traits::{ + fungible::{Inspect as FungibleInspect, NativeOrWithId}, + fungibles::{Create, Inspect}, + Incrementable, + }, +}; + +#[test] +fn migrate_pool_account_id_with_native() { + new_test_ext().execute_with(|| { + type PoolLocator = ::PoolLocator; + let user = 1; + let token_1 = NativeOrWithId::Native; + let token_2 = NativeOrWithId::WithId(2); + let pool_id = PoolLocator::pool_id(&token_1, &token_2).unwrap(); + let lp_token = + ::PoolAssetId::initial_value().unwrap(); + + // setup pool and provide some liquidity. + assert_ok!(NativeAndAssets::create(token_2.clone(), user, false, 1)); + + assert_ok!(AssetConversion::create_pool( + RuntimeOrigin::signed(user), + Box::new(token_1.clone()), + Box::new(token_2.clone()) + )); + + let ed = Balances::minimum_balance(); + assert_ok!(Balances::force_set_balance(RuntimeOrigin::root(), user, 10000 * 2 + ed)); + assert_ok!(Assets::mint(RuntimeOrigin::signed(user), 2, user, 1000)); + + assert_ok!(AssetConversion::add_liquidity( + RuntimeOrigin::signed(user), + Box::new(token_1.clone()), + Box::new(token_2.clone()), + 10000, + 10, + 10000, + 10, + user, + )); + + // assert user's balance. + assert_eq!(NativeAndAssets::balance(token_1.clone(), &user), 10000 + ed); + assert_eq!(NativeAndAssets::balance(token_2.clone(), &user), 1000 - 10); + assert_eq!(PoolAssets::balance(lp_token, &user), 216); + + // record total issuances before migration. + let total_issuance_token1 = NativeAndAssets::total_issuance(token_1.clone()); + let total_issuance_token2 = NativeAndAssets::total_issuance(token_2.clone()); + let total_issuance_lp_token = PoolAssets::total_issuance(lp_token); + + let pool_account = PoolLocator::address(&pool_id).unwrap(); + let (prior_pool_account, new_pool_account) = + AssetConversionOps::addresses(&pool_id).unwrap(); + assert_eq!(pool_account, prior_pool_account); + + // assert pool's balances before migration. + assert_eq!(NativeAndAssets::balance(token_1.clone(), &prior_pool_account), 10000); + assert_eq!(NativeAndAssets::balance(token_2.clone(), &prior_pool_account), 10); + assert_eq!(PoolAssets::balance(lp_token, &prior_pool_account), 100); + + // migrate. + assert_ok!(AssetConversionOps::migrate_to_new_account( + RuntimeOrigin::signed(user), + Box::new(token_1.clone()), + Box::new(token_2.clone()), + )); + + // assert user's balance has not changed. + assert_eq!(NativeAndAssets::balance(token_1.clone(), &user), 10000 + ed); + assert_eq!(NativeAndAssets::balance(token_2.clone(), &user), 1000 - 10); + assert_eq!(PoolAssets::balance(lp_token, &user), 216); + + // assert pool's balance on new account id is same as on prior account id. + assert_eq!(NativeAndAssets::balance(token_1.clone(), &new_pool_account), 10000); + assert_eq!(NativeAndAssets::balance(token_2.clone(), &new_pool_account), 10); + assert_eq!(PoolAssets::balance(lp_token, &new_pool_account), 100); + + // assert pool's balance on prior account id is zero. + assert_eq!(NativeAndAssets::balance(token_1.clone(), &prior_pool_account), 0); + assert_eq!(NativeAndAssets::balance(token_2.clone(), &prior_pool_account), 0); + assert_eq!(PoolAssets::balance(lp_token, &prior_pool_account), 0); + + // assert total issuance has not changed. + assert_eq!(total_issuance_token1, NativeAndAssets::total_issuance(token_1)); + assert_eq!(total_issuance_token2, NativeAndAssets::total_issuance(token_2)); + assert_eq!(total_issuance_lp_token, PoolAssets::total_issuance(lp_token)); + }); +} + +#[test] +fn migrate_pool_account_id_with_insufficient_assets() { + new_test_ext().execute_with(|| { + type PoolLocator = ::PoolLocator; + let user = 1; + let token_1 = NativeOrWithId::WithId(1); + let token_2 = NativeOrWithId::WithId(2); + let pool_id = PoolLocator::pool_id(&token_1, &token_2).unwrap(); + let lp_token = + ::PoolAssetId::initial_value().unwrap(); + + // setup pool and provide some liquidity. + assert_ok!(NativeAndAssets::create(token_1.clone(), user, false, 1)); + assert_ok!(NativeAndAssets::create(token_2.clone(), user, false, 1)); + + assert_ok!(AssetConversion::create_pool( + RuntimeOrigin::signed(user), + Box::new(token_1.clone()), + Box::new(token_2.clone()) + )); + + assert_ok!(Assets::mint(RuntimeOrigin::signed(user), 1, user, 20000)); + assert_ok!(Assets::mint(RuntimeOrigin::signed(user), 2, user, 1000)); + + assert_ok!(AssetConversion::add_liquidity( + RuntimeOrigin::signed(user), + Box::new(token_1.clone()), + Box::new(token_2.clone()), + 10000, + 10, + 10000, + 10, + user, + )); + + // assert user's balance. + assert_eq!(NativeAndAssets::balance(token_1.clone(), &user), 10000); + assert_eq!(NativeAndAssets::balance(token_2.clone(), &user), 1000 - 10); + assert_eq!(PoolAssets::balance(lp_token, &user), 216); + + // record total issuances before migration. + let total_issuance_token1 = NativeAndAssets::total_issuance(token_1.clone()); + let total_issuance_token2 = NativeAndAssets::total_issuance(token_2.clone()); + let total_issuance_lp_token = PoolAssets::total_issuance(lp_token); + + let pool_account = PoolLocator::address(&pool_id).unwrap(); + let (prior_pool_account, new_pool_account) = + AssetConversionOps::addresses(&pool_id).unwrap(); + assert_eq!(pool_account, prior_pool_account); + + // assert pool's balances before migration. + assert_eq!(NativeAndAssets::balance(token_1.clone(), &prior_pool_account), 10000); + assert_eq!(NativeAndAssets::balance(token_2.clone(), &prior_pool_account), 10); + assert_eq!(PoolAssets::balance(lp_token, &prior_pool_account), 100); + + // migrate. + assert_ok!(AssetConversionOps::migrate_to_new_account( + RuntimeOrigin::signed(user), + Box::new(token_1.clone()), + Box::new(token_2.clone()), + )); + + // assert user's balance has not changed. + assert_eq!(NativeAndAssets::balance(token_1.clone(), &user), 10000); + assert_eq!(NativeAndAssets::balance(token_2.clone(), &user), 1000 - 10); + assert_eq!(PoolAssets::balance(lp_token, &user), 216); + + // assert pool's balance on new account id is same as on prior account id. + assert_eq!(NativeAndAssets::balance(token_1.clone(), &new_pool_account), 10000); + assert_eq!(NativeAndAssets::balance(token_2.clone(), &new_pool_account), 10); + assert_eq!(PoolAssets::balance(lp_token, &new_pool_account), 100); + + // assert pool's balance on prior account id is zero. + assert_eq!(NativeAndAssets::balance(token_1.clone(), &prior_pool_account), 0); + assert_eq!(NativeAndAssets::balance(token_2.clone(), &prior_pool_account), 0); + assert_eq!(PoolAssets::balance(lp_token, &prior_pool_account), 0); + + // assert total issuance has not changed. + assert_eq!(total_issuance_token1, NativeAndAssets::total_issuance(token_1)); + assert_eq!(total_issuance_token2, NativeAndAssets::total_issuance(token_2)); + assert_eq!(total_issuance_lp_token, PoolAssets::total_issuance(lp_token)); + }); +} + +#[test] +fn migrate_pool_account_id_with_sufficient_assets() { + new_test_ext().execute_with(|| { + type PoolLocator = ::PoolLocator; + let user = 1; + let token_1 = NativeOrWithId::WithId(1); + let token_2 = NativeOrWithId::WithId(2); + let pool_id = PoolLocator::pool_id(&token_1, &token_2).unwrap(); + let lp_token = + ::PoolAssetId::initial_value().unwrap(); + + // setup pool and provide some liquidity. + assert_ok!(NativeAndAssets::create(token_1.clone(), user, true, 1)); + assert_ok!(NativeAndAssets::create(token_2.clone(), user, true, 1)); + + assert_ok!(AssetConversion::create_pool( + RuntimeOrigin::signed(user), + Box::new(token_1.clone()), + Box::new(token_2.clone()) + )); + + assert_ok!(Assets::mint(RuntimeOrigin::signed(user), 1, user, 20000)); + assert_ok!(Assets::mint(RuntimeOrigin::signed(user), 2, user, 1000)); + + assert_ok!(AssetConversion::add_liquidity( + RuntimeOrigin::signed(user), + Box::new(token_1.clone()), + Box::new(token_2.clone()), + 10000, + 10, + 10000, + 10, + user, + )); + + // assert user's balance. + assert_eq!(NativeAndAssets::balance(token_1.clone(), &user), 10000); + assert_eq!(NativeAndAssets::balance(token_2.clone(), &user), 1000 - 10); + assert_eq!(PoolAssets::balance(lp_token, &user), 216); + + // record total issuances before migration. + let total_issuance_token1 = NativeAndAssets::total_issuance(token_1.clone()); + let total_issuance_token2 = NativeAndAssets::total_issuance(token_2.clone()); + let total_issuance_lp_token = PoolAssets::total_issuance(lp_token); + + let pool_account = PoolLocator::address(&pool_id).unwrap(); + let (prior_pool_account, new_pool_account) = + AssetConversionOps::addresses(&pool_id).unwrap(); + assert_eq!(pool_account, prior_pool_account); + + // assert pool's balances before migration. + assert_eq!(NativeAndAssets::balance(token_1.clone(), &prior_pool_account), 10000); + assert_eq!(NativeAndAssets::balance(token_2.clone(), &prior_pool_account), 10); + assert_eq!(PoolAssets::balance(lp_token, &prior_pool_account), 100); + + // migrate. + assert_ok!(AssetConversionOps::migrate_to_new_account( + RuntimeOrigin::signed(user), + Box::new(token_1.clone()), + Box::new(token_2.clone()), + )); + + // assert user's balance has not changed. + assert_eq!(NativeAndAssets::balance(token_1.clone(), &user), 10000); + assert_eq!(NativeAndAssets::balance(token_2.clone(), &user), 1000 - 10); + assert_eq!(PoolAssets::balance(lp_token, &user), 216); + + // assert pool's balance on new account id is same as on prior account id. + assert_eq!(NativeAndAssets::balance(token_1.clone(), &new_pool_account), 10000); + assert_eq!(NativeAndAssets::balance(token_2.clone(), &new_pool_account), 10); + assert_eq!(PoolAssets::balance(lp_token, &new_pool_account), 100); + + // assert pool's balance on prior account id is zero. + assert_eq!(NativeAndAssets::balance(token_1.clone(), &prior_pool_account), 0); + assert_eq!(NativeAndAssets::balance(token_2.clone(), &prior_pool_account), 0); + assert_eq!(PoolAssets::balance(lp_token, &prior_pool_account), 0); + + // assert total issuance has not changed. + assert_eq!(total_issuance_token1, NativeAndAssets::total_issuance(token_1)); + assert_eq!(total_issuance_token2, NativeAndAssets::total_issuance(token_2)); + assert_eq!(total_issuance_lp_token, PoolAssets::total_issuance(lp_token)); + }); +} + +#[test] +fn migrate_empty_pool_account_id() { + new_test_ext().execute_with(|| { + let user = 1; + let token_1 = NativeOrWithId::Native; + let token_2 = NativeOrWithId::WithId(2); + + // setup pool and provide some liquidity. + assert_ok!(NativeAndAssets::create(token_2.clone(), user, false, 1)); + + assert_ok!(AssetConversion::create_pool( + RuntimeOrigin::signed(user), + Box::new(token_1.clone()), + Box::new(token_2.clone()) + )); + + // migrate. + assert_noop!( + AssetConversionOps::migrate_to_new_account( + RuntimeOrigin::signed(user), + Box::new(token_1.clone()), + Box::new(token_2.clone()), + ), + Error::::ZeroBalance + ); + }); +} diff --git a/substrate/frame/asset-conversion/ops/src/weights.rs b/substrate/frame/asset-conversion/ops/src/weights.rs new file mode 100644 index 0000000000000000000000000000000000000000..9e7379c50156e4f7bcb8a4a68881e6250c3600fb --- /dev/null +++ b/substrate/frame/asset-conversion/ops/src/weights.rs @@ -0,0 +1,104 @@ +// 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_ops` +//! +//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 32.0.0 +//! DATE: 2024-04-13, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! WORST CASE MAP SIZE: `1000000` +//! HOSTNAME: `runner-anb7yjbi-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 +// --steps=50 +// --repeat=20 +// --extrinsic=* +// --wasm-execution=compiled +// --heap-pages=4096 +// --json-file=/builds/parity/mirrors/polkadot-sdk/.git/.artifacts/bench.json +// --pallet=pallet_asset_conversion_ops +// --chain=dev +// --header=./substrate/HEADER-APACHE2 +// --output=./substrate/frame/asset-conversion-ops/src/weights.rs +// --template=./substrate/.maintain/frame-weight-template.hbs + +#![cfg_attr(rustfmt, rustfmt_skip)] +#![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_ops`. +pub trait WeightInfo { + fn migrate_to_new_account() -> Weight; +} + +/// Weights for `pallet_asset_conversion_ops` using the Substrate node and recommended hardware. +pub struct SubstrateWeight(PhantomData); +impl WeightInfo for SubstrateWeight { + /// Storage: `AssetConversion::Pools` (r:1 w:0) + /// Proof: `AssetConversion::Pools` (`max_values`: None, `max_size`: Some(30), added: 2505, mode: `MaxEncodedLen`) + /// Storage: `Assets::Account` (r:4 w:4) + /// Proof: `Assets::Account` (`max_values`: None, `max_size`: Some(134), added: 2609, mode: `MaxEncodedLen`) + /// Storage: `PoolAssets::Account` (r:2 w:2) + /// Proof: `PoolAssets::Account` (`max_values`: None, `max_size`: Some(134), added: 2609, mode: `MaxEncodedLen`) + /// Storage: `PoolAssets::Asset` (r:1 w:1) + /// Proof: `PoolAssets::Asset` (`max_values`: None, `max_size`: Some(210), added: 2685, mode: `MaxEncodedLen`) + /// Storage: `Assets::Asset` (r:2 w:2) + /// Proof: `Assets::Asset` (`max_values`: None, `max_size`: Some(210), added: 2685, mode: `MaxEncodedLen`) + /// Storage: `System::Account` (r:2 w:2) + /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) + fn migrate_to_new_account() -> Weight { + // Proof Size summary in bytes: + // Measured: `1762` + // Estimated: `11426` + // Minimum execution time: 223_850_000 picoseconds. + Weight::from_parts(231_676_000, 11426) + .saturating_add(T::DbWeight::get().reads(12_u64)) + .saturating_add(T::DbWeight::get().writes(11_u64)) + } +} + +// For backwards compatibility and tests. +impl WeightInfo for () { + /// Storage: `AssetConversion::Pools` (r:1 w:0) + /// Proof: `AssetConversion::Pools` (`max_values`: None, `max_size`: Some(30), added: 2505, mode: `MaxEncodedLen`) + /// Storage: `Assets::Account` (r:4 w:4) + /// Proof: `Assets::Account` (`max_values`: None, `max_size`: Some(134), added: 2609, mode: `MaxEncodedLen`) + /// Storage: `PoolAssets::Account` (r:2 w:2) + /// Proof: `PoolAssets::Account` (`max_values`: None, `max_size`: Some(134), added: 2609, mode: `MaxEncodedLen`) + /// Storage: `PoolAssets::Asset` (r:1 w:1) + /// Proof: `PoolAssets::Asset` (`max_values`: None, `max_size`: Some(210), added: 2685, mode: `MaxEncodedLen`) + /// Storage: `Assets::Asset` (r:2 w:2) + /// Proof: `Assets::Asset` (`max_values`: None, `max_size`: Some(210), added: 2685, mode: `MaxEncodedLen`) + /// Storage: `System::Account` (r:2 w:2) + /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) + fn migrate_to_new_account() -> Weight { + // Proof Size summary in bytes: + // Measured: `1762` + // Estimated: `11426` + // Minimum execution time: 223_850_000 picoseconds. + Weight::from_parts(231_676_000, 11426) + .saturating_add(RocksDbWeight::get().reads(12_u64)) + .saturating_add(RocksDbWeight::get().writes(11_u64)) + } +} diff --git a/substrate/frame/asset-conversion/src/benchmarking.rs b/substrate/frame/asset-conversion/src/benchmarking.rs index f0e02c802ad8e5a923cb9801c33c5539e9bd58a6..c5f68476b1d0a620425719877843b9a276a9f08e 100644 --- a/substrate/frame/asset-conversion/src/benchmarking.rs +++ b/substrate/frame/asset-conversion/src/benchmarking.rs @@ -24,7 +24,7 @@ use frame_support::{ assert_ok, traits::{ fungible::NativeOrWithId, - fungibles::{Create, Inspect, Mutate}, + fungibles::{Create, Inspect, Mutate, Refund}, }, }; use frame_system::RawOrigin as SystemOrigin; @@ -75,12 +75,21 @@ where } /// Create the `asset` and mint the `amount` for the `caller`. -fn create_asset(caller: &T::AccountId, asset: &T::AssetKind, amount: T::Balance) -where +fn create_asset( + caller: &T::AccountId, + asset: &T::AssetKind, + amount: T::Balance, + is_sufficient: bool, +) where T::Assets: Create + Mutate, { if !T::Assets::asset_exists(asset.clone()) { - assert_ok!(T::Assets::create(asset.clone(), caller.clone(), true, T::Balance::one())); + assert_ok!(T::Assets::create( + asset.clone(), + caller.clone(), + is_sufficient, + T::Balance::one() + )); } assert_ok!(T::Assets::mint_into( asset.clone(), @@ -141,8 +150,8 @@ where T::Assets::minimum_balance(asset1.clone()), T::Assets::minimum_balance(asset2.clone()), ); - create_asset::(caller, asset1, liquidity1); - create_asset::(caller, asset2, liquidity2); + create_asset::(caller, asset1, liquidity1, true); + create_asset::(caller, asset2, liquidity2, true); let lp_token = AssetConversion::::get_next_pool_asset_id(); mint_setup_fee_asset::(caller, asset1, asset2, &lp_token); @@ -172,8 +181,8 @@ mod benchmarks { fn create_pool() { let caller: T::AccountId = whitelisted_caller(); let (asset1, asset2) = T::BenchmarkHelper::create_pair(0, 1); - create_asset::(&caller, &asset1, T::Assets::minimum_balance(asset1.clone())); - create_asset::(&caller, &asset2, T::Assets::minimum_balance(asset2.clone())); + create_asset::(&caller, &asset1, T::Assets::minimum_balance(asset1.clone()), true); + create_asset::(&caller, &asset2, T::Assets::minimum_balance(asset2.clone()), true); let lp_token = AssetConversion::::get_next_pool_asset_id(); create_fee_asset::(&caller); @@ -358,5 +367,47 @@ mod benchmarks { assert_eq!(actual_balance, init_caller_balance + T::Balance::one()); } + #[benchmark] + fn touch(n: Linear<0, 3>) { + let caller: T::AccountId = whitelisted_caller(); + let (asset1, asset2) = T::BenchmarkHelper::create_pair(0, 1); + let pool_id = T::PoolLocator::pool_id(&asset1, &asset2).unwrap(); + let pool_account = T::PoolLocator::address(&pool_id).unwrap(); + + create_fee_asset::(&caller); + create_asset::(&caller, &asset1, ::Balance::one(), false); + create_asset::(&caller, &asset2, ::Balance::one(), false); + let lp_token = AssetConversion::::get_next_pool_asset_id(); + mint_setup_fee_asset::(&caller, &asset1, &asset2, &lp_token); + + assert_ok!(AssetConversion::::create_pool( + SystemOrigin::Signed(caller.clone()).into(), + Box::new(asset1.clone()), + Box::new(asset2.clone()) + )); + + if n > 0 && + ::Assets::deposit_held(asset1.clone(), pool_account.clone()).is_some() + { + let _ = ::Assets::refund(asset1.clone(), pool_account.clone()); + } + if n > 1 && + ::Assets::deposit_held(asset2.clone(), pool_account.clone()).is_some() + { + let _ = ::Assets::refund(asset2.clone(), pool_account.clone()); + } + if n > 2 && + ::PoolAssets::deposit_held(lp_token.clone(), pool_account.clone()) + .is_some() + { + let _ = ::PoolAssets::refund(lp_token, pool_account); + } + + #[extrinsic_call] + _(SystemOrigin::Signed(caller.clone()), Box::new(asset1.clone()), Box::new(asset2.clone())); + + assert_last_event::(Event::Touched { pool_id, who: caller }.into()); + } + impl_benchmark_test_suite!(AssetConversion, crate::mock::new_test_ext(), crate::mock::Test); } diff --git a/substrate/frame/asset-conversion/src/lib.rs b/substrate/frame/asset-conversion/src/lib.rs index 0bf73e8809cfb3cb305716b8561846ff9a1ed631..62acb693efb1c1e36bf22ad0530649f796a0d5a7 100644 --- a/substrate/frame/asset-conversion/src/lib.rs +++ b/substrate/frame/asset-conversion/src/lib.rs @@ -98,7 +98,10 @@ use sp_std::{boxed::Box, collections::btree_set::BTreeSet, vec::Vec}; #[frame_support::pallet] pub mod pallet { use super::*; - use frame_support::pallet_prelude::*; + use frame_support::{ + pallet_prelude::{DispatchResult, *}, + traits::fungibles::Refund, + }; use frame_system::pallet_prelude::*; use sp_arithmetic::{traits::Unsigned, Permill}; @@ -130,7 +133,8 @@ pub mod pallet { type Assets: Inspect + Mutate + AccountTouch - + Balanced; + + Balanced + + Refund; /// Liquidity pool identifier. type PoolId: Parameter + MaxEncodedLen + Ord; @@ -149,7 +153,8 @@ pub mod pallet { type PoolAssets: Inspect + Create + Mutate - + AccountTouch; + + AccountTouch + + Refund; /// A % the liquidity providers will take of every swap. Represents 10ths of a percent. #[pallet::constant] @@ -281,6 +286,13 @@ pub mod pallet { /// E.g. (A, amount_in) -> (Dot, amount_out) -> (B, amount_out) path: BalancePath, }, + /// Pool has been touched in order to fulfill operational requirements. + Touched { + /// The ID of the pool. + pool_id: T::PoolId, + /// The account initiating the touch. + who: T::AccountId, + }, } #[pallet::error] @@ -391,7 +403,9 @@ pub mod pallet { NextPoolAssetId::::set(Some(next_lp_token_id)); T::PoolAssets::create(lp_token.clone(), pool_account.clone(), false, 1u32.into())?; - T::PoolAssets::touch(lp_token.clone(), &pool_account, &sender)?; + if T::PoolAssets::should_touch(lp_token.clone(), &pool_account) { + T::PoolAssets::touch(lp_token.clone(), &pool_account, &sender)? + }; let pool_info = PoolInfo { lp_token: lp_token.clone() }; Pools::::insert(pool_id.clone(), pool_info); @@ -582,7 +596,14 @@ pub mod pallet { ); // burn the provided lp token amount that includes the fee - T::PoolAssets::burn_from(pool.lp_token.clone(), &sender, lp_token_burn, Exact, Polite)?; + T::PoolAssets::burn_from( + pool.lp_token.clone(), + &sender, + lp_token_burn, + Expendable, + Exact, + Polite, + )?; T::Assets::transfer(*asset1, &pool_account, &withdraw_to, amount1, Expendable)?; T::Assets::transfer(*asset2, &pool_account, &withdraw_to, amount2, Expendable)?; @@ -656,6 +677,49 @@ pub mod pallet { )?; Ok(()) } + + /// Touch an existing pool to fulfill prerequisites before providing liquidity, such as + /// ensuring that the pool's accounts are in place. It is typically useful when a pool + /// creator removes the pool's accounts and does not provide a liquidity. This action may + /// involve holding assets from the caller as a deposit for creating the pool's accounts. + /// + /// The origin must be Signed. + /// + /// - `asset1`: The asset ID of an existing pool with a pair (asset1, asset2). + /// - `asset2`: The asset ID of an existing pool with a pair (asset1, asset2). + /// + /// Emits `Touched` event when successful. + #[pallet::call_index(5)] + #[pallet::weight(T::WeightInfo::touch(3))] + pub fn touch( + origin: OriginFor, + asset1: Box, + asset2: Box, + ) -> DispatchResultWithPostInfo { + let who = ensure_signed(origin)?; + + let pool_id = T::PoolLocator::pool_id(&asset1, &asset2) + .map_err(|_| Error::::InvalidAssetPair)?; + let pool = Pools::::get(&pool_id).ok_or(Error::::PoolNotFound)?; + let pool_account = + T::PoolLocator::address(&pool_id).map_err(|_| Error::::InvalidAssetPair)?; + + let mut refunds_number: u32 = 0; + if T::Assets::should_touch(*asset1.clone(), &pool_account) { + T::Assets::touch(*asset1, &pool_account, &who)?; + refunds_number += 1; + } + if T::Assets::should_touch(*asset2.clone(), &pool_account) { + T::Assets::touch(*asset2, &pool_account, &who)?; + refunds_number += 1; + } + if T::PoolAssets::should_touch(pool.lp_token.clone(), &pool_account) { + T::PoolAssets::touch(pool.lp_token, &pool_account, &who)?; + refunds_number += 1; + } + Self::deposit_event(Event::Touched { pool_id, who }); + Ok(Some(T::WeightInfo::touch(refunds_number)).into()) + } } impl Pallet { diff --git a/substrate/frame/asset-conversion/src/mock.rs b/substrate/frame/asset-conversion/src/mock.rs index 4591b87c1867862e87a16e86c0d96a060bd1b7ff..477866e0051bc43207d1fb728380e5f84258964f 100644 --- a/substrate/frame/asset-conversion/src/mock.rs +++ b/substrate/frame/asset-conversion/src/mock.rs @@ -137,8 +137,11 @@ ord_parameter_types! { } pub type NativeAndAssets = UnionOf, u128>; -pub type AscendingLocator = Ascending>; -pub type WithFirstAssetLocator = WithFirstAsset>; +pub type PoolIdToAccountId = + AccountIdConverter, NativeOrWithId)>; +pub type AscendingLocator = Ascending, PoolIdToAccountId>; +pub type WithFirstAssetLocator = + WithFirstAsset, PoolIdToAccountId>; impl Config for Test { type RuntimeEvent = RuntimeEvent; diff --git a/substrate/frame/asset-conversion/src/types.rs b/substrate/frame/asset-conversion/src/types.rs index 5ee81c2012de226baf6aafbda0e2ec9a380cc1e2..27c0e8e68805ea7716ed7371aeed532be906fa47 100644 --- a/substrate/frame/asset-conversion/src/types.rs +++ b/substrate/frame/asset-conversion/src/types.rs @@ -19,6 +19,7 @@ use super::*; use codec::{Decode, Encode, MaxEncodedLen}; use core::marker::PhantomData; use scale_info::TypeInfo; +use sp_runtime::traits::TryConvert; /// Represents a swap path with associated asset amounts indicating how much of the asset needs to /// be deposited to get the following asset's amount withdrawn (this is inclusive of fees). @@ -68,49 +69,59 @@ pub trait PoolLocator { /// /// The `PoolId` is represented as a tuple of `AssetKind`s with `FirstAsset` always positioned as /// the first element. -pub struct WithFirstAsset( - PhantomData<(FirstAsset, AccountId, AssetKind)>, +pub struct WithFirstAsset( + PhantomData<(FirstAsset, AccountId, AssetKind, AccountIdConverter)>, ); -impl PoolLocator - for WithFirstAsset +impl + PoolLocator + for WithFirstAsset where AssetKind: Eq + Clone + Encode, AccountId: Decode, FirstAsset: Get, + AccountIdConverter: for<'a> TryConvert<&'a (AssetKind, AssetKind), AccountId>, { fn pool_id(asset1: &AssetKind, asset2: &AssetKind) -> Result<(AssetKind, AssetKind), ()> { + if asset1 == asset2 { + return Err(()); + } let first = FirstAsset::get(); - match true { - _ if asset1 == asset2 => Err(()), - _ if first == *asset1 => Ok((first, asset2.clone())), - _ if first == *asset2 => Ok((first, asset1.clone())), - _ => Err(()), + if first == *asset1 { + Ok((first, asset2.clone())) + } else if first == *asset2 { + Ok((first, asset1.clone())) + } else { + Err(()) } } fn address(id: &(AssetKind, AssetKind)) -> Result { - let encoded = sp_io::hashing::blake2_256(&Encode::encode(id)[..]); - Decode::decode(&mut TrailingZeroInput::new(encoded.as_ref())).map_err(|_| ()) + AccountIdConverter::try_convert(id).map_err(|_| ()) } } /// Pool locator where the `PoolId` is a tuple of `AssetKind`s arranged in ascending order. -pub struct Ascending(PhantomData<(AccountId, AssetKind)>); -impl PoolLocator - for Ascending +pub struct Ascending( + PhantomData<(AccountId, AssetKind, AccountIdConverter)>, +); +impl + PoolLocator + for Ascending where AssetKind: Ord + Clone + Encode, AccountId: Decode, + AccountIdConverter: for<'a> TryConvert<&'a (AssetKind, AssetKind), AccountId>, { fn pool_id(asset1: &AssetKind, asset2: &AssetKind) -> Result<(AssetKind, AssetKind), ()> { - match true { - _ if asset1 > asset2 => Ok((asset2.clone(), asset1.clone())), - _ if asset1 < asset2 => Ok((asset1.clone(), asset2.clone())), - _ => Err(()), + if asset1 > asset2 { + Ok((asset2.clone(), asset1.clone())) + } else if asset1 < asset2 { + Ok((asset1.clone(), asset2.clone())) + } else { + Err(()) } } fn address(id: &(AssetKind, AssetKind)) -> Result { - let encoded = sp_io::hashing::blake2_256(&Encode::encode(id)[..]); - Decode::decode(&mut TrailingZeroInput::new(encoded.as_ref())).map_err(|_| ()) + AccountIdConverter::try_convert(id).map_err(|_| ()) } } @@ -131,3 +142,30 @@ where First::address(id).or(Second::address(id)) } } + +/// `PoolId` to `AccountId` conversion. +pub struct AccountIdConverter(PhantomData<(Seed, PoolId)>); +impl TryConvert<&PoolId, AccountId> for AccountIdConverter +where + PoolId: Encode, + AccountId: Decode, + Seed: Get, +{ + fn try_convert(id: &PoolId) -> Result { + sp_io::hashing::blake2_256(&Encode::encode(&(Seed::get(), id))[..]) + .using_encoded(|e| Decode::decode(&mut TrailingZeroInput::new(e)).map_err(|_| id)) + } +} + +/// `PoolId` to `AccountId` conversion without an addition arguments to the seed. +pub struct AccountIdConverterNoSeed(PhantomData); +impl TryConvert<&PoolId, AccountId> for AccountIdConverterNoSeed +where + PoolId: Encode, + AccountId: Decode, +{ + fn try_convert(id: &PoolId) -> Result { + sp_io::hashing::blake2_256(&Encode::encode(id)[..]) + .using_encoded(|e| Decode::decode(&mut TrailingZeroInput::new(e)).map_err(|_| id)) + } +} diff --git a/substrate/frame/asset-conversion/src/weights.rs b/substrate/frame/asset-conversion/src/weights.rs index 212f56073f942bc4964ea7af2a5dde80fed1a4a5..9aea19dbf57c6adf2936d4141987d198cd944fb7 100644 --- a/substrate/frame/asset-conversion/src/weights.rs +++ b/substrate/frame/asset-conversion/src/weights.rs @@ -18,27 +18,25 @@ //! Autogenerated weights for `pallet_asset_conversion` //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 32.0.0 -//! DATE: 2024-04-08, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! DATE: 2024-03-13, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` //! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `runner-anb7yjbi-project-674-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` +//! HOSTNAME: `runner-p5qp1txx-project-674-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` //! WASM-EXECUTION: `Compiled`, CHAIN: `Some("dev")`, DB CACHE: `1024` // Executed Command: -// ./target/production/substrate-node +// target/production/substrate-node // benchmark // pallet -// --chain=dev // --steps=50 // --repeat=20 -// --pallet=pallet_asset_conversion -// --no-storage-info -// --no-median-slopes -// --no-min-squares // --extrinsic=* // --wasm-execution=compiled // --heap-pages=4096 -// --output=./substrate/frame/asset-conversion/src/weights.rs +// --json-file=/builds/parity/mirrors/polkadot-sdk/.git/.artifacts/bench.json +// --pallet=pallet_asset_conversion +// --chain=dev // --header=./substrate/HEADER-APACHE2 +// --output=./substrate/frame/asset-conversion/src/weights.rs // --template=./substrate/.maintain/frame-weight-template.hbs #![cfg_attr(rustfmt, rustfmt_skip)] @@ -56,6 +54,7 @@ pub trait WeightInfo { fn remove_liquidity() -> Weight; fn swap_exact_tokens_for_tokens(n: u32, ) -> Weight; fn swap_tokens_for_exact_tokens(n: u32, ) -> Weight; + fn touch(n: u32, ) -> Weight; } /// Weights for `pallet_asset_conversion` using the Substrate node and recommended hardware. @@ -63,7 +62,7 @@ pub struct SubstrateWeight(PhantomData); impl WeightInfo for SubstrateWeight { /// Storage: `AssetConversion::Pools` (r:1 w:1) /// Proof: `AssetConversion::Pools` (`max_values`: None, `max_size`: Some(30), added: 2505, mode: `MaxEncodedLen`) - /// Storage: `System::Account` (r:1 w:1) + /// Storage: `System::Account` (r:2 w:1) /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) /// Storage: `Assets::Asset` (r:2 w:0) /// Proof: `Assets::Asset` (`max_values`: None, `max_size`: Some(210), added: 2685, mode: `MaxEncodedLen`) @@ -77,9 +76,9 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `910` // Estimated: `6360` - // Minimum execution time: 86_709_000 picoseconds. - Weight::from_parts(88_841_000, 6360) - .saturating_add(T::DbWeight::get().reads(7_u64)) + // Minimum execution time: 95_080_000 picoseconds. + Weight::from_parts(97_241_000, 6360) + .saturating_add(T::DbWeight::get().reads(8_u64)) .saturating_add(T::DbWeight::get().writes(5_u64)) } /// Storage: `AssetConversion::Pools` (r:1 w:0) @@ -98,8 +97,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `1507` // Estimated: `11426` - // Minimum execution time: 148_672_000 picoseconds. - Weight::from_parts(151_824_000, 11426) + // Minimum execution time: 147_652_000 picoseconds. + Weight::from_parts(153_331_000, 11426) .saturating_add(T::DbWeight::get().reads(11_u64)) .saturating_add(T::DbWeight::get().writes(10_u64)) } @@ -117,8 +116,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `1650` // Estimated: `11426` - // Minimum execution time: 130_743_000 picoseconds. - Weight::from_parts(132_793_000, 11426) + // Minimum execution time: 130_738_000 picoseconds. + Weight::from_parts(134_350_000, 11426) .saturating_add(T::DbWeight::get().reads(9_u64)) .saturating_add(T::DbWeight::get().writes(8_u64)) } @@ -131,10 +130,10 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `89 + n * (419 ±0)` // Estimated: `990 + n * (5218 ±0)` - // Minimum execution time: 81_173_000 picoseconds. - Weight::from_parts(82_574_000, 990) - // Standard Error: 335_929 - .saturating_add(Weight::from_parts(11_607_291, 0).saturating_mul(n.into())) + // Minimum execution time: 79_681_000 picoseconds. + Weight::from_parts(81_461_000, 990) + // Standard Error: 320_959 + .saturating_add(Weight::from_parts(11_223_703, 0).saturating_mul(n.into())) .saturating_add(T::DbWeight::get().reads((3_u64).saturating_mul(n.into()))) .saturating_add(T::DbWeight::get().writes((3_u64).saturating_mul(n.into()))) .saturating_add(Weight::from_parts(0, 5218).saturating_mul(n.into())) @@ -148,21 +147,45 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `89 + n * (419 ±0)` // Estimated: `990 + n * (5218 ±0)` - // Minimum execution time: 80_562_000 picoseconds. - Weight::from_parts(82_501_000, 990) - // Standard Error: 329_460 - .saturating_add(Weight::from_parts(11_295_339, 0).saturating_mul(n.into())) + // Minimum execution time: 78_988_000 picoseconds. + Weight::from_parts(81_025_000, 990) + // Standard Error: 320_021 + .saturating_add(Weight::from_parts(11_040_712, 0).saturating_mul(n.into())) .saturating_add(T::DbWeight::get().reads((3_u64).saturating_mul(n.into()))) .saturating_add(T::DbWeight::get().writes((3_u64).saturating_mul(n.into()))) .saturating_add(Weight::from_parts(0, 5218).saturating_mul(n.into())) } + /// Storage: `AssetConversion::Pools` (r:1 w:0) + /// Proof: `AssetConversion::Pools` (`max_values`: None, `max_size`: Some(30), added: 2505, mode: `MaxEncodedLen`) + /// Storage: `Assets::Asset` (r:2 w:2) + /// Proof: `Assets::Asset` (`max_values`: None, `max_size`: Some(210), added: 2685, mode: `MaxEncodedLen`) + /// Storage: `System::Account` (r:1 w:0) + /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) + /// Storage: `Assets::Account` (r:2 w:2) + /// Proof: `Assets::Account` (`max_values`: None, `max_size`: Some(134), added: 2609, mode: `MaxEncodedLen`) + /// Storage: `PoolAssets::Asset` (r:1 w:1) + /// Proof: `PoolAssets::Asset` (`max_values`: None, `max_size`: Some(210), added: 2685, mode: `MaxEncodedLen`) + /// Storage: `PoolAssets::Account` (r:1 w:1) + /// Proof: `PoolAssets::Account` (`max_values`: None, `max_size`: Some(134), added: 2609, mode: `MaxEncodedLen`) + /// The range of component `n` is `[0, 3]`. + fn touch(n: u32, ) -> Weight { + // Proof Size summary in bytes: + // Measured: `1571` + // Estimated: `6360` + // Minimum execution time: 45_757_000 picoseconds. + Weight::from_parts(48_502_032, 6360) + // Standard Error: 62_850 + .saturating_add(Weight::from_parts(19_450_978, 0).saturating_mul(n.into())) + .saturating_add(T::DbWeight::get().reads(8_u64)) + .saturating_add(T::DbWeight::get().writes((2_u64).saturating_mul(n.into()))) + } } // For backwards compatibility and tests. impl WeightInfo for () { /// Storage: `AssetConversion::Pools` (r:1 w:1) /// Proof: `AssetConversion::Pools` (`max_values`: None, `max_size`: Some(30), added: 2505, mode: `MaxEncodedLen`) - /// Storage: `System::Account` (r:1 w:1) + /// Storage: `System::Account` (r:2 w:1) /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) /// Storage: `Assets::Asset` (r:2 w:0) /// Proof: `Assets::Asset` (`max_values`: None, `max_size`: Some(210), added: 2685, mode: `MaxEncodedLen`) @@ -176,9 +199,9 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `910` // Estimated: `6360` - // Minimum execution time: 86_709_000 picoseconds. - Weight::from_parts(88_841_000, 6360) - .saturating_add(RocksDbWeight::get().reads(7_u64)) + // Minimum execution time: 95_080_000 picoseconds. + Weight::from_parts(97_241_000, 6360) + .saturating_add(RocksDbWeight::get().reads(8_u64)) .saturating_add(RocksDbWeight::get().writes(5_u64)) } /// Storage: `AssetConversion::Pools` (r:1 w:0) @@ -197,8 +220,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `1507` // Estimated: `11426` - // Minimum execution time: 148_672_000 picoseconds. - Weight::from_parts(151_824_000, 11426) + // Minimum execution time: 147_652_000 picoseconds. + Weight::from_parts(153_331_000, 11426) .saturating_add(RocksDbWeight::get().reads(11_u64)) .saturating_add(RocksDbWeight::get().writes(10_u64)) } @@ -216,8 +239,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `1650` // Estimated: `11426` - // Minimum execution time: 130_743_000 picoseconds. - Weight::from_parts(132_793_000, 11426) + // Minimum execution time: 130_738_000 picoseconds. + Weight::from_parts(134_350_000, 11426) .saturating_add(RocksDbWeight::get().reads(9_u64)) .saturating_add(RocksDbWeight::get().writes(8_u64)) } @@ -230,10 +253,10 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `89 + n * (419 ±0)` // Estimated: `990 + n * (5218 ±0)` - // Minimum execution time: 81_173_000 picoseconds. - Weight::from_parts(82_574_000, 990) - // Standard Error: 335_929 - .saturating_add(Weight::from_parts(11_607_291, 0).saturating_mul(n.into())) + // Minimum execution time: 79_681_000 picoseconds. + Weight::from_parts(81_461_000, 990) + // Standard Error: 320_959 + .saturating_add(Weight::from_parts(11_223_703, 0).saturating_mul(n.into())) .saturating_add(RocksDbWeight::get().reads((3_u64).saturating_mul(n.into()))) .saturating_add(RocksDbWeight::get().writes((3_u64).saturating_mul(n.into()))) .saturating_add(Weight::from_parts(0, 5218).saturating_mul(n.into())) @@ -247,12 +270,36 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `89 + n * (419 ±0)` // Estimated: `990 + n * (5218 ±0)` - // Minimum execution time: 80_562_000 picoseconds. - Weight::from_parts(82_501_000, 990) - // Standard Error: 329_460 - .saturating_add(Weight::from_parts(11_295_339, 0).saturating_mul(n.into())) + // Minimum execution time: 78_988_000 picoseconds. + Weight::from_parts(81_025_000, 990) + // Standard Error: 320_021 + .saturating_add(Weight::from_parts(11_040_712, 0).saturating_mul(n.into())) .saturating_add(RocksDbWeight::get().reads((3_u64).saturating_mul(n.into()))) .saturating_add(RocksDbWeight::get().writes((3_u64).saturating_mul(n.into()))) .saturating_add(Weight::from_parts(0, 5218).saturating_mul(n.into())) } + /// Storage: `AssetConversion::Pools` (r:1 w:0) + /// Proof: `AssetConversion::Pools` (`max_values`: None, `max_size`: Some(30), added: 2505, mode: `MaxEncodedLen`) + /// Storage: `Assets::Asset` (r:2 w:2) + /// Proof: `Assets::Asset` (`max_values`: None, `max_size`: Some(210), added: 2685, mode: `MaxEncodedLen`) + /// Storage: `System::Account` (r:1 w:0) + /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) + /// Storage: `Assets::Account` (r:2 w:2) + /// Proof: `Assets::Account` (`max_values`: None, `max_size`: Some(134), added: 2609, mode: `MaxEncodedLen`) + /// Storage: `PoolAssets::Asset` (r:1 w:1) + /// Proof: `PoolAssets::Asset` (`max_values`: None, `max_size`: Some(210), added: 2685, mode: `MaxEncodedLen`) + /// Storage: `PoolAssets::Account` (r:1 w:1) + /// Proof: `PoolAssets::Account` (`max_values`: None, `max_size`: Some(134), added: 2609, mode: `MaxEncodedLen`) + /// The range of component `n` is `[0, 3]`. + fn touch(n: u32, ) -> Weight { + // Proof Size summary in bytes: + // Measured: `1571` + // Estimated: `6360` + // Minimum execution time: 45_757_000 picoseconds. + Weight::from_parts(48_502_032, 6360) + // Standard Error: 62_850 + .saturating_add(Weight::from_parts(19_450_978, 0).saturating_mul(n.into())) + .saturating_add(RocksDbWeight::get().reads(8_u64)) + .saturating_add(RocksDbWeight::get().writes((2_u64).saturating_mul(n.into()))) + } } diff --git a/substrate/frame/asset-rate/Cargo.toml b/substrate/frame/asset-rate/Cargo.toml index cd502148a8d8f116afcbcde8969490a454da81b7..4662469e46ce423edaab234041a852a42b0711bb 100644 --- a/substrate/frame/asset-rate/Cargo.toml +++ b/substrate/frame/asset-rate/Cargo.toml @@ -15,7 +15,7 @@ workspace = true targets = ["x86_64-unknown-linux-gnu"] [dependencies] -codec = { package = "parity-scale-codec", version = "3.6.1", default-features = false, features = [ +codec = { package = "parity-scale-codec", version = "3.6.12", default-features = false, features = [ "derive", ] } scale-info = { version = "2.11.1", default-features = false, features = ["derive"] } diff --git a/substrate/frame/assets/Cargo.toml b/substrate/frame/assets/Cargo.toml index 3b95750c14c8c9c78ad86442085580810e447f5a..9647ae4db6baa6ada63350153b8a10993e940401 100644 --- a/substrate/frame/assets/Cargo.toml +++ b/substrate/frame/assets/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "pallet-assets" -version = "29.0.0" +version = "29.1.0" authors.workspace = true edition.workspace = true license = "Apache-2.0" @@ -16,7 +16,7 @@ workspace = true targets = ["x86_64-unknown-linux-gnu"] [dependencies] -codec = { package = "parity-scale-codec", version = "3.6.1", default-features = false } +codec = { package = "parity-scale-codec", version = "3.6.12", default-features = false } log = { workspace = true } scale-info = { version = "2.11.1", default-features = false, features = ["derive"] } sp-std = { path = "../../primitives/std", default-features = false } diff --git a/substrate/frame/assets/src/functions.rs b/substrate/frame/assets/src/functions.rs index 8791aaa736b350292cfce58c4d4067f3e8af101b..9309d010117576177f6bb055e732c8caf2f13bcb 100644 --- a/substrate/frame/assets/src/functions.rs +++ b/substrate/frame/assets/src/functions.rs @@ -368,11 +368,14 @@ impl, I: 'static> Pallet { Ok(()) } - /// Returns a `DepositFrom` of an account only if balance is zero. + /// Refunds the `DepositFrom` of an account only if its balance is zero. + /// + /// If the `maybe_check_caller` parameter is specified, it must match the account that provided + /// the deposit or must be the admin of the asset. pub(super) fn do_refund_other( id: T::AssetId, who: &T::AccountId, - caller: &T::AccountId, + maybe_check_caller: Option, ) -> DispatchResult { let mut account = Account::::get(&id, &who).ok_or(Error::::NoDeposit)?; let (depositor, deposit) = @@ -380,7 +383,9 @@ impl, I: 'static> Pallet { let mut details = Asset::::get(&id).ok_or(Error::::Unknown)?; ensure!(details.status == AssetStatus::Live, Error::::AssetNotLive); ensure!(!account.status.is_frozen(), Error::::Frozen); - ensure!(caller == &depositor || caller == &details.admin, Error::::NoPermission); + if let Some(caller) = maybe_check_caller { + ensure!(caller == depositor || caller == details.admin, Error::::NoPermission); + } ensure!(account.balance.is_zero(), Error::::WouldBurn); T::Currency::unreserve(&depositor, deposit); @@ -491,7 +496,7 @@ impl, I: 'static> Pallet { let d = Asset::::get(&id).ok_or(Error::::Unknown)?; ensure!( d.status == AssetStatus::Live || d.status == AssetStatus::Frozen, - Error::::AssetNotLive + Error::::IncorrectStatus ); let actual = Self::decrease_balance(id.clone(), target, amount, f, |actual, details| { @@ -1013,4 +1018,28 @@ impl, I: 'static> Pallet { }) .collect::>() } + + /// Reset the team for the asset with the given `id`. + /// + /// ### Parameters + /// - `id`: The identifier of the asset for which the team is being reset. + /// - `owner`: The new `owner` account for the asset. + /// - `admin`: The new `admin` account for the asset. + /// - `issuer`: The new `issuer` account for the asset. + /// - `freezer`: The new `freezer` account for the asset. + pub(crate) fn do_reset_team( + id: T::AssetId, + owner: T::AccountId, + admin: T::AccountId, + issuer: T::AccountId, + freezer: T::AccountId, + ) -> DispatchResult { + let mut d = Asset::::get(&id).ok_or(Error::::Unknown)?; + d.owner = owner; + d.admin = admin; + d.issuer = issuer; + d.freezer = freezer; + Asset::::insert(&id, d); + Ok(()) + } } diff --git a/substrate/frame/assets/src/impl_fungibles.rs b/substrate/frame/assets/src/impl_fungibles.rs index 123abeba8283fce8300521a80acead12c1616933..30122f6d788ff868b6f077f3e0c4e7cd3b26915f 100644 --- a/substrate/frame/assets/src/impl_fungibles.rs +++ b/substrate/frame/assets/src/impl_fungibles.rs @@ -118,6 +118,22 @@ impl, I: 'static> fungibles::Balanced<::AccountI { type OnDropCredit = fungibles::DecreaseIssuance; type OnDropDebt = fungibles::IncreaseIssuance; + + fn done_deposit( + asset_id: Self::AssetId, + who: &::AccountId, + amount: Self::Balance, + ) { + Self::deposit_event(Event::Deposited { asset_id, who: who.clone(), amount }) + } + + fn done_withdraw( + asset_id: Self::AssetId, + who: &::AccountId, + amount: Self::Balance, + ) { + Self::deposit_event(Event::Withdrawn { asset_id, who: who.clone(), amount }) + } } impl, I: 'static> fungibles::Unbalanced for Pallet { @@ -308,3 +324,35 @@ impl, I: 'static> fungibles::InspectEnumerable for Pa Asset::::iter_keys() } } + +impl, I: 'static> fungibles::roles::ResetTeam for Pallet { + fn reset_team( + id: T::AssetId, + owner: T::AccountId, + admin: T::AccountId, + issuer: T::AccountId, + freezer: T::AccountId, + ) -> DispatchResult { + Self::do_reset_team(id, owner, admin, issuer, freezer) + } +} + +impl, I: 'static> fungibles::Refund for Pallet { + type AssetId = T::AssetId; + type Balance = DepositBalanceOf; + fn deposit_held(id: Self::AssetId, who: T::AccountId) -> Option<(T::AccountId, Self::Balance)> { + use ExistenceReason::*; + match Account::::get(&id, &who).ok_or(Error::::NoDeposit).ok()?.reason { + DepositHeld(b) => Some((who, b)), + DepositFrom(d, b) => Some((d, b)), + _ => None, + } + } + fn refund(id: Self::AssetId, who: T::AccountId) -> DispatchResult { + match Self::deposit_held(id.clone(), who.clone()) { + Some((d, _)) if d == who => Self::do_refund(id, who, false), + Some(..) => Self::do_refund_other(id, &who, None), + None => Err(Error::::NoDeposit.into()), + } + } +} diff --git a/substrate/frame/assets/src/lib.rs b/substrate/frame/assets/src/lib.rs index 6891f04dfb51aae356a708112a7bba284e894be2..d5214922555890ac96a931458b01522da1b52779 100644 --- a/substrate/frame/assets/src/lib.rs +++ b/substrate/frame/assets/src/lib.rs @@ -571,6 +571,10 @@ pub mod pallet { Touched { asset_id: T::AssetId, who: T::AccountId, depositor: T::AccountId }, /// Some account `who` was blocked. Blocked { asset_id: T::AssetId, who: T::AccountId }, + /// Some assets were deposited (e.g. for transaction fees). + Deposited { asset_id: T::AssetId, who: T::AccountId, amount: T::Balance }, + /// Some assets were withdrawn from the account (e.g. for transaction fees). + Withdrawn { asset_id: T::AssetId, who: T::AccountId, amount: T::Balance }, } #[pallet::error] @@ -987,7 +991,7 @@ pub mod pallet { let d = Asset::::get(&id).ok_or(Error::::Unknown)?; ensure!( d.status == AssetStatus::Live || d.status == AssetStatus::Frozen, - Error::::AssetNotLive + Error::::IncorrectStatus ); ensure!(origin == d.freezer, Error::::NoPermission); let who = T::Lookup::lookup(who)?; @@ -1024,7 +1028,7 @@ pub mod pallet { let details = Asset::::get(&id).ok_or(Error::::Unknown)?; ensure!( details.status == AssetStatus::Live || details.status == AssetStatus::Frozen, - Error::::AssetNotLive + Error::::IncorrectStatus ); ensure!(origin == details.admin, Error::::NoPermission); let who = T::Lookup::lookup(who)?; @@ -1113,7 +1117,7 @@ pub mod pallet { Asset::::try_mutate(id.clone(), |maybe_details| { let details = maybe_details.as_mut().ok_or(Error::::Unknown)?; - ensure!(details.status == AssetStatus::Live, Error::::LiveAsset); + ensure!(details.status == AssetStatus::Live, Error::::AssetNotLive); ensure!(origin == details.owner, Error::::NoPermission); if details.owner == owner { return Ok(()) @@ -1644,7 +1648,7 @@ pub mod pallet { let origin = ensure_signed(origin)?; let who = T::Lookup::lookup(who)?; let id: T::AssetId = id.into(); - Self::do_refund_other(id, &who, &origin) + Self::do_refund_other(id, &who, Some(origin)) } /// Disallow further unprivileged transfers of an asset `id` to and from an account `who`. @@ -1669,7 +1673,7 @@ pub mod pallet { let d = Asset::::get(&id).ok_or(Error::::Unknown)?; ensure!( d.status == AssetStatus::Live || d.status == AssetStatus::Frozen, - Error::::AssetNotLive + Error::::IncorrectStatus ); ensure!(origin == d.freezer, Error::::NoPermission); let who = T::Lookup::lookup(who)?; @@ -1697,7 +1701,9 @@ pub mod pallet { fn should_touch(asset: T::AssetId, who: &T::AccountId) -> bool { match Asset::::get(&asset) { + // refer to the [`Self::new_account`] function for more details. Some(info) if info.is_sufficient => false, + Some(_) if frame_system::Pallet::::can_accrue_consumers(who, 2) => false, Some(_) => !Account::::contains_key(asset, who), _ => true, } diff --git a/substrate/frame/assets/src/tests/sets.rs b/substrate/frame/assets/src/tests/sets.rs index f85a736c08320c22df3ec3ad9d0aeaa74cc1706c..4d75b8aeab2c51841b751705b3ffaf7a321e5b08 100644 --- a/substrate/frame/assets/src/tests/sets.rs +++ b/substrate/frame/assets/src/tests/sets.rs @@ -90,6 +90,12 @@ fn deposit_from_set_types_works() { assert_eq!(First::::balance((), &account2), 50); assert_eq!(First::::total_issuance(()), 100); + System::assert_has_event(RuntimeEvent::Assets(crate::Event::Deposited { + asset_id: asset1, + who: account2, + amount: 50, + })); + assert_eq!(imb.peek(), 50); let (imb1, imb2) = imb.split(30); @@ -336,6 +342,12 @@ fn withdraw_from_set_types_works() { assert_eq!(First::::balance((), &account2), 50); assert_eq!(First::::total_issuance(()), 200); + System::assert_has_event(RuntimeEvent::Assets(crate::Event::Withdrawn { + asset_id: asset1, + who: account2, + amount: 50, + })); + assert_eq!(imb.peek(), 50); drop(imb); assert_eq!(First::::total_issuance(()), 150); diff --git a/substrate/frame/atomic-swap/Cargo.toml b/substrate/frame/atomic-swap/Cargo.toml index c641071df902d0fa78f4794292bacd824f9712bb..8083c12d4b39fb0b860a738f700168bcad0bc2f3 100644 --- a/substrate/frame/atomic-swap/Cargo.toml +++ b/substrate/frame/atomic-swap/Cargo.toml @@ -16,7 +16,7 @@ workspace = true targets = ["x86_64-unknown-linux-gnu"] [dependencies] -codec = { package = "parity-scale-codec", version = "3.6.1", default-features = false } +codec = { package = "parity-scale-codec", version = "3.6.12", default-features = false } scale-info = { version = "2.11.1", default-features = false, features = ["derive"] } frame-support = { path = "../support", default-features = false } frame-system = { path = "../system", default-features = false } diff --git a/substrate/frame/atomic-swap/src/lib.rs b/substrate/frame/atomic-swap/src/lib.rs index 609903e67e3e56f7016a20772a996a41705839d7..dc0300dc1a5c95d2654dfa5a210e6efab26125f6 100644 --- a/substrate/frame/atomic-swap/src/lib.rs +++ b/substrate/frame/atomic-swap/src/lib.rs @@ -58,6 +58,7 @@ use frame_system::pallet_prelude::BlockNumberFor; use scale_info::TypeInfo; use sp_io::hashing::blake2_256; use sp_runtime::RuntimeDebug; +use sp_std::vec::Vec; /// Pending atomic swap operation. #[derive(Clone, Eq, PartialEq, RuntimeDebugNoBound, Encode, Decode, TypeInfo, MaxEncodedLen)] diff --git a/substrate/frame/aura/Cargo.toml b/substrate/frame/aura/Cargo.toml index 92ff3a0c56589d204cabe9770281f34d30f1eca9..9264d2f4a643cdedd02fa17f81f90d949c2c0729 100644 --- a/substrate/frame/aura/Cargo.toml +++ b/substrate/frame/aura/Cargo.toml @@ -16,7 +16,7 @@ workspace = true targets = ["x86_64-unknown-linux-gnu"] [dependencies] -codec = { package = "parity-scale-codec", version = "3.6.1", default-features = false, features = ["derive", "max-encoded-len"] } +codec = { package = "parity-scale-codec", version = "3.6.12", default-features = false, features = ["derive", "max-encoded-len"] } log = { workspace = true } scale-info = { version = "2.11.1", default-features = false, features = ["derive"] } frame-support = { path = "../support", default-features = false } diff --git a/substrate/frame/authority-discovery/Cargo.toml b/substrate/frame/authority-discovery/Cargo.toml index a7aba711a5686088241e4507e686683114641bf7..c21f9b5c904556f8a0c01a0e5f1e468e32685ee5 100644 --- a/substrate/frame/authority-discovery/Cargo.toml +++ b/substrate/frame/authority-discovery/Cargo.toml @@ -16,7 +16,7 @@ workspace = true targets = ["x86_64-unknown-linux-gnu"] [dependencies] -codec = { package = "parity-scale-codec", version = "3.6.1", default-features = false, features = [ +codec = { package = "parity-scale-codec", version = "3.6.12", default-features = false, features = [ "derive", ] } scale-info = { version = "2.11.1", default-features = false, features = ["derive"] } diff --git a/substrate/frame/authority-discovery/src/lib.rs b/substrate/frame/authority-discovery/src/lib.rs index ed9240d99e8d5bb2b814fe80e0211c601378651c..16f71960d693bec3de2babe446470e2db94bb8b9 100644 --- a/substrate/frame/authority-discovery/src/lib.rs +++ b/substrate/frame/authority-discovery/src/lib.rs @@ -48,13 +48,11 @@ pub mod pallet { } #[pallet::storage] - #[pallet::getter(fn keys)] /// Keys of the current authority set. pub(super) type Keys = StorageValue<_, WeakBoundedVec, ValueQuery>; #[pallet::storage] - #[pallet::getter(fn next_keys)] /// Keys of the next authority set. pub(super) type NextKeys = StorageValue<_, WeakBoundedVec, ValueQuery>; diff --git a/substrate/frame/authorship/Cargo.toml b/substrate/frame/authorship/Cargo.toml index 2bfd59a48e10e0cee249d62680e66d7ce426cc3f..dd78e3404ef0b3c30adfa5b24bd4444c2fec10d1 100644 --- a/substrate/frame/authorship/Cargo.toml +++ b/substrate/frame/authorship/Cargo.toml @@ -16,7 +16,7 @@ workspace = true targets = ["x86_64-unknown-linux-gnu"] [dependencies] -codec = { package = "parity-scale-codec", version = "3.6.1", default-features = false, features = [ +codec = { package = "parity-scale-codec", version = "3.6.12", default-features = false, features = [ "derive", ] } impl-trait-for-tuples = "0.2.2" diff --git a/substrate/frame/babe/Cargo.toml b/substrate/frame/babe/Cargo.toml index 9f6ef2bc05ea18e96786bd59b697c0290fd2d398..d06b7f7454648ea529595aa91e1e3a0f9e2b5486 100644 --- a/substrate/frame/babe/Cargo.toml +++ b/substrate/frame/babe/Cargo.toml @@ -16,7 +16,7 @@ workspace = true targets = ["x86_64-unknown-linux-gnu"] [dependencies] -codec = { package = "parity-scale-codec", version = "3.6.1", default-features = false, features = ["derive"] } +codec = { package = "parity-scale-codec", version = "3.6.12", default-features = false, features = ["derive"] } log = { workspace = true } scale-info = { version = "2.11.1", default-features = false, features = ["derive", "serde"] } frame-benchmarking = { path = "../benchmarking", default-features = false, optional = true } diff --git a/substrate/frame/babe/src/mock.rs b/substrate/frame/babe/src/mock.rs index ec54275278eb625d9648b9fd744a3f7aab0a646a..395a86e6528807ff21ee2667d1446016b6826a1e 100644 --- a/substrate/frame/babe/src/mock.rs +++ b/substrate/frame/babe/src/mock.rs @@ -144,7 +144,6 @@ parameter_types! { pub const BondingDuration: EraIndex = 3; pub const SlashDeferDuration: EraIndex = 0; pub const RewardCurve: &'static PiecewiseLinear<'static> = &REWARD_CURVE; - pub const OffendingValidatorsThreshold: Perbill = Perbill::from_percent(16); pub static ElectionsBounds: ElectionBounds = ElectionBoundsBuilder::default().build(); } @@ -174,7 +173,6 @@ impl pallet_staking::Config for Test { type UnixTime = pallet_timestamp::Pallet; type EraPayout = pallet_staking::ConvertCurve; type MaxExposurePageSize = ConstU32<64>; - type OffendingValidatorsThreshold = OffendingValidatorsThreshold; type NextNewSession = Session; type ElectionProvider = onchain::OnChainExecution; type GenesisElectionProvider = Self::ElectionProvider; @@ -187,6 +185,7 @@ impl pallet_staking::Config for Test { type EventListeners = (); type BenchmarkingConfig = pallet_staking::TestBenchmarkingConfig; type WeightInfo = (); + type DisablingStrategy = pallet_staking::UpToLimitDisablingStrategy; } impl pallet_offences::Config for Test { diff --git a/substrate/frame/bags-list/Cargo.toml b/substrate/frame/bags-list/Cargo.toml index 5deb504d0a4f2846748bd0fb4970cfbfdde41733..3429d2f28a6cc7445e383a28e5f817b876251f2b 100644 --- a/substrate/frame/bags-list/Cargo.toml +++ b/substrate/frame/bags-list/Cargo.toml @@ -16,7 +16,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] # parity -codec = { package = "parity-scale-codec", version = "3.6.1", default-features = false, features = [ +codec = { package = "parity-scale-codec", version = "3.6.12", default-features = false, features = [ "derive", ] } scale-info = { version = "2.11.1", default-features = false, features = [ diff --git a/substrate/frame/balances/Cargo.toml b/substrate/frame/balances/Cargo.toml index 28eabdaf5062b4c7250bb5a03dc64debb2f37a8c..4da14aea12809f09c797d0eb0925e1c43bfdc8d6 100644 --- a/substrate/frame/balances/Cargo.toml +++ b/substrate/frame/balances/Cargo.toml @@ -16,7 +16,7 @@ workspace = true targets = ["x86_64-unknown-linux-gnu"] [dependencies] -codec = { package = "parity-scale-codec", version = "3.6.1", default-features = false, features = ["derive", "max-encoded-len"] } +codec = { package = "parity-scale-codec", version = "3.6.12", default-features = false, features = ["derive", "max-encoded-len"] } log = { workspace = true } scale-info = { version = "2.11.1", default-features = false, features = ["derive"] } frame-benchmarking = { path = "../benchmarking", default-features = false, optional = true } @@ -28,6 +28,7 @@ docify = "0.2.8" [dev-dependencies] pallet-transaction-payment = { path = "../transaction-payment" } +frame-support = { path = "../support", features = ["experimental"] } sp-core = { path = "../../primitives/core" } sp-io = { path = "../../primitives/io" } paste = "1.0.12" diff --git a/substrate/frame/balances/src/benchmarking.rs b/substrate/frame/balances/src/benchmarking.rs index 0ce1240eb5d3987e43f7dba2734cec3b6fbea62a..e4229f2d7f0fafa96260710f218e73dd63832893 100644 --- a/substrate/frame/balances/src/benchmarking.rs +++ b/substrate/frame/balances/src/benchmarking.rs @@ -44,7 +44,7 @@ mod benchmarks { let caller = whitelisted_caller(); // Give some multiple of the existential deposit - let balance = existential_deposit.saturating_mul(ED_MULTIPLIER.into()); + let balance = existential_deposit.saturating_mul(ED_MULTIPLIER.into()).max(1u32.into()); let _ = as Currency<_>>::make_free_balance_be(&caller, balance); // Transfer `e - 1` existential deposits + 1 unit, which guarantees to create one account, @@ -297,6 +297,44 @@ mod benchmarks { assert_eq!(Balances::::total_issuance(), ti + delta); } + /// Benchmark `burn` extrinsic with the worst possible condition - burn kills the account. + #[benchmark] + fn burn_allow_death() { + 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()); + let _ = as Currency<_>>::make_free_balance_be(&caller, balance); + + // Burn enough to kill the account. + let burn_amount = balance - existential_deposit + 1u32.into(); + + #[extrinsic_call] + burn(RawOrigin::Signed(caller.clone()), burn_amount, false); + + assert_eq!(Balances::::free_balance(&caller), Zero::zero()); + } + + // Benchmark `burn` extrinsic with the case where account is kept alive. + #[benchmark] + fn burn_keep_alive() { + 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()); + let _ = as Currency<_>>::make_free_balance_be(&caller, balance); + + // Burn minimum possible amount which should not kill the account. + let burn_amount = 1u32.into(); + + #[extrinsic_call] + burn(RawOrigin::Signed(caller.clone()), burn_amount, true); + + assert_eq!(Balances::::free_balance(&caller), balance - burn_amount); + } + impl_benchmark_test_suite! { Balances, crate::tests::ExtBuilder::default().build(), diff --git a/substrate/frame/balances/src/lib.rs b/substrate/frame/balances/src/lib.rs index 685b12499ac0ffb2a27d3f861232ab3dc09bf08f..8d904d3d21b8acbf8469b8213d1220c277d3dd11 100644 --- a/substrate/frame/balances/src/lib.rs +++ b/substrate/frame/balances/src/lib.rs @@ -767,6 +767,32 @@ pub mod pallet { Ok(()) } + + /// Burn the specified liquid free balance from the origin account. + /// + /// If the origin's account ends up below the existential deposit as a result + /// of the burn and `keep_alive` is false, the account will be reaped. + /// + /// Unlike sending funds to a _burn_ address, which merely makes the funds inaccessible, + /// this `burn` operation will reduce total issuance by the amount _burned_. + #[pallet::call_index(10)] + #[pallet::weight(if *keep_alive {T::WeightInfo::burn_allow_death() } else {T::WeightInfo::burn_keep_alive()})] + pub fn burn( + origin: OriginFor, + #[pallet::compact] value: T::Balance, + keep_alive: bool, + ) -> DispatchResult { + let source = ensure_signed(origin)?; + let preservation = if keep_alive { Preserve } else { Expendable }; + >::burn_from( + &source, + value, + preservation, + Precision::Exact, + Polite, + )?; + Ok(()) + } } impl, I: 'static> Pallet { @@ -954,6 +980,13 @@ pub mod pallet { if !did_consume && does_consume { frame_system::Pallet::::inc_consumers(who)?; } + if does_consume && frame_system::Pallet::::consumers(who) == 0 { + // NOTE: This is a failsafe and should not happen for normal accounts. A normal + // account should have gotten a consumer ref in `!did_consume && does_consume` + // at some point. + log::error!(target: LOG_TARGET, "Defensively bumping a consumer ref."); + frame_system::Pallet::::inc_consumers(who)?; + } if did_provide && !does_provide { // This could reap the account so must go last. frame_system::Pallet::::dec_providers(who).map_err(|r| { diff --git a/substrate/frame/balances/src/migration.rs b/substrate/frame/balances/src/migration.rs index 38d9c07ff7e002f6a7a57189b7ebce6830b52c75..568c3fbb7cf0926f9f23b2bdd23d840fa85bad5c 100644 --- a/substrate/frame/balances/src/migration.rs +++ b/substrate/frame/balances/src/migration.rs @@ -91,7 +91,7 @@ impl, I: 'static> OnRuntimeUpgrade for ResetInactive { StorageVersion::new(0).put::>(); log::info!(target: LOG_TARGET, "Storage to version 0"); - T::DbWeight::get().reads_writes(1, 2) + T::DbWeight::get().reads_writes(1, 3) } else { log::info!( target: LOG_TARGET, diff --git a/substrate/frame/balances/src/tests/currency_tests.rs b/substrate/frame/balances/src/tests/currency_tests.rs index 450b1a84aa878552cdd8e9bd38918099b7edb463..9ad4aca64406b8ab1e284bf69d081211d47b37d9 100644 --- a/substrate/frame/balances/src/tests/currency_tests.rs +++ b/substrate/frame/balances/src/tests/currency_tests.rs @@ -701,7 +701,7 @@ fn account_removal_on_free_too_low() { fn burn_must_work() { ExtBuilder::default().monied(true).build_and_execute_with(|| { let init_total_issuance = Balances::total_issuance(); - let imbalance = Balances::burn(10); + let imbalance = >::burn(10); assert_eq!(Balances::total_issuance(), init_total_issuance - 10); drop(imbalance); assert_eq!(Balances::total_issuance(), init_total_issuance); diff --git a/substrate/frame/balances/src/tests/dispatchable_tests.rs b/substrate/frame/balances/src/tests/dispatchable_tests.rs index 4be68f61693b4f1c92b066fc396218a48550632e..4bc96f6b43d97444252f42e4820d97168ed50e1e 100644 --- a/substrate/frame/balances/src/tests/dispatchable_tests.rs +++ b/substrate/frame/balances/src/tests/dispatchable_tests.rs @@ -335,3 +335,47 @@ fn force_adjust_total_issuance_rejects_more_than_inactive() { assert_eq!(Balances::active_issuance(), 10); }); } + +#[test] +fn burn_works() { + ExtBuilder::default().build().execute_with(|| { + // Prepare account with initial balance + let (account, init_balance) = (1, 37); + assert_ok!(Balances::force_set_balance(RuntimeOrigin::root(), account, init_balance)); + let init_issuance = Balances::total_issuance(); + let (keep_alive, allow_death) = (true, false); + + // 1. Cannot burn more than what's available + assert_noop!( + Balances::burn(Some(account).into(), init_balance + 1, allow_death), + TokenError::FundsUnavailable, + ); + + // 2. Burn some funds, without reaping the account + let burn_amount_1 = 1; + assert_ok!(Balances::burn(Some(account).into(), burn_amount_1, allow_death)); + System::assert_last_event(RuntimeEvent::Balances(Event::Burned { + who: account, + amount: burn_amount_1, + })); + assert_eq!(Balances::total_issuance(), init_issuance - burn_amount_1); + assert_eq!(Balances::total_balance(&account), init_balance - burn_amount_1); + + // 3. Cannot burn funds below existential deposit if `keep_alive` is `true` + let burn_amount_2 = + init_balance - burn_amount_1 - ::ExistentialDeposit::get() + 1; + assert_noop!( + Balances::burn(Some(account).into(), init_balance + 1, keep_alive), + TokenError::FundsUnavailable, + ); + + // 4. Burn some more funds, this time reaping the account + assert_ok!(Balances::burn(Some(account).into(), burn_amount_2, allow_death)); + System::assert_last_event(RuntimeEvent::Balances(Event::Burned { + who: account, + amount: burn_amount_2, + })); + assert_eq!(Balances::total_issuance(), init_issuance - burn_amount_1 - burn_amount_2); + assert!(Balances::total_balance(&account).is_zero()); + }); +} diff --git a/substrate/frame/balances/src/tests/general_tests.rs b/substrate/frame/balances/src/tests/general_tests.rs new file mode 100644 index 0000000000000000000000000000000000000000..0f3e015d0a89242dd321285b84a134bd907702ec --- /dev/null +++ b/substrate/frame/balances/src/tests/general_tests.rs @@ -0,0 +1,111 @@ +// 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::{ + system::AccountInfo, + tests::{ensure_ti_valid, Balances, ExtBuilder, System, Test, TestId, UseSystem}, + AccountData, ExtraFlags, TotalIssuance, +}; +use frame_support::{ + assert_noop, assert_ok, hypothetically, + traits::{ + fungible::{Mutate, MutateHold}, + tokens::Precision, + }, +}; +use sp_runtime::DispatchError; + +/// There are some accounts that have one consumer ref too few. These accounts are at risk of losing +/// their held (reserved) balance. They do not just lose it - it is also not accounted for in the +/// Total Issuance. Here we test the case that the account does not reap in such a case, but gets +/// one consumer ref for its reserved balance. +#[test] +fn regression_historic_acc_does_not_evaporate_reserve() { + ExtBuilder::default().build_and_execute_with(|| { + UseSystem::set(true); + let (alice, bob) = (0, 1); + // Alice is in a bad state with consumer == 0 && reserved > 0: + Balances::set_balance(&alice, 100); + TotalIssuance::::put(100); + ensure_ti_valid(); + + assert_ok!(Balances::hold(&TestId::Foo, &alice, 10)); + // This is the issue of the account: + System::dec_consumers(&alice); + + assert_eq!( + System::account(&alice), + AccountInfo { + data: AccountData { + free: 90, + reserved: 10, + frozen: 0, + flags: ExtraFlags(1u128 << 127), + }, + nonce: 0, + consumers: 0, // should be 1 on a good acc + providers: 1, + sufficients: 0, + } + ); + + ensure_ti_valid(); + + // Reaping the account is prevented by the new logic: + assert_noop!( + Balances::transfer_allow_death(Some(alice).into(), bob, 90), + DispatchError::ConsumerRemaining + ); + assert_noop!( + Balances::transfer_all(Some(alice).into(), bob, false), + DispatchError::ConsumerRemaining + ); + + // normal transfers still work: + hypothetically!({ + assert_ok!(Balances::transfer_keep_alive(Some(alice).into(), bob, 40)); + // Alice got back her consumer ref: + assert_eq!(System::consumers(&alice), 1); + ensure_ti_valid(); + }); + hypothetically!({ + assert_ok!(Balances::transfer_all(Some(alice).into(), bob, true)); + // Alice got back her consumer ref: + assert_eq!(System::consumers(&alice), 1); + ensure_ti_valid(); + }); + + // un-reserving all does not add a consumer ref: + hypothetically!({ + assert_ok!(Balances::release(&TestId::Foo, &alice, 10, Precision::Exact)); + assert_eq!(System::consumers(&alice), 0); + assert_ok!(Balances::transfer_keep_alive(Some(alice).into(), bob, 40)); + assert_eq!(System::consumers(&alice), 0); + ensure_ti_valid(); + }); + // un-reserving some does add a consumer ref: + hypothetically!({ + assert_ok!(Balances::release(&TestId::Foo, &alice, 5, Precision::Exact)); + assert_eq!(System::consumers(&alice), 1); + assert_ok!(Balances::transfer_keep_alive(Some(alice).into(), bob, 40)); + assert_eq!(System::consumers(&alice), 1); + ensure_ti_valid(); + }); + }); +} diff --git a/substrate/frame/balances/src/tests/mod.rs b/substrate/frame/balances/src/tests/mod.rs index 234fe6eaf2c3298183d55d646a8af6bad14153c1..0abf2251290fee6881f0346aaab7df37ff2f0efb 100644 --- a/substrate/frame/balances/src/tests/mod.rs +++ b/substrate/frame/balances/src/tests/mod.rs @@ -19,7 +19,7 @@ #![cfg(test)] -use crate::{self as pallet_balances, AccountData, Config, CreditOf, Error, Pallet}; +use crate::{self as pallet_balances, AccountData, Config, CreditOf, Error, Pallet, TotalIssuance}; use codec::{Decode, Encode, MaxEncodedLen}; use frame_support::{ assert_err, assert_noop, assert_ok, assert_storage_noop, derive_impl, @@ -47,6 +47,7 @@ mod currency_tests; mod dispatchable_tests; mod fungible_conformance_tests; mod fungible_tests; +mod general_tests; mod reentrancy_tests; type Block = frame_system::mocking::MockBlock; @@ -278,6 +279,23 @@ pub fn info_from_weight(w: Weight) -> DispatchInfo { DispatchInfo { weight: w, ..Default::default() } } +/// Check that the total-issuance matches the sum of all accounts' total balances. +pub fn ensure_ti_valid() { + let mut sum = 0; + + for acc in frame_system::Account::::iter_keys() { + if UseSystem::get() { + let data = frame_system::Pallet::::account(acc); + sum += data.data.total(); + } else { + let data = crate::Account::::get(acc); + sum += data.total(); + } + } + + assert_eq!(TotalIssuance::::get(), sum, "Total Issuance wrong"); +} + #[test] fn weights_sane() { let info = crate::Call::::transfer_allow_death { dest: 10, value: 4 }.get_dispatch_info(); diff --git a/substrate/frame/balances/src/types.rs b/substrate/frame/balances/src/types.rs index 69d33bb023f397ba7b2464004224a233c4b913a9..3e36a83575c892812d687e5882784b023754fe44 100644 --- a/substrate/frame/balances/src/types.rs +++ b/substrate/frame/balances/src/types.rs @@ -111,7 +111,7 @@ pub struct AccountData { const IS_NEW_LOGIC: u128 = 0x80000000_00000000_00000000_00000000u128; #[derive(Encode, Decode, Clone, PartialEq, Eq, RuntimeDebug, MaxEncodedLen, TypeInfo)] -pub struct ExtraFlags(u128); +pub struct ExtraFlags(pub(crate) u128); impl Default for ExtraFlags { fn default() -> Self { Self(IS_NEW_LOGIC) diff --git a/substrate/frame/balances/src/weights.rs b/substrate/frame/balances/src/weights.rs index f99fc45107614a96f223f4113e03ed6c6cab4041..e82c97160efcfdac6b994345e0baeb787e69bcb9 100644 --- a/substrate/frame/balances/src/weights.rs +++ b/substrate/frame/balances/src/weights.rs @@ -18,27 +18,25 @@ //! Autogenerated weights for `pallet_balances` //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 32.0.0 -//! DATE: 2024-04-08, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! DATE: 2024-05-06, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` //! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `runner-anb7yjbi-project-674-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` +//! HOSTNAME: `runner-unxyhko3-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 -// --output=./substrate/frame/balances/src/weights.rs +// --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 // --template=./substrate/.maintain/frame-weight-template.hbs #![cfg_attr(rustfmt, rustfmt_skip)] @@ -60,6 +58,8 @@ pub trait WeightInfo { fn force_unreserve() -> Weight; fn upgrade_accounts(u: u32, ) -> Weight; fn force_adjust_total_issuance() -> Weight; + fn burn_allow_death() -> Weight; + fn burn_keep_alive() -> Weight; } /// Weights for `pallet_balances` using the Substrate node and recommended hardware. @@ -71,8 +71,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `3593` - // Minimum execution time: 50_062_000 picoseconds. - Weight::from_parts(51_214_000, 3593) + // Minimum execution time: 47_552_000 picoseconds. + Weight::from_parts(48_363_000, 3593) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -82,8 +82,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `3593` - // Minimum execution time: 39_700_000 picoseconds. - Weight::from_parts(40_754_000, 3593) + // Minimum execution time: 37_565_000 picoseconds. + Weight::from_parts(38_159_000, 3593) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -93,8 +93,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `174` // Estimated: `3593` - // Minimum execution time: 14_939_000 picoseconds. - Weight::from_parts(15_302_000, 3593) + // Minimum execution time: 14_147_000 picoseconds. + Weight::from_parts(14_687_000, 3593) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -104,8 +104,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `174` // Estimated: `3593` - // Minimum execution time: 20_516_000 picoseconds. - Weight::from_parts(21_179_000, 3593) + // Minimum execution time: 19_188_000 picoseconds. + Weight::from_parts(19_929_000, 3593) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -115,8 +115,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `103` // Estimated: `6196` - // Minimum execution time: 51_281_000 picoseconds. - Weight::from_parts(52_145_000, 6196) + // Minimum execution time: 48_903_000 picoseconds. + Weight::from_parts(49_944_000, 6196) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(2_u64)) } @@ -126,8 +126,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `3593` - // Minimum execution time: 48_988_000 picoseconds. - Weight::from_parts(49_935_000, 3593) + // Minimum execution time: 46_573_000 picoseconds. + Weight::from_parts(47_385_000, 3593) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -137,8 +137,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `174` // Estimated: `3593` - // Minimum execution time: 17_594_000 picoseconds. - Weight::from_parts(18_232_000, 3593) + // Minimum execution time: 16_750_000 picoseconds. + Weight::from_parts(17_233_000, 3593) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -149,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: 16_701_000 picoseconds. - Weight::from_parts(16_897_000, 990) - // Standard Error: 11_684 - .saturating_add(Weight::from_parts(14_375_201, 0).saturating_mul(u.into())) + // Minimum execution time: 16_333_000 picoseconds. + Weight::from_parts(16_588_000, 990) + // Standard Error: 12_254 + .saturating_add(Weight::from_parts(13_973_659, 0).saturating_mul(u.into())) .saturating_add(T::DbWeight::get().reads((1_u64).saturating_mul(u.into()))) .saturating_add(T::DbWeight::get().writes((1_u64).saturating_mul(u.into()))) .saturating_add(Weight::from_parts(0, 2603).saturating_mul(u.into())) @@ -161,8 +161,22 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 6_692_000 picoseconds. - Weight::from_parts(7_140_000, 0) + // Minimum execution time: 6_265_000 picoseconds. + Weight::from_parts(6_594_000, 0) + } + fn burn_allow_death() -> Weight { + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 30_151_000 picoseconds. + Weight::from_parts(30_968_000, 0) + } + fn burn_keep_alive() -> Weight { + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 20_055_000 picoseconds. + Weight::from_parts(20_711_000, 0) } } @@ -174,8 +188,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `0` // Estimated: `3593` - // Minimum execution time: 50_062_000 picoseconds. - Weight::from_parts(51_214_000, 3593) + // Minimum execution time: 47_552_000 picoseconds. + Weight::from_parts(48_363_000, 3593) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -185,8 +199,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `0` // Estimated: `3593` - // Minimum execution time: 39_700_000 picoseconds. - Weight::from_parts(40_754_000, 3593) + // Minimum execution time: 37_565_000 picoseconds. + Weight::from_parts(38_159_000, 3593) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -196,8 +210,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `174` // Estimated: `3593` - // Minimum execution time: 14_939_000 picoseconds. - Weight::from_parts(15_302_000, 3593) + // Minimum execution time: 14_147_000 picoseconds. + Weight::from_parts(14_687_000, 3593) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -207,8 +221,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `174` // Estimated: `3593` - // Minimum execution time: 20_516_000 picoseconds. - Weight::from_parts(21_179_000, 3593) + // Minimum execution time: 19_188_000 picoseconds. + Weight::from_parts(19_929_000, 3593) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -218,8 +232,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `103` // Estimated: `6196` - // Minimum execution time: 51_281_000 picoseconds. - Weight::from_parts(52_145_000, 6196) + // Minimum execution time: 48_903_000 picoseconds. + Weight::from_parts(49_944_000, 6196) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(2_u64)) } @@ -229,8 +243,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `0` // Estimated: `3593` - // Minimum execution time: 48_988_000 picoseconds. - Weight::from_parts(49_935_000, 3593) + // Minimum execution time: 46_573_000 picoseconds. + Weight::from_parts(47_385_000, 3593) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -240,8 +254,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `174` // Estimated: `3593` - // Minimum execution time: 17_594_000 picoseconds. - Weight::from_parts(18_232_000, 3593) + // Minimum execution time: 16_750_000 picoseconds. + Weight::from_parts(17_233_000, 3593) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -252,10 +266,10 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `0 + u * (135 ±0)` // Estimated: `990 + u * (2603 ±0)` - // Minimum execution time: 16_701_000 picoseconds. - Weight::from_parts(16_897_000, 990) - // Standard Error: 11_684 - .saturating_add(Weight::from_parts(14_375_201, 0).saturating_mul(u.into())) + // Minimum execution time: 16_333_000 picoseconds. + Weight::from_parts(16_588_000, 990) + // Standard Error: 12_254 + .saturating_add(Weight::from_parts(13_973_659, 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())) @@ -264,7 +278,21 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 6_692_000 picoseconds. - Weight::from_parts(7_140_000, 0) + // Minimum execution time: 6_265_000 picoseconds. + Weight::from_parts(6_594_000, 0) + } + fn burn_allow_death() -> Weight { + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 30_151_000 picoseconds. + Weight::from_parts(30_968_000, 0) + } + fn burn_keep_alive() -> Weight { + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 20_055_000 picoseconds. + Weight::from_parts(20_711_000, 0) } } diff --git a/substrate/frame/beefy-mmr/Cargo.toml b/substrate/frame/beefy-mmr/Cargo.toml index 8fcb8e1d559bea2c5082e49cc0002d15745639c0..51abc306265d60a3ffc990fb6878831e12593a60 100644 --- a/substrate/frame/beefy-mmr/Cargo.toml +++ b/substrate/frame/beefy-mmr/Cargo.toml @@ -12,8 +12,8 @@ homepage = "https://substrate.io" workspace = true [dependencies] -array-bytes = { version = "6.1", optional = true } -codec = { package = "parity-scale-codec", version = "3.6.1", default-features = false, features = ["derive"] } +array-bytes = { version = "6.2.2", optional = true } +codec = { package = "parity-scale-codec", version = "3.6.12", default-features = false, features = ["derive"] } log = { workspace = true } scale-info = { version = "2.11.1", default-features = false, features = ["derive"] } serde = { optional = true, workspace = true, default-features = true } @@ -32,7 +32,7 @@ sp-api = { path = "../../primitives/api", default-features = false } sp-state-machine = { path = "../../primitives/state-machine", default-features = false } [dev-dependencies] -array-bytes = "6.1" +array-bytes = "6.2.2" sp-staking = { path = "../../primitives/staking" } [features] diff --git a/substrate/frame/beefy/Cargo.toml b/substrate/frame/beefy/Cargo.toml index f181f4d41cdcb2567654d21b0fefb88b507d6f69..890ac1399b9dfcee8d71348d8eac9ff7b3ae2546 100644 --- a/substrate/frame/beefy/Cargo.toml +++ b/substrate/frame/beefy/Cargo.toml @@ -12,7 +12,7 @@ homepage = "https://substrate.io" workspace = true [dependencies] -codec = { package = "parity-scale-codec", version = "3.6.1", default-features = false, features = ["derive"] } +codec = { package = "parity-scale-codec", version = "3.6.12", default-features = false, features = ["derive"] } log = { workspace = true } scale-info = { version = "2.11.1", default-features = false, features = ["derive", "serde"] } serde = { optional = true, workspace = true, default-features = true } diff --git a/substrate/frame/beefy/src/equivocation.rs b/substrate/frame/beefy/src/equivocation.rs index bbc6eae6af29d8b7beb41d903e6f9bf52af05763..aecc9e721d5c43c938b744b8682f59e96b472970 100644 --- a/substrate/frame/beefy/src/equivocation.rs +++ b/substrate/frame/beefy/src/equivocation.rs @@ -38,7 +38,7 @@ use codec::{self as codec, Decode, Encode}; use frame_support::traits::{Get, KeyOwnerProofSystem}; use frame_system::pallet_prelude::BlockNumberFor; use log::{error, info}; -use sp_consensus_beefy::{EquivocationProof, ValidatorSetId, KEY_TYPE as BEEFY_KEY_TYPE}; +use sp_consensus_beefy::{DoubleVotingProof, ValidatorSetId, KEY_TYPE as BEEFY_KEY_TYPE}; use sp_runtime::{ transaction_validity::{ InvalidTransaction, TransactionPriority, TransactionSource, TransactionValidity, @@ -123,7 +123,7 @@ pub struct EquivocationReportSystem(sp_std::marker::PhantomData<(T, /// Equivocation evidence convenience alias. pub type EquivocationEvidenceFor = ( - EquivocationProof< + DoubleVotingProof< BlockNumberFor, ::BeefyId, <::BeefyId as RuntimeAppPublic>::Signature, diff --git a/substrate/frame/beefy/src/lib.rs b/substrate/frame/beefy/src/lib.rs index 09cd13ab70a4fc1089c794124fd8d7f6f24b7482..63f3e9bb309c6adc452bb27827969de5e1713e89 100644 --- a/substrate/frame/beefy/src/lib.rs +++ b/substrate/frame/beefy/src/lib.rs @@ -41,7 +41,7 @@ use sp_staking::{offence::OffenceReportSystem, SessionIndex}; use sp_std::prelude::*; use sp_consensus_beefy::{ - AuthorityIndex, BeefyAuthorityId, ConsensusLog, EquivocationProof, OnNewValidatorSet, + AuthorityIndex, BeefyAuthorityId, ConsensusLog, DoubleVotingProof, OnNewValidatorSet, ValidatorSet, BEEFY_ENGINE_ID, GENESIS_AUTHORITY_SET_ID, }; @@ -210,7 +210,7 @@ pub mod pallet { pub fn report_equivocation( origin: OriginFor, equivocation_proof: Box< - EquivocationProof< + DoubleVotingProof< BlockNumberFor, T::BeefyId, ::Signature, @@ -245,7 +245,7 @@ pub mod pallet { pub fn report_equivocation_unsigned( origin: OriginFor, equivocation_proof: Box< - EquivocationProof< + DoubleVotingProof< BlockNumberFor, T::BeefyId, ::Signature, @@ -368,7 +368,7 @@ impl Pallet { /// an unsigned extrinsic with a call to `report_equivocation_unsigned` and /// will push the transaction to the pool. Only useful in an offchain context. pub fn submit_unsigned_equivocation_report( - equivocation_proof: EquivocationProof< + equivocation_proof: DoubleVotingProof< BlockNumberFor, T::BeefyId, ::Signature, diff --git a/substrate/frame/beefy/src/mock.rs b/substrate/frame/beefy/src/mock.rs index 1c55adc8de4b7d87535367e1f934c9db171b4902..0b87de6bf5d79a3884d96f6f7cf79fc96ab3568b 100644 --- a/substrate/frame/beefy/src/mock.rs +++ b/substrate/frame/beefy/src/mock.rs @@ -158,7 +158,6 @@ parameter_types! { pub const SessionsPerEra: SessionIndex = 3; pub const BondingDuration: EraIndex = 3; pub const RewardCurve: &'static PiecewiseLinear<'static> = &REWARD_CURVE; - pub const OffendingValidatorsThreshold: Perbill = Perbill::from_percent(17); pub static ElectionsBoundsOnChain: ElectionBounds = ElectionBoundsBuilder::default().build(); } @@ -188,7 +187,6 @@ impl pallet_staking::Config for Test { type UnixTime = pallet_timestamp::Pallet; type EraPayout = pallet_staking::ConvertCurve; type MaxExposurePageSize = ConstU32<64>; - type OffendingValidatorsThreshold = OffendingValidatorsThreshold; type NextNewSession = Session; type ElectionProvider = onchain::OnChainExecution; type GenesisElectionProvider = Self::ElectionProvider; @@ -201,6 +199,7 @@ impl pallet_staking::Config for Test { type EventListeners = (); type BenchmarkingConfig = pallet_staking::TestBenchmarkingConfig; type WeightInfo = (); + type DisablingStrategy = pallet_staking::UpToLimitDisablingStrategy; } impl pallet_offences::Config for Test { diff --git a/substrate/frame/benchmarking/Cargo.toml b/substrate/frame/benchmarking/Cargo.toml index 8210e8cfa626063a32b5528b5469f7029857299f..b5824ab2ec2eeaa2126bd72f6832e87736a8f914 100644 --- a/substrate/frame/benchmarking/Cargo.toml +++ b/substrate/frame/benchmarking/Cargo.toml @@ -16,7 +16,7 @@ workspace = true targets = ["x86_64-unknown-linux-gnu"] [dependencies] -codec = { package = "parity-scale-codec", version = "3.6.1", default-features = false } +codec = { package = "parity-scale-codec", version = "3.6.12", default-features = false } linregress = { version = "0.5.1", optional = true } log = { workspace = true } paste = "1.0" @@ -36,7 +36,7 @@ sp-storage = { path = "../../primitives/storage", default-features = false } static_assertions = "1.1.0" [dev-dependencies] -array-bytes = "6.1" +array-bytes = "6.2.2" rusty-fork = { version = "0.3.0", default-features = false } sp-keystore = { path = "../../primitives/keystore" } diff --git a/substrate/frame/benchmarking/pov/Cargo.toml b/substrate/frame/benchmarking/pov/Cargo.toml index 5d3aaa7890488018eb3715ed13845a7e3d130b50..e4f3c272a63e4938aa2efd6fa30784543383c82a 100644 --- a/substrate/frame/benchmarking/pov/Cargo.toml +++ b/substrate/frame/benchmarking/pov/Cargo.toml @@ -15,7 +15,7 @@ workspace = true targets = ["x86_64-unknown-linux-gnu"] [dependencies] -codec = { package = "parity-scale-codec", version = "3.6.1", default-features = false } +codec = { package = "parity-scale-codec", version = "3.6.12", default-features = false } scale-info = { version = "2.11.1", default-features = false, features = ["derive"] } frame-benchmarking = { path = "..", default-features = false } frame-support = { path = "../../support", default-features = false } diff --git a/substrate/frame/bounties/Cargo.toml b/substrate/frame/bounties/Cargo.toml index 3307e47e9818934d629ff1989aff08ff03de9acf..fac0054359060fd3c63741eaa1897c66990f5523 100644 --- a/substrate/frame/bounties/Cargo.toml +++ b/substrate/frame/bounties/Cargo.toml @@ -16,7 +16,7 @@ workspace = true targets = ["x86_64-unknown-linux-gnu"] [dependencies] -codec = { package = "parity-scale-codec", version = "3.6.1", default-features = false, features = [ +codec = { package = "parity-scale-codec", version = "3.6.12", default-features = false, features = [ "derive", ] } log = { workspace = true } diff --git a/substrate/frame/bounties/src/lib.rs b/substrate/frame/bounties/src/lib.rs index c099fc48b7a3bceb94e8b026386c84aed4edf818..c930868bf10159326bae978553eadcbd3fe03128 100644 --- a/substrate/frame/bounties/src/lib.rs +++ b/substrate/frame/bounties/src/lib.rs @@ -303,12 +303,10 @@ pub mod pallet { /// Number of bounty proposals that have been made. #[pallet::storage] - #[pallet::getter(fn bounty_count)] pub type BountyCount, I: 'static = ()> = StorageValue<_, BountyIndex, ValueQuery>; /// Bounties that have been made. #[pallet::storage] - #[pallet::getter(fn bounties)] pub type Bounties, I: 'static = ()> = StorageMap< _, Twox64Concat, @@ -318,13 +316,11 @@ pub mod pallet { /// The description of each bounty. #[pallet::storage] - #[pallet::getter(fn bounty_descriptions)] pub type BountyDescriptions, I: 'static = ()> = StorageMap<_, Twox64Concat, BountyIndex, BoundedVec>; /// Bounty indices that have been approved but not yet funded. #[pallet::storage] - #[pallet::getter(fn bounty_approvals)] pub type BountyApprovals, I: 'static = ()> = StorageValue<_, BoundedVec, ValueQuery>; @@ -849,7 +845,7 @@ impl, I: 'static> Pallet { description.try_into().map_err(|_| Error::::ReasonTooBig)?; ensure!(value >= T::BountyValueMinimum::get(), Error::::InvalidValue); - let index = Self::bounty_count(); + let index = BountyCount::::get(); // reserve deposit for new bounty let bond = T::BountyDepositBase::get() + diff --git a/substrate/frame/bounties/src/tests.rs b/substrate/frame/bounties/src/tests.rs index de747db53749902ad6164265e3cad139ddefa7da..a89f4ff9fbf301a8d03d9ad040a1b4009e7b18f6 100644 --- a/substrate/frame/bounties/src/tests.rs +++ b/substrate/frame/bounties/src/tests.rs @@ -534,7 +534,7 @@ fn propose_bounty_works() { assert_eq!(Balances::free_balance(0), 100 - deposit); assert_eq!( - Bounties::bounties(0).unwrap(), + pallet_bounties::Bounties::::get(0).unwrap(), Bounty { proposer: 0, fee: 0, @@ -545,9 +545,12 @@ fn propose_bounty_works() { } ); - assert_eq!(Bounties::bounty_descriptions(0).unwrap(), b"1234567890".to_vec()); + assert_eq!( + pallet_bounties::BountyDescriptions::::get(0).unwrap(), + b"1234567890".to_vec() + ); - assert_eq!(Bounties::bounty_count(), 1); + assert_eq!(pallet_bounties::BountyCount::::get(), 1); }); } @@ -598,10 +601,10 @@ fn close_bounty_works() { assert_eq!(Balances::reserved_balance(0), 0); assert_eq!(Balances::free_balance(0), 100 - deposit); - assert_eq!(Bounties::bounties(0), None); + assert_eq!(pallet_bounties::Bounties::::get(0), None); assert!(!pallet_treasury::Proposals::::contains_key(0)); - assert_eq!(Bounties::bounty_descriptions(0), None); + assert_eq!(pallet_bounties::BountyDescriptions::::get(0), None); }); } @@ -622,7 +625,7 @@ fn approve_bounty_works() { let deposit: u64 = 80 + 5; assert_eq!( - Bounties::bounties(0).unwrap(), + pallet_bounties::Bounties::::get(0).unwrap(), Bounty { proposer: 0, fee: 0, @@ -632,7 +635,7 @@ fn approve_bounty_works() { status: BountyStatus::Approved, } ); - assert_eq!(Bounties::bounty_approvals(), vec![0]); + assert_eq!(pallet_bounties::BountyApprovals::::get(), vec![0]); assert_noop!( Bounties::close_bounty(RuntimeOrigin::root(), 0), @@ -650,7 +653,7 @@ fn approve_bounty_works() { assert_eq!(Balances::free_balance(0), 100); assert_eq!( - Bounties::bounties(0).unwrap(), + pallet_bounties::Bounties::::get(0).unwrap(), Bounty { proposer: 0, fee: 0, @@ -693,7 +696,7 @@ fn assign_curator_works() { assert_ok!(Bounties::propose_curator(RuntimeOrigin::root(), 0, 4, fee)); assert_eq!( - Bounties::bounties(0).unwrap(), + pallet_bounties::Bounties::::get(0).unwrap(), Bounty { proposer: 0, fee, @@ -720,7 +723,7 @@ fn assign_curator_works() { let expected_deposit = Bounties::calculate_curator_deposit(&fee); assert_eq!( - Bounties::bounties(0).unwrap(), + pallet_bounties::Bounties::::get(0).unwrap(), Bounty { proposer: 0, fee, @@ -755,7 +758,7 @@ fn unassign_curator_works() { assert_ok!(Bounties::unassign_curator(RuntimeOrigin::signed(4), 0)); assert_eq!( - Bounties::bounties(0).unwrap(), + pallet_bounties::Bounties::::get(0).unwrap(), Bounty { proposer: 0, fee, @@ -773,7 +776,7 @@ fn unassign_curator_works() { assert_ok!(Bounties::unassign_curator(RuntimeOrigin::root(), 0)); assert_eq!( - Bounties::bounties(0).unwrap(), + pallet_bounties::Bounties::::get(0).unwrap(), Bounty { proposer: 0, fee, @@ -817,7 +820,7 @@ fn award_and_claim_bounty_works() { assert_ok!(Bounties::award_bounty(RuntimeOrigin::signed(4), 0, 3)); assert_eq!( - Bounties::bounties(0).unwrap(), + pallet_bounties::Bounties::::get(0).unwrap(), Bounty { proposer: 0, fee, @@ -851,8 +854,8 @@ fn award_and_claim_bounty_works() { assert_eq!(Balances::free_balance(3), 56); assert_eq!(Balances::free_balance(Bounties::bounty_account_id(0)), 0); - assert_eq!(Bounties::bounties(0), None); - assert_eq!(Bounties::bounty_descriptions(0), None); + assert_eq!(pallet_bounties::Bounties::::get(0), None); + assert_eq!(pallet_bounties::BountyDescriptions::::get(0), None); }); } @@ -892,8 +895,8 @@ fn claim_handles_high_fee() { assert_eq!(Balances::free_balance(3), 0); assert_eq!(Balances::free_balance(Bounties::bounty_account_id(0)), 0); - assert_eq!(Bounties::bounties(0), None); - assert_eq!(Bounties::bounty_descriptions(0), None); + assert_eq!(pallet_bounties::Bounties::::get(0), None); + assert_eq!(pallet_bounties::BountyDescriptions::::get(0), None); }); } @@ -918,7 +921,7 @@ fn cancel_and_refund() { )); assert_eq!( - Bounties::bounties(0).unwrap(), + pallet_bounties::Bounties::::get(0).unwrap(), Bounty { proposer: 0, fee: 0, @@ -978,8 +981,8 @@ fn award_and_cancel() { assert_eq!(Balances::free_balance(0), 95); assert_eq!(Balances::reserved_balance(0), 0); - assert_eq!(Bounties::bounties(0), None); - assert_eq!(Bounties::bounty_descriptions(0), None); + assert_eq!(pallet_bounties::Bounties::::get(0), None); + assert_eq!(pallet_bounties::BountyDescriptions::::get(0), None); }); } @@ -1015,7 +1018,7 @@ fn expire_and_unassign() { assert_ok!(Bounties::unassign_curator(RuntimeOrigin::signed(0), 0)); assert_eq!( - Bounties::bounties(0).unwrap(), + pallet_bounties::Bounties::::get(0).unwrap(), Bounty { proposer: 0, fee: 10, @@ -1065,7 +1068,7 @@ fn extend_expiry() { assert_ok!(Bounties::extend_bounty_expiry(RuntimeOrigin::signed(4), 0, Vec::new())); assert_eq!( - Bounties::bounties(0).unwrap(), + pallet_bounties::Bounties::::get(0).unwrap(), Bounty { proposer: 0, fee: 10, @@ -1079,7 +1082,7 @@ fn extend_expiry() { assert_ok!(Bounties::extend_bounty_expiry(RuntimeOrigin::signed(4), 0, Vec::new())); assert_eq!( - Bounties::bounties(0).unwrap(), + pallet_bounties::Bounties::::get(0).unwrap(), Bounty { proposer: 0, fee: 10, @@ -1190,7 +1193,7 @@ fn unassign_curator_self() { assert_ok!(Bounties::unassign_curator(RuntimeOrigin::signed(1), 0)); assert_eq!( - Bounties::bounties(0).unwrap(), + pallet_bounties::Bounties::::get(0).unwrap(), Bounty { proposer: 0, fee: 10, diff --git a/substrate/frame/broker/Cargo.toml b/substrate/frame/broker/Cargo.toml index f36b94c3cec567ebe25a2194876598e5a3b92a56..8f3f30ec58ebc2ff868cee03037939d0e9aac884 100644 --- a/substrate/frame/broker/Cargo.toml +++ b/substrate/frame/broker/Cargo.toml @@ -15,7 +15,8 @@ workspace = true targets = ["x86_64-unknown-linux-gnu"] [dependencies] -codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = ["derive"] } +log = { workspace = true } +codec = { package = "parity-scale-codec", version = "3.6.12", default-features = false, features = ["derive"] } scale-info = { version = "2.11.1", default-features = false, features = ["derive"] } bitvec = { version = "1.0.0", default-features = false } sp-api = { path = "../../primitives/api", default-features = false } @@ -40,6 +41,7 @@ std = [ "frame-benchmarking?/std", "frame-support/std", "frame-system/std", + "log/std", "scale-info/std", "sp-api/std", "sp-arithmetic/std", diff --git a/substrate/frame/broker/src/benchmarking.rs b/substrate/frame/broker/src/benchmarking.rs index 98ac074ca91778cfd2538cc0e89f90ca79a62ad5..7533e3dc68c41fa54d39b7bb234ecaafe4e56fab 100644 --- a/substrate/frame/broker/src/benchmarking.rs +++ b/substrate/frame/broker/src/benchmarking.rs @@ -189,11 +189,15 @@ mod benches { let config = new_config_record::(); Configuration::::put(config.clone()); + let mut extra_cores = n; + // Assume Reservations to be filled for worst case - setup_reservations::(T::MaxReservedCores::get()); + setup_reservations::(extra_cores.min(T::MaxReservedCores::get())); + extra_cores = extra_cores.saturating_sub(T::MaxReservedCores::get()); // Assume Leases to be filled for worst case - setup_leases::(T::MaxLeasedCores::get(), 1, 10); + setup_leases::(extra_cores.min(T::MaxLeasedCores::get()), 1, 10); + extra_cores = extra_cores.saturating_sub(T::MaxLeasedCores::get()); let latest_region_begin = Broker::::latest_timeslice_ready_to_commit(&config); @@ -203,7 +207,7 @@ mod benches { T::AdminOrigin::try_successful_origin().map_err(|_| BenchmarkError::Weightless)?; #[extrinsic_call] - _(origin as T::RuntimeOrigin, initial_price, n.try_into().unwrap()); + _(origin as T::RuntimeOrigin, initial_price, extra_cores.try_into().unwrap()); assert!(SaleInfo::::get().is_some()); assert_last_event::( @@ -313,8 +317,8 @@ mod benches { assert_last_event::( Event::Transferred { region_id: region, - old_owner: caller, - owner: recipient, + old_owner: Some(caller), + owner: Some(recipient), duration: 3u32.into(), } .into(), diff --git a/substrate/frame/broker/src/dispatchable_impls.rs b/substrate/frame/broker/src/dispatchable_impls.rs index c2e731462ca58bb042ffe08c3b2c59af2cf3954c..45a0a514c307adaeb8be65f514e6c46251210d06 100644 --- a/substrate/frame/broker/src/dispatchable_impls.rs +++ b/substrate/frame/broker/src/dispatchable_impls.rs @@ -70,8 +70,16 @@ impl Pallet { Ok(()) } - pub(crate) fn do_start_sales(price: BalanceOf, core_count: CoreIndex) -> DispatchResult { + pub(crate) fn do_start_sales(price: BalanceOf, extra_cores: CoreIndex) -> DispatchResult { let config = Configuration::::get().ok_or(Error::::Uninitialized)?; + + // Determine the core count + let core_count = Leases::::decode_len().unwrap_or(0) as CoreIndex + + Reservations::::decode_len().unwrap_or(0) as CoreIndex + + extra_cores; + + Self::do_request_core_count(core_count)?; + let commit_timeslice = Self::latest_timeslice_ready_to_commit(&config); let status = StatusRecord { core_count, @@ -120,7 +128,8 @@ impl Pallet { sale.sellout_price = Some(price); } SaleInfo::::put(&sale); - let id = Self::issue(core, sale.region_begin, sale.region_end, who.clone(), Some(price)); + let id = + Self::issue(core, sale.region_begin, sale.region_end, Some(who.clone()), Some(price)); let duration = sale.region_end.saturating_sub(sale.region_begin); Self::deposit_event(Event::Purchased { who, region_id: id, price, duration }); Ok(id) @@ -178,11 +187,11 @@ impl Pallet { let mut region = Regions::::get(®ion_id).ok_or(Error::::UnknownRegion)?; if let Some(check_owner) = maybe_check_owner { - ensure!(check_owner == region.owner, Error::::NotOwner); + ensure!(Some(check_owner) == region.owner, Error::::NotOwner); } let old_owner = region.owner; - region.owner = new_owner; + region.owner = Some(new_owner); Regions::::insert(®ion_id, ®ion); let duration = region.end.saturating_sub(region_id.begin); Self::deposit_event(Event::Transferred { @@ -203,7 +212,7 @@ impl Pallet { let mut region = Regions::::get(®ion_id).ok_or(Error::::UnknownRegion)?; if let Some(check_owner) = maybe_check_owner { - ensure!(check_owner == region.owner, Error::::NotOwner); + ensure!(Some(check_owner) == region.owner, Error::::NotOwner); } let pivot = region_id.begin.saturating_add(pivot_offset); ensure!(pivot < region.end, Error::::PivotTooLate); @@ -227,7 +236,7 @@ impl Pallet { let region = Regions::::get(®ion_id).ok_or(Error::::UnknownRegion)?; if let Some(check_owner) = maybe_check_owner { - ensure!(check_owner == region.owner, Error::::NotOwner); + ensure!(Some(check_owner) == region.owner, Error::::NotOwner); } ensure!((pivot & !region_id.mask).is_void(), Error::::ExteriorPivot); @@ -419,7 +428,10 @@ impl Pallet { pub(crate) fn do_drop_history(when: Timeslice) -> DispatchResult { let config = Configuration::::get().ok_or(Error::::Uninitialized)?; let status = Status::::get().ok_or(Error::::Uninitialized)?; - ensure!(status.last_timeslice > when + config.contribution_timeout, Error::::StillValid); + ensure!( + status.last_timeslice > when.saturating_add(config.contribution_timeout), + Error::::StillValid + ); let record = InstaPoolHistory::::take(when).ok_or(Error::::NoHistory)?; if let Some(payout) = record.maybe_payout { let _ = Self::charge(&Self::account_id(), payout); diff --git a/substrate/frame/broker/src/lib.rs b/substrate/frame/broker/src/lib.rs index 330491eb2087f032435bb07636694bd27da470ef..d59c4c9c6b24e4e576580715378a32b48f61eb91 100644 --- a/substrate/frame/broker/src/lib.rs +++ b/substrate/frame/broker/src/lib.rs @@ -36,6 +36,7 @@ mod tick_impls; mod types; mod utility_impls; +pub mod migration; pub mod runtime_api; pub mod weights; @@ -46,6 +47,9 @@ pub use core_mask::*; pub use coretime_interface::*; pub use types::*; +/// The log target for this pallet. +const LOG_TARGET: &str = "runtime::broker"; + #[frame_support::pallet] pub mod pallet { use super::*; @@ -61,7 +65,10 @@ pub mod pallet { use sp_runtime::traits::{Convert, ConvertBack}; use sp_std::vec::Vec; + const STORAGE_VERSION: StorageVersion = StorageVersion::new(1); + #[pallet::pallet] + #[pallet::storage_version(STORAGE_VERSION)] pub struct Pallet(_); #[pallet::config] @@ -216,9 +223,9 @@ pub mod pallet { /// The duration of the Region. duration: Timeslice, /// The old owner of the Region. - old_owner: T::AccountId, + old_owner: Option, /// The new owner of the Region. - owner: T::AccountId, + owner: Option, }, /// A Region has been split into two non-overlapping Regions. Partitioned { @@ -552,27 +559,22 @@ pub mod pallet { /// /// - `origin`: Must be Root or pass `AdminOrigin`. /// - `initial_price`: The price of Bulk Coretime in the first sale. - /// - `total_core_count`: This is the total number of cores the relay chain should have - /// after the sale concludes. - /// - /// NOTE: This function does not actually request that new core count from the relay chain. - /// You need to make sure to call `request_core_count` afterwards to bring the relay chain - /// in sync. + /// - `extra_cores`: Number of extra cores that should be requested on top of the cores + /// required for `Reservations` and `Leases`. /// - /// When to call the function depends on the new core count. If it is larger than what it - /// was before, you can call it immediately or even before `start_sales` as non allocated - /// cores will just be `Idle`. If you are actually reducing the number of cores, you should - /// call `request_core_count`, right before the next sale, to avoid shutting down tasks too - /// early. + /// This will call [`Self::request_core_count`] internally to set the correct core count on + /// the relay chain. #[pallet::call_index(4)] - #[pallet::weight(T::WeightInfo::start_sales((*total_core_count).into()))] + #[pallet::weight(T::WeightInfo::start_sales( + T::MaxLeasedCores::get() + T::MaxReservedCores::get() + *extra_cores as u32 + ))] pub fn start_sales( origin: OriginFor, initial_price: BalanceOf, - total_core_count: CoreIndex, + extra_cores: CoreIndex, ) -> DispatchResultWithPostInfo { T::AdminOrigin::ensure_origin_or_root(origin)?; - Self::do_start_sales(initial_price, total_core_count)?; + Self::do_start_sales(initial_price, extra_cores)?; Ok(Pays::No.into()) } diff --git a/substrate/frame/broker/src/migration.rs b/substrate/frame/broker/src/migration.rs new file mode 100644 index 0000000000000000000000000000000000000000..95aa28250a628e8352f6e4852a5588cbdad2a5e8 --- /dev/null +++ b/substrate/frame/broker/src/migration.rs @@ -0,0 +1,87 @@ +// This file is part of Substrate. + +// Copyright (C) Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +use super::*; +use crate::types::RegionRecord; +use codec::{Decode, Encode}; +use core::marker::PhantomData; +use frame_support::traits::{Get, UncheckedOnRuntimeUpgrade}; +use sp_runtime::Saturating; + +#[cfg(feature = "try-runtime")] +use frame_support::ensure; +#[cfg(feature = "try-runtime")] +use sp_std::vec::Vec; + +mod v1 { + use super::*; + + /// V0 region record. + #[derive(Encode, Decode)] + struct RegionRecordV0 { + /// The end of the Region. + pub end: Timeslice, + /// The owner of the Region. + pub owner: AccountId, + /// The amount paid to Polkadot for this Region, or `None` if renewal is not allowed. + pub paid: Option, + } + + pub struct MigrateToV1Impl(PhantomData); + + impl UncheckedOnRuntimeUpgrade for MigrateToV1Impl { + fn on_runtime_upgrade() -> frame_support::weights::Weight { + let mut count: u64 = 0; + + >::translate::>, _>(|_, v0| { + count.saturating_inc(); + Some(RegionRecord { end: v0.end, owner: Some(v0.owner), paid: v0.paid }) + }); + + log::info!( + target: LOG_TARGET, + "Storage migration v1 for pallet-broker finished.", + ); + + // calculate and return migration weights + T::DbWeight::get().reads_writes(count as u64 + 1, count as u64 + 1) + } + + #[cfg(feature = "try-runtime")] + fn pre_upgrade() -> Result, sp_runtime::TryRuntimeError> { + Ok((Regions::::iter_keys().count() as u32).encode()) + } + + #[cfg(feature = "try-runtime")] + fn post_upgrade(state: Vec) -> Result<(), sp_runtime::TryRuntimeError> { + let old_count = u32::decode(&mut &state[..]).expect("Known good"); + let new_count = Regions::::iter_values().count() as u32; + + ensure!(old_count == new_count, "Regions count should not change"); + Ok(()) + } + } +} + +/// Migrate the pallet storage from `0` to `1`. +pub type MigrateV0ToV1 = frame_support::migrations::VersionedMigration< + 0, + 1, + v1::MigrateToV1Impl, + Pallet, + ::DbWeight, +>; diff --git a/substrate/frame/broker/src/nonfungible_impl.rs b/substrate/frame/broker/src/nonfungible_impl.rs index b2e88bf09a0e9d59e90648c0e202872969b4f391..80dcc175df539bbc9861fdaa30adfdab1bb40172 100644 --- a/substrate/frame/broker/src/nonfungible_impl.rs +++ b/substrate/frame/broker/src/nonfungible_impl.rs @@ -25,12 +25,13 @@ use sp_std::vec::Vec; impl Inspect for Pallet { type ItemId = u128; - fn owner(index: &Self::ItemId) -> Option { - Regions::::get(RegionId::from(*index)).map(|r| r.owner) + fn owner(item: &Self::ItemId) -> Option { + let record = Regions::::get(RegionId::from(*item))?; + record.owner } - fn attribute(index: &Self::ItemId, key: &[u8]) -> Option> { - let id = RegionId::from(*index); + fn attribute(item: &Self::ItemId, key: &[u8]) -> Option> { + let id = RegionId::from(*item); let item = Regions::::get(id)?; match key { b"begin" => Some(id.begin.encode()), @@ -46,11 +47,49 @@ impl Inspect for Pallet { } impl Transfer for Pallet { - fn transfer(index: &Self::ItemId, dest: &T::AccountId) -> DispatchResult { - Self::do_transfer((*index).into(), None, dest.clone()).map_err(Into::into) + fn transfer(item: &Self::ItemId, dest: &T::AccountId) -> DispatchResult { + Self::do_transfer((*item).into(), None, dest.clone()).map_err(Into::into) } } -// We don't allow any of the mutate operations, so the default implementation is used, which will -// return `TokenError::Unsupported` in case any of the operations is called. -impl Mutate for Pallet {} +/// We don't really support burning and minting. +/// +/// We only need this to allow the region to be reserve transferable. +/// +/// For reserve transfers that are not 'local', the asset must first be withdrawn to the holding +/// register and then deposited into the designated account. This process necessitates that the +/// asset is capable of being 'burned' and 'minted'. +/// +/// Since each region is associated with specific record data, we will not actually burn the asset. +/// If we did, we wouldn't know what record to assign to the newly minted region. Therefore, instead +/// of burning, we set the asset's owner to `None`. In essence, 'burning' a region involves setting +/// its owner to `None`, whereas 'minting' the region assigns its owner to an actual account. This +/// way we never lose track of the associated record data. +impl Mutate for Pallet { + /// Deposit a region into an account. + fn mint_into(item: &Self::ItemId, who: &T::AccountId) -> DispatchResult { + let region_id: RegionId = (*item).into(); + let record = Regions::::get(®ion_id).ok_or(Error::::UnknownRegion)?; + + // 'Minting' can only occur if the asset has previously been burned (i.e. moved to the + // holding register) + ensure!(record.owner.is_none(), Error::::NotAllowed); + Self::issue(region_id.core, region_id.begin, record.end, Some(who.clone()), record.paid); + + Ok(()) + } + + /// Withdraw a region from account. + fn burn(item: &Self::ItemId, maybe_check_owner: Option<&T::AccountId>) -> DispatchResult { + let region_id: RegionId = (*item).into(); + let mut record = Regions::::get(®ion_id).ok_or(Error::::UnknownRegion)?; + if let Some(owner) = maybe_check_owner { + ensure!(Some(owner.clone()) == record.owner, Error::::NotOwner); + } + + record.owner = None; + Regions::::insert(region_id, record); + + Ok(()) + } +} diff --git a/substrate/frame/broker/src/tests.rs b/substrate/frame/broker/src/tests.rs index 7fc7e31e9bb6e3e4141422393944bc2b6fd5b0ee..f929f0d50dcfaf3d8e7e77d07e260d54c75b1a27 100644 --- a/substrate/frame/broker/src/tests.rs +++ b/substrate/frame/broker/src/tests.rs @@ -146,6 +146,7 @@ fn drop_history_works() { advance_to(16); assert_eq!(InstaPoolHistory::::iter().count(), 6); advance_to(17); + assert_noop!(Broker::do_drop_history(u32::MAX), Error::::StillValid); assert_noop!(Broker::do_drop_history(region.begin), Error::::StillValid); advance_to(18); assert_eq!(InstaPoolHistory::::iter().count(), 6); @@ -199,14 +200,35 @@ fn transfer_works() { } #[test] -fn mutate_operations_unsupported_for_regions() { - TestExt::new().execute_with(|| { +fn mutate_operations_work() { + TestExt::new().endow(1, 1000).execute_with(|| { let region_id = RegionId { begin: 0, core: 0, mask: CoreMask::complete() }; assert_noop!( >::mint_into(®ion_id.into(), &2), - TokenError::Unsupported + Error::::UnknownRegion + ); + + assert_ok!(Broker::do_start_sales(100, 1)); + advance_to(2); + let region_id = Broker::do_purchase(1, u64::max_value()).unwrap(); + assert_noop!( + >::mint_into(®ion_id.into(), &2), + Error::::NotAllowed + ); + + assert_noop!( + >::burn(®ion_id.into(), Some(&2)), + Error::::NotOwner ); - assert_noop!(>::burn(®ion_id.into(), None), TokenError::Unsupported); + // 'withdraw' the region from user 1: + assert_ok!(>::burn(®ion_id.into(), Some(&1))); + assert_eq!(Regions::::get(region_id).unwrap().owner, None); + + // `mint_into` works after burning: + assert_ok!(>::mint_into(®ion_id.into(), &2)); + assert_eq!(Regions::::get(region_id).unwrap().owner, Some(2)); + + // Unsupported operations: assert_noop!( >::set_attribute(®ion_id.into(), &[], &[]), TokenError::Unsupported @@ -284,7 +306,7 @@ fn nft_metadata_works() { assert_eq!(attribute::(region, b"begin"), 4); assert_eq!(attribute::(region, b"length"), 3); assert_eq!(attribute::(region, b"end"), 7); - assert_eq!(attribute::(region, b"owner"), 1); + assert_eq!(attribute::>(region, b"owner"), Some(1)); assert_eq!(attribute::(region, b"part"), 0xfffff_fffff_fffff_fffff.into()); assert_eq!(attribute::(region, b"core"), 0); assert_eq!(attribute::>(region, b"paid"), Some(100)); @@ -296,7 +318,7 @@ fn nft_metadata_works() { assert_eq!(attribute::(region, b"begin"), 6); assert_eq!(attribute::(region, b"length"), 1); assert_eq!(attribute::(region, b"end"), 7); - assert_eq!(attribute::(region, b"owner"), 42); + assert_eq!(attribute::>(region, b"owner"), Some(42)); assert_eq!(attribute::(region, b"part"), 0x00000_fffff_fffff_00000.into()); assert_eq!(attribute::(region, b"core"), 0); assert_eq!(attribute::>(region, b"paid"), None); @@ -307,7 +329,7 @@ fn nft_metadata_works() { fn migration_works() { TestExt::new().endow(1, 1000).execute_with(|| { assert_ok!(Broker::do_set_lease(1000, 8)); - assert_ok!(Broker::do_start_sales(100, 2)); + assert_ok!(Broker::do_start_sales(100, 1)); // Sale is for regions from TS4..7 // Not ending in this sale period. @@ -363,7 +385,7 @@ fn instapool_payouts_work() { TestExt::new().endow(1, 1000).execute_with(|| { let item = ScheduleItem { assignment: Pool, mask: CoreMask::complete() }; assert_ok!(Broker::do_reserve(Schedule::truncate_from(vec![item]))); - assert_ok!(Broker::do_start_sales(100, 3)); + assert_ok!(Broker::do_start_sales(100, 2)); advance_to(2); let region = Broker::do_purchase(1, u64::max_value()).unwrap(); assert_ok!(Broker::do_pool(region, None, 2, Final)); @@ -389,7 +411,7 @@ fn instapool_partial_core_payouts_work() { TestExt::new().endow(1, 1000).execute_with(|| { let item = ScheduleItem { assignment: Pool, mask: CoreMask::complete() }; assert_ok!(Broker::do_reserve(Schedule::truncate_from(vec![item]))); - assert_ok!(Broker::do_start_sales(100, 2)); + assert_ok!(Broker::do_start_sales(100, 1)); advance_to(2); let region = Broker::do_purchase(1, u64::max_value()).unwrap(); let (region1, region2) = @@ -455,7 +477,7 @@ fn initialize_with_system_paras_works() { ScheduleItem { assignment: Task(4u32), mask: 0x00000_00000_00000_fffff.into() }, ]; assert_ok!(Broker::do_reserve(Schedule::truncate_from(items))); - assert_ok!(Broker::do_start_sales(100, 2)); + assert_ok!(Broker::do_start_sales(100, 0)); advance_to(10); assert_eq!( CoretimeTrace::get(), @@ -488,7 +510,7 @@ fn initialize_with_leased_slots_works() { TestExt::new().execute_with(|| { assert_ok!(Broker::do_set_lease(1000, 6)); assert_ok!(Broker::do_set_lease(1001, 7)); - assert_ok!(Broker::do_start_sales(100, 2)); + assert_ok!(Broker::do_start_sales(100, 0)); advance_to(18); let end_hint = None; assert_eq!( @@ -892,6 +914,161 @@ fn short_leases_are_cleaned() { }); } +#[test] +fn leases_can_be_renewed() { + TestExt::new().endow(1, 1000).execute_with(|| { + // Timeslice period is 2. + // + // Sale 1 starts at block 7, Sale 2 starts at 13. + + // Set lease to expire in sale 1 and start sales. + assert_ok!(Broker::do_set_lease(2001, 9)); + assert_eq!(Leases::::get().len(), 1); + // Start the sales with only one core for this lease. + assert_ok!(Broker::do_start_sales(100, 0)); + + // Advance to sale period 1, we should get an AllowedRenewal for task 2001 for the next + // sale. + advance_sale_period(); + assert_eq!( + AllowedRenewals::::get(AllowedRenewalId { core: 0, when: 10 }), + Some(AllowedRenewalRecord { + price: 100, + completion: CompletionStatus::Complete( + vec![ScheduleItem { mask: CoreMask::complete(), assignment: Task(2001) }] + .try_into() + .unwrap() + ) + }) + ); + // And the lease has been removed from storage. + assert_eq!(Leases::::get().len(), 0); + + // Advance to sale period 2, where we can renew. + advance_sale_period(); + assert_ok!(Broker::do_renew(1, 0)); + // We renew for the base price of the previous sale period. + assert_eq!(balance(1), 900); + + // We just renewed for this period. + advance_sale_period(); + // Now we are off core and the core is pooled. + advance_sale_period(); + // Check the trace agrees. + assert_eq!( + CoretimeTrace::get(), + vec![ + // Period 0 gets no assign core, but leases are on-core. + // Period 1: + ( + 6, + AssignCore { + core: 0, + begin: 8, + assignment: vec![(CoreAssignment::Task(2001), 57600)], + end_hint: None, + }, + ), + // Period 2 - expiring at the end of this period, so we called renew. + ( + 12, + AssignCore { + core: 0, + begin: 14, + assignment: vec![(CoreAssignment::Task(2001), 57600)], + end_hint: None, + }, + ), + // Period 3 - we get assigned a core because we called renew in period 2. + ( + 18, + AssignCore { + core: 0, + begin: 20, + assignment: vec![(CoreAssignment::Task(2001), 57600)], + end_hint: None, + }, + ), + // Period 4 - we don't get a core as we didn't call renew again. + // This core is recycled into the pool. + ( + 24, + AssignCore { + core: 0, + begin: 26, + assignment: vec![(CoreAssignment::Pool, 57600)], + end_hint: None, + }, + ), + ] + ); + }); +} + +// We understand that this does not work as intended for leases that expire within `region_length` +// timeslices after calling `start_sales`. +#[test] +fn short_leases_cannot_be_renewed() { + TestExt::new().endow(1, 1000).execute_with(|| { + // Timeslice period is 2. + // + // Sale 1 starts at block 7, Sale 2 starts at 13. + + // Set lease to expire in sale period 0 and start sales. + assert_ok!(Broker::do_set_lease(2001, 3)); + assert_eq!(Leases::::get().len(), 1); + // Start the sales with one core for this lease. + assert_ok!(Broker::do_start_sales(100, 0)); + + // The lease is removed. + assert_eq!(Leases::::get().len(), 0); + + // We should have got an entry in AllowedRenewals, but we don't because rotate_sale + // schedules leases a period in advance. This renewal should be in the period after next + // because while bootstrapping our way into the sale periods, we give everything a lease for + // period 1, so they can renew for period 2. So we have a core until the end of period 1, + // but we are not marked as able to renew because we expired before sale period 1 starts. + // + // This should be fixed. + assert_eq!(AllowedRenewals::::get(AllowedRenewalId { core: 0, when: 10 }), None); + // And the lease has been removed from storage. + assert_eq!(Leases::::get().len(), 0); + + // Advance to sale period 2, where we now cannot renew. + advance_to(13); + assert_noop!(Broker::do_renew(1, 0), Error::::NotAllowed); + + // Check the trace. + assert_eq!( + CoretimeTrace::get(), + vec![ + // Period 0 gets no assign core, but leases are on-core. + // Period 1 we get assigned a core due to the way the sales are bootstrapped. + ( + 6, + AssignCore { + core: 0, + begin: 8, + assignment: vec![(CoreAssignment::Task(2001), 57600)], + end_hint: None, + }, + ), + // Period 2 - we don't get a core as we couldn't renew. + // This core is recycled into the pool. + ( + 12, + AssignCore { + core: 0, + begin: 14, + assignment: vec![(CoreAssignment::Pool, 57600)], + end_hint: None, + }, + ), + ] + ); + }); +} + #[test] fn leases_are_limited() { TestExt::new().execute_with(|| { @@ -1113,7 +1290,7 @@ fn renewal_works_leases_ended_before_start_sales() { )); // This intializes the first sale and the period 0. - assert_ok!(Broker::do_start_sales(100, 2)); + assert_ok!(Broker::do_start_sales(100, 0)); assert_noop!(Broker::do_renew(1, 1), Error::::Unavailable); assert_noop!(Broker::do_renew(1, 0), Error::::Unavailable); @@ -1231,3 +1408,23 @@ fn renewal_works_leases_ended_before_start_sales() { ); }); } + +#[test] +fn start_sales_sets_correct_core_count() { + TestExt::new().endow(1, 1000).execute_with(|| { + advance_to(1); + + Broker::do_set_lease(1, 100).unwrap(); + Broker::do_set_lease(2, 100).unwrap(); + Broker::do_set_lease(3, 100).unwrap(); + Broker::do_reserve(Schedule::truncate_from(vec![ScheduleItem { + assignment: Pool, + mask: CoreMask::complete(), + }])) + .unwrap(); + + Broker::do_start_sales(5, 5).unwrap(); + + System::assert_has_event(Event::::CoreCountRequested { core_count: 9 }.into()); + }) +} diff --git a/substrate/frame/broker/src/types.rs b/substrate/frame/broker/src/types.rs index e8119d29ef5d38e25060514d624713a6eedd11a8..f2cae9a41ad480b1e4608a4d556b10d166282c1d 100644 --- a/substrate/frame/broker/src/types.rs +++ b/substrate/frame/broker/src/types.rs @@ -84,7 +84,7 @@ pub struct RegionRecord { /// The end of the Region. pub end: Timeslice, /// The owner of the Region. - pub owner: AccountId, + pub owner: Option, /// The amount paid to Polkadot for this Region, or `None` if renewal is not allowed. pub paid: Option, } diff --git a/substrate/frame/broker/src/utility_impls.rs b/substrate/frame/broker/src/utility_impls.rs index 3dba5be5b398b8f30156179e7dd1b203fff5e311..4163817a8b584bd949210aff383398ff50b95d58 100644 --- a/substrate/frame/broker/src/utility_impls.rs +++ b/substrate/frame/broker/src/utility_impls.rs @@ -72,11 +72,11 @@ impl Pallet { Ok(()) } - pub(crate) fn issue( + pub fn issue( core: CoreIndex, begin: Timeslice, end: Timeslice, - owner: T::AccountId, + owner: Option, paid: Option>, ) -> RegionId { let id = RegionId { begin, core, mask: CoreMask::complete() }; @@ -94,7 +94,7 @@ impl Pallet { let region = Regions::::get(®ion_id).ok_or(Error::::UnknownRegion)?; if let Some(check_owner) = maybe_check_owner { - ensure!(check_owner == region.owner, Error::::NotOwner); + ensure!(Some(check_owner) == region.owner, Error::::NotOwner); } Regions::::remove(®ion_id); diff --git a/substrate/frame/child-bounties/Cargo.toml b/substrate/frame/child-bounties/Cargo.toml index 14a5e25e13da6a246e3935c90839a350bf773d2e..09271632df54b74601d5d318a4749bffcbc86777 100644 --- a/substrate/frame/child-bounties/Cargo.toml +++ b/substrate/frame/child-bounties/Cargo.toml @@ -16,7 +16,7 @@ workspace = true targets = ["x86_64-unknown-linux-gnu"] [dependencies] -codec = { package = "parity-scale-codec", version = "3.6.1", default-features = false, features = [ +codec = { package = "parity-scale-codec", version = "3.6.12", default-features = false, features = [ "derive", ] } log = { workspace = true } diff --git a/substrate/frame/child-bounties/src/benchmarking.rs b/substrate/frame/child-bounties/src/benchmarking.rs index 1973564d0dc1dacca9d30421cda2b4b03771cef9..947cfcfaa96a2daeb88c68c9cda501c42554fbe3 100644 --- a/substrate/frame/child-bounties/src/benchmarking.rs +++ b/substrate/frame/child-bounties/src/benchmarking.rs @@ -109,7 +109,7 @@ fn activate_bounty( child_bounty_setup.reason.clone(), )?; - child_bounty_setup.bounty_id = Bounties::::bounty_count() - 1; + child_bounty_setup.bounty_id = pallet_bounties::BountyCount::::get() - 1; let approve_origin = T::SpendOrigin::try_successful_origin().map_err(|_| BenchmarkError::Weightless)?; diff --git a/substrate/frame/child-bounties/src/lib.rs b/substrate/frame/child-bounties/src/lib.rs index 1eedeaa5a1ae3c5aa6b3804117921eab63768d1e..04a1f9799cb86e8831a849620b8288fc0692a9c8 100644 --- a/substrate/frame/child-bounties/src/lib.rs +++ b/substrate/frame/child-bounties/src/lib.rs @@ -181,19 +181,16 @@ pub mod pallet { /// Number of total child bounties. #[pallet::storage] - #[pallet::getter(fn child_bounty_count)] pub type ChildBountyCount = StorageValue<_, BountyIndex, ValueQuery>; /// Number of child bounties per parent bounty. /// Map of parent bounty index to number of child bounties. #[pallet::storage] - #[pallet::getter(fn parent_child_bounties)] pub type ParentChildBounties = StorageMap<_, Twox64Concat, BountyIndex, u32, ValueQuery>; /// Child bounties that have been added. #[pallet::storage] - #[pallet::getter(fn child_bounties)] pub type ChildBounties = StorageDoubleMap< _, Twox64Concat, @@ -205,13 +202,11 @@ pub mod pallet { /// The description of each child-bounty. #[pallet::storage] - #[pallet::getter(fn child_bounty_descriptions)] pub type ChildBountyDescriptions = StorageMap<_, Twox64Concat, BountyIndex, BoundedVec>; /// The cumulative child-bounty curator fee for each parent bounty. #[pallet::storage] - #[pallet::getter(fn children_curator_fees)] pub type ChildrenCuratorFees = StorageMap<_, Twox64Concat, BountyIndex, BalanceOf, ValueQuery>; @@ -251,7 +246,7 @@ pub mod pallet { description.try_into().map_err(|_| BountiesError::::ReasonTooBig)?; ensure!(value >= T::ChildBountyValueMinimum::get(), BountiesError::::InvalidValue); ensure!( - Self::parent_child_bounties(parent_bounty_id) <= + ParentChildBounties::::get(parent_bounty_id) <= T::MaxActiveChildBountyCount::get() as u32, Error::::TooManyChildBounties, ); @@ -276,15 +271,15 @@ pub mod pallet { )?; // Get child-bounty ID. - let child_bounty_id = Self::child_bounty_count(); + let child_bounty_id = ChildBountyCount::::get(); let child_bounty_account = Self::child_bounty_account_id(child_bounty_id); // Transfer funds from parent bounty to child-bounty. T::Currency::transfer(&parent_bounty_account, &child_bounty_account, value, KeepAlive)?; // Increment the active child-bounty count. - >::mutate(parent_bounty_id, |count| count.saturating_inc()); - >::put(child_bounty_id.saturating_add(1)); + ParentChildBounties::::mutate(parent_bounty_id, |count| count.saturating_inc()); + ChildBountyCount::::put(child_bounty_id.saturating_add(1)); // Create child-bounty instance. Self::create_child_bounty( @@ -710,12 +705,12 @@ pub mod pallet { }); // Update the active child-bounty tracking count. - >::mutate(parent_bounty_id, |count| { + ParentChildBounties::::mutate(parent_bounty_id, |count| { count.saturating_dec() }); // Remove the child-bounty description. - >::remove(child_bounty_id); + ChildBountyDescriptions::::remove(child_bounty_id); // Remove the child-bounty instance from the state. *maybe_child_bounty = None; @@ -817,7 +812,7 @@ impl Pallet { fn ensure_bounty_active( bounty_id: BountyIndex, ) -> Result<(T::AccountId, BlockNumberFor), DispatchError> { - let parent_bounty = pallet_bounties::Pallet::::bounties(bounty_id) + let parent_bounty = pallet_bounties::Bounties::::get(bounty_id) .ok_or(BountiesError::::InvalidIndex)?; if let BountyStatus::Active { curator, update_due } = parent_bounty.get_status() { Ok((curator, update_due)) @@ -862,7 +857,7 @@ impl Pallet { ChildrenCuratorFees::::mutate(parent_bounty_id, |value| { *value = value.saturating_sub(child_bounty.fee) }); - >::mutate(parent_bounty_id, |count| { + ParentChildBounties::::mutate(parent_bounty_id, |count| { *count = count.saturating_sub(1) }); @@ -880,7 +875,7 @@ impl Pallet { debug_assert!(transfer_result.is_ok()); // Remove the child-bounty description. - >::remove(child_bounty_id); + ChildBountyDescriptions::::remove(child_bounty_id); *maybe_child_bounty = None; @@ -901,14 +896,14 @@ impl pallet_bounties::ChildBountyManager> for Pallet fn child_bounties_count( bounty_id: pallet_bounties::BountyIndex, ) -> pallet_bounties::BountyIndex { - Self::parent_child_bounties(bounty_id) + ParentChildBounties::::get(bounty_id) } fn children_curator_fees(bounty_id: pallet_bounties::BountyIndex) -> BalanceOf { // This is asked for when the parent bounty is being claimed. No use of // keeping it in state after that. Hence removing. - let children_fee_total = Self::children_curator_fees(bounty_id); - >::remove(bounty_id); + let children_fee_total = ChildrenCuratorFees::::get(bounty_id); + ChildrenCuratorFees::::remove(bounty_id); children_fee_total } } diff --git a/substrate/frame/child-bounties/src/tests.rs b/substrate/frame/child-bounties/src/tests.rs index 30601f821e4384827059ffc694ab0108a347bf8b..d9405d3d28977c2cac3b42a034eb5fcfe8e56e8f 100644 --- a/substrate/frame/child-bounties/src/tests.rs +++ b/substrate/frame/child-bounties/src/tests.rs @@ -264,7 +264,7 @@ fn add_child_bounty() { // DB check. // Check the child-bounty status. assert_eq!( - ChildBounties::child_bounties(0, 0).unwrap(), + pallet_child_bounties::ChildBounties::::get(0, 0).unwrap(), ChildBounty { parent_bounty: 0, value: 10, @@ -275,10 +275,13 @@ fn add_child_bounty() { ); // Check the child-bounty count. - assert_eq!(ChildBounties::parent_child_bounties(0), 1); + assert_eq!(pallet_child_bounties::ParentChildBounties::::get(0), 1); // Check the child-bounty description status. - assert_eq!(ChildBounties::child_bounty_descriptions(0).unwrap(), b"12345-p1".to_vec(),); + assert_eq!( + pallet_child_bounties::ChildBountyDescriptions::::get(0).unwrap(), + b"12345-p1".to_vec(), + ); }); } @@ -340,7 +343,7 @@ fn child_bounty_assign_curator() { assert_ok!(ChildBounties::propose_curator(RuntimeOrigin::signed(4), 0, 0, 8, fee)); assert_eq!( - ChildBounties::child_bounties(0, 0).unwrap(), + pallet_child_bounties::ChildBounties::::get(0, 0).unwrap(), ChildBounty { parent_bounty: 0, value: 10, @@ -364,7 +367,7 @@ fn child_bounty_assign_curator() { let expected_child_deposit = CuratorDepositMultiplier::get() * fee; assert_eq!( - ChildBounties::child_bounties(0, 0).unwrap(), + pallet_child_bounties::ChildBounties::::get(0, 0).unwrap(), ChildBounty { parent_bounty: 0, value: 10, @@ -441,7 +444,7 @@ fn award_claim_child_bounty() { let expected_deposit = CuratorDepositMultiplier::get() * fee; assert_eq!( - ChildBounties::child_bounties(0, 0).unwrap(), + pallet_child_bounties::ChildBounties::::get(0, 0).unwrap(), ChildBounty { parent_bounty: 0, value: 10, @@ -479,7 +482,7 @@ fn award_claim_child_bounty() { assert_eq!(Balances::reserved_balance(ChildBounties::child_bounty_account_id(0)), 0); // Check the child-bounty count. - assert_eq!(ChildBounties::parent_child_bounties(0), 0); + assert_eq!(pallet_child_bounties::ParentChildBounties::::get(0), 0); }); } @@ -528,7 +531,7 @@ fn close_child_bounty_added() { assert_ok!(ChildBounties::close_child_bounty(RuntimeOrigin::signed(4), 0, 0)); // Check the child-bounty count. - assert_eq!(ChildBounties::parent_child_bounties(0), 0); + assert_eq!(pallet_child_bounties::ParentChildBounties::::get(0), 0); // Parent-bounty account status. assert_eq!(Balances::free_balance(Bounties::bounty_account_id(0)), 50); @@ -582,7 +585,7 @@ fn close_child_bounty_active() { assert_ok!(ChildBounties::close_child_bounty(RuntimeOrigin::signed(4), 0, 0)); // Check the child-bounty count. - assert_eq!(ChildBounties::parent_child_bounties(0), 0); + assert_eq!(pallet_child_bounties::ParentChildBounties::::get(0), 0); // Ensure child-bounty curator balance is unreserved. assert_eq!(Balances::free_balance(8), 101); @@ -647,7 +650,7 @@ fn close_child_bounty_pending() { ); // Check the child-bounty count. - assert_eq!(ChildBounties::parent_child_bounties(0), 1); + assert_eq!(pallet_child_bounties::ParentChildBounties::::get(0), 1); // Ensure no changes in child-bounty curator balance. assert_eq!(Balances::reserved_balance(8), expected_child_deposit); @@ -739,7 +742,7 @@ fn child_bounty_curator_proposed_unassign_curator() { assert_ok!(ChildBounties::propose_curator(RuntimeOrigin::signed(4), 0, 0, 8, 2)); assert_eq!( - ChildBounties::child_bounties(0, 0).unwrap(), + pallet_child_bounties::ChildBounties::::get(0, 0).unwrap(), ChildBounty { parent_bounty: 0, value: 10, @@ -757,7 +760,7 @@ fn child_bounty_curator_proposed_unassign_curator() { // Verify updated child-bounty status. assert_eq!( - ChildBounties::child_bounties(0, 0).unwrap(), + pallet_child_bounties::ChildBounties::::get(0, 0).unwrap(), ChildBounty { parent_bounty: 0, value: 10, @@ -820,7 +823,7 @@ fn child_bounty_active_unassign_curator() { let expected_child_deposit = CuratorDepositMultiplier::get() * fee; assert_eq!( - ChildBounties::child_bounties(0, 0).unwrap(), + pallet_child_bounties::ChildBounties::::get(0, 0).unwrap(), ChildBounty { parent_bounty: 0, value: 10, @@ -838,7 +841,7 @@ fn child_bounty_active_unassign_curator() { // Verify updated child-bounty status. assert_eq!( - ChildBounties::child_bounties(0, 0).unwrap(), + pallet_child_bounties::ChildBounties::::get(0, 0).unwrap(), ChildBounty { parent_bounty: 0, value: 10, @@ -859,7 +862,7 @@ fn child_bounty_active_unassign_curator() { let expected_child_deposit = CuratorDepositMin::get(); assert_eq!( - ChildBounties::child_bounties(0, 0).unwrap(), + pallet_child_bounties::ChildBounties::::get(0, 0).unwrap(), ChildBounty { parent_bounty: 0, value: 10, @@ -877,7 +880,7 @@ fn child_bounty_active_unassign_curator() { // Verify updated child-bounty status. assert_eq!( - ChildBounties::child_bounties(0, 0).unwrap(), + pallet_child_bounties::ChildBounties::::get(0, 0).unwrap(), ChildBounty { parent_bounty: 0, value: 10, @@ -896,7 +899,7 @@ fn child_bounty_active_unassign_curator() { assert_ok!(ChildBounties::accept_curator(RuntimeOrigin::signed(6), 0, 0)); assert_eq!( - ChildBounties::child_bounties(0, 0).unwrap(), + pallet_child_bounties::ChildBounties::::get(0, 0).unwrap(), ChildBounty { parent_bounty: 0, value: 10, @@ -914,7 +917,7 @@ fn child_bounty_active_unassign_curator() { // Verify updated child-bounty status. assert_eq!( - ChildBounties::child_bounties(0, 0).unwrap(), + pallet_child_bounties::ChildBounties::::get(0, 0).unwrap(), ChildBounty { parent_bounty: 0, value: 10, @@ -935,7 +938,7 @@ fn child_bounty_active_unassign_curator() { let expected_child_deposit = CuratorDepositMin::get(); assert_eq!( - ChildBounties::child_bounties(0, 0).unwrap(), + pallet_child_bounties::ChildBounties::::get(0, 0).unwrap(), ChildBounty { parent_bounty: 0, value: 10, @@ -963,7 +966,7 @@ fn child_bounty_active_unassign_curator() { // Verify updated child-bounty status. assert_eq!( - ChildBounties::child_bounties(0, 0).unwrap(), + pallet_child_bounties::ChildBounties::::get(0, 0).unwrap(), ChildBounty { parent_bounty: 0, value: 10, @@ -1025,7 +1028,7 @@ fn parent_bounty_inactive_unassign_curator_child_bounty() { let expected_child_deposit = CuratorDepositMultiplier::get() * fee; assert_eq!( - ChildBounties::child_bounties(0, 0).unwrap(), + pallet_child_bounties::ChildBounties::::get(0, 0).unwrap(), ChildBounty { parent_bounty: 0, value: 10, @@ -1056,7 +1059,7 @@ fn parent_bounty_inactive_unassign_curator_child_bounty() { // Verify updated child-bounty status. assert_eq!( - ChildBounties::child_bounties(0, 0).unwrap(), + pallet_child_bounties::ChildBounties::::get(0, 0).unwrap(), ChildBounty { parent_bounty: 0, value: 10, @@ -1087,7 +1090,7 @@ fn parent_bounty_inactive_unassign_curator_child_bounty() { let expected_deposit = CuratorDepositMin::get(); assert_eq!( - ChildBounties::child_bounties(0, 0).unwrap(), + pallet_child_bounties::ChildBounties::::get(0, 0).unwrap(), ChildBounty { parent_bounty: 0, value: 10, @@ -1116,7 +1119,7 @@ fn parent_bounty_inactive_unassign_curator_child_bounty() { // Verify updated child-bounty status. assert_eq!( - ChildBounties::child_bounties(0, 0).unwrap(), + pallet_child_bounties::ChildBounties::::get(0, 0).unwrap(), ChildBounty { parent_bounty: 0, value: 10, @@ -1186,7 +1189,7 @@ fn close_parent_with_child_bounty() { assert_ok!(ChildBounties::close_child_bounty(RuntimeOrigin::root(), 0, 0)); // Check the child-bounty count. - assert_eq!(ChildBounties::parent_child_bounties(0), 0); + assert_eq!(pallet_child_bounties::ParentChildBounties::::get(0), 0); // Try close parent-bounty again. // Should pass this time. @@ -1235,7 +1238,7 @@ fn children_curator_fee_calculation_test() { // Propose curator for child-bounty. assert_ok!(ChildBounties::propose_curator(RuntimeOrigin::signed(4), 0, 0, 8, fee)); // Check curator fee added to the sum. - assert_eq!(ChildBounties::children_curator_fees(0), fee); + assert_eq!(pallet_child_bounties::ChildrenCuratorFees::::get(0), fee); // Accept curator for child-bounty. assert_ok!(ChildBounties::accept_curator(RuntimeOrigin::signed(8), 0, 0)); // Award child-bounty. @@ -1244,7 +1247,7 @@ fn children_curator_fee_calculation_test() { let expected_child_deposit = CuratorDepositMultiplier::get() * fee; assert_eq!( - ChildBounties::child_bounties(0, 0).unwrap(), + pallet_child_bounties::ChildBounties::::get(0, 0).unwrap(), ChildBounty { parent_bounty: 0, value: 10, @@ -1264,7 +1267,7 @@ fn children_curator_fee_calculation_test() { assert_ok!(ChildBounties::claim_child_bounty(RuntimeOrigin::signed(7), 0, 0)); // Check the child-bounty count. - assert_eq!(ChildBounties::parent_child_bounties(0), 0); + assert_eq!(pallet_child_bounties::ParentChildBounties::::get(0), 0); // Award the parent bounty. assert_ok!(Bounties::award_bounty(RuntimeOrigin::signed(4), 0, 9)); diff --git a/substrate/frame/collective/Cargo.toml b/substrate/frame/collective/Cargo.toml index 850390409abc9646afbdb058dd2392d9f35869aa..d966370238bc4f2c8597555187a1830280752732 100644 --- a/substrate/frame/collective/Cargo.toml +++ b/substrate/frame/collective/Cargo.toml @@ -16,7 +16,7 @@ workspace = true targets = ["x86_64-unknown-linux-gnu"] [dependencies] -codec = { package = "parity-scale-codec", version = "3.6.1", default-features = false, features = ["derive"] } +codec = { package = "parity-scale-codec", version = "3.6.12", default-features = false, features = ["derive"] } log = { workspace = true } scale-info = { version = "2.11.1", default-features = false, features = ["derive"] } frame-benchmarking = { path = "../benchmarking", default-features = false, optional = true } diff --git a/substrate/frame/contracts/Cargo.toml b/substrate/frame/contracts/Cargo.toml index d963ac261d1940fc9fa4d88101df2ca35cf99c43..bd4ded1a1170c9356730eaef9ffbc28e0b6a356a 100644 --- a/substrate/frame/contracts/Cargo.toml +++ b/substrate/frame/contracts/Cargo.toml @@ -20,7 +20,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] paste = { version = "1.0", default-features = false } bitflags = "1.3" -codec = { package = "parity-scale-codec", version = "3.6.1", default-features = false, features = [ +codec = { package = "parity-scale-codec", version = "3.6.12", default-features = false, features = [ "derive", "max-encoded-len", ] } @@ -56,7 +56,7 @@ xcm = { package = "staging-xcm", path = "../../../polkadot/xcm", default-feature xcm-builder = { package = "staging-xcm-builder", path = "../../../polkadot/xcm/xcm-builder", default-features = false } [dev-dependencies] -array-bytes = "6.1" +array-bytes = "6.2.2" assert_matches = "1" env_logger = "0.11" pretty_assertions = "1" diff --git a/substrate/frame/contracts/fixtures/build.rs b/substrate/frame/contracts/fixtures/build.rs index 19aff37c1601430011966768d54a475ef0bbc1d2..baaeaf0342032f43821f19c5526d3a8850e3a035 100644 --- a/substrate/frame/contracts/fixtures/build.rs +++ b/substrate/frame/contracts/fixtures/build.rs @@ -163,7 +163,7 @@ fn invoke_cargo_fmt<'a>( ) -> Result<()> { // If rustfmt is not installed, skip the check. if !Command::new("rustup") - .args(["nightly-2024-01-22", "run", "rustfmt", "--version"]) + .args(["nightly-2024-04-10", "run", "rustfmt", "--version"]) .output() .map_or(false, |o| o.status.success()) { @@ -171,7 +171,7 @@ fn invoke_cargo_fmt<'a>( } let fmt_res = Command::new("rustup") - .args(["nightly-2024-01-22", "run", "rustfmt", "--check", "--config-path"]) + .args(["nightly-2024-04-10", "run", "rustfmt", "--check", "--config-path"]) .arg(config_path) .args(files) .output() @@ -186,7 +186,7 @@ fn invoke_cargo_fmt<'a>( eprintln!("{}\n{}", stdout, stderr); eprintln!( "Fixtures files are not formatted.\n - Please run `rustup nightly-2024-01-22 run rustfmt --config-path {} {}/*.rs`", + Please run `rustup nightly-2024-04-10 run rustfmt --config-path {} {}/*.rs`", config_path.display(), contract_dir.display() ); diff --git a/substrate/frame/contracts/mock-network/Cargo.toml b/substrate/frame/contracts/mock-network/Cargo.toml index 387c3ca39d049f7674541e24a36b300683326260..a348b7308d1232109a4763dcc764fdac87deee6d 100644 --- a/substrate/frame/contracts/mock-network/Cargo.toml +++ b/substrate/frame/contracts/mock-network/Cargo.toml @@ -12,7 +12,7 @@ description = "A mock network for testing pallet-contracts" workspace = true [dependencies] -codec = { package = "parity-scale-codec", version = "3.6.1", default-features = false, features = ["derive", "max-encoded-len"] } +codec = { package = "parity-scale-codec", version = "3.6.12", default-features = false, features = ["derive", "max-encoded-len"] } frame-support = { path = "../../support", default-features = false } frame-system = { path = "../../system", default-features = false } diff --git a/substrate/frame/contracts/mock-network/src/lib.rs b/substrate/frame/contracts/mock-network/src/lib.rs index 8a17a3f2fa781703f1393f2d69ca955384a080a2..20ded0f4a0b8475d2cd203ca4acd8164dd9792eb 100644 --- a/substrate/frame/contracts/mock-network/src/lib.rs +++ b/substrate/frame/contracts/mock-network/src/lib.rs @@ -23,6 +23,7 @@ pub mod relay_chain; mod tests; use crate::primitives::{AccountId, UNITS}; +pub use pallet_contracts::test_utils::{ALICE, BOB}; use sp_runtime::BuildStorage; use xcm::latest::prelude::*; use xcm_executor::traits::ConvertLocation; @@ -31,8 +32,6 @@ use xcm_simulator::{decl_test_network, decl_test_parachain, decl_test_relay_chai // Accounts pub const ADMIN: sp_runtime::AccountId32 = sp_runtime::AccountId32::new([0u8; 32]); -pub const ALICE: sp_runtime::AccountId32 = sp_runtime::AccountId32::new([1u8; 32]); -pub const BOB: sp_runtime::AccountId32 = sp_runtime::AccountId32::new([2u8; 32]); // Balances pub const INITIAL_BALANCE: u128 = 1_000_000_000 * UNITS; diff --git a/substrate/frame/contracts/mock-network/src/mocks/msg_queue.rs b/substrate/frame/contracts/mock-network/src/mocks/msg_queue.rs index cc81b6bd636e54187e3ba09500fc39b472ed1943..bfdf6dd97eaf17fc0601f78c7c179e411c3a143d 100644 --- a/substrate/frame/contracts/mock-network/src/mocks/msg_queue.rs +++ b/substrate/frame/contracts/mock-network/src/mocks/msg_queue.rs @@ -47,17 +47,15 @@ pub mod pallet { pub struct Pallet(_); #[pallet::storage] - #[pallet::getter(fn parachain_id)] pub(super) type ParachainId = StorageValue<_, ParaId, ValueQuery>; #[pallet::storage] - #[pallet::getter(fn received_dmp)] /// A queue of received DMP messages pub(super) type ReceivedDmp = StorageValue<_, Vec>, ValueQuery>; impl Get for Pallet { fn get() -> ParaId { - Self::parachain_id() + ParachainId::::get() } } @@ -89,6 +87,14 @@ pub mod pallet { ParachainId::::put(para_id); } + pub fn parachain_id() -> ParaId { + ParachainId::::get() + } + + pub fn received_dmp() -> Vec> { + ReceivedDmp::::get() + } + fn handle_xcmp_message( sender: ParaId, _sent_at: RelayBlockNumber, @@ -169,7 +175,7 @@ pub mod pallet { limit, Weight::zero(), ); - >::append(x); + ReceivedDmp::::append(x); Self::deposit_event(Event::ExecutedDownward(id, outcome)); }, }, diff --git a/substrate/frame/contracts/mock-network/src/parachain.rs b/substrate/frame/contracts/mock-network/src/parachain.rs index d4ad47581d16740df732459b3faee2d0b02306b4..b46d7df6c2bcf1f99a48540d5f1c5ef104d09206 100644 --- a/substrate/frame/contracts/mock-network/src/parachain.rs +++ b/substrate/frame/contracts/mock-network/src/parachain.rs @@ -144,7 +144,7 @@ parameter_types! { pub const KsmLocation: Location = Location::parent(); pub const TokenLocation: Location = Here.into_location(); pub const RelayNetwork: NetworkId = ByGenesis([0; 32]); - pub UniversalLocation: InteriorLocation = Parachain(MsgQueue::parachain_id().into()).into(); + pub UniversalLocation: InteriorLocation = [GlobalConsensus(RelayNetwork::get()), Parachain(MsgQueue::parachain_id().into())].into(); } pub type XcmOriginToCallOrigin = ( @@ -285,6 +285,7 @@ impl Config for XcmConfig { type HrmpNewChannelOpenRequestHandler = (); type HrmpChannelAcceptedHandler = (); type HrmpChannelClosingHandler = (); + type XcmRecorder = PolkadotXcm; } impl mock_msg_queue::Config for Runtime { diff --git a/substrate/frame/contracts/mock-network/src/relay_chain.rs b/substrate/frame/contracts/mock-network/src/relay_chain.rs index 470304ed357ec5594a2a66f795f838bc8be7740b..36a7de499ba99311889980ba2c02d8502602b945 100644 --- a/substrate/frame/contracts/mock-network/src/relay_chain.rs +++ b/substrate/frame/contracts/mock-network/src/relay_chain.rs @@ -107,7 +107,7 @@ impl configuration::Config for Runtime { parameter_types! { pub RelayNetwork: NetworkId = ByGenesis([0; 32]); pub const TokenLocation: Location = Here.into_location(); - pub UniversalLocation: InteriorLocation = Here; + pub UniversalLocation: InteriorLocation = RelayNetwork::get().into(); pub UnitWeightCost: u64 = 1_000; } @@ -185,6 +185,7 @@ impl Config for XcmConfig { type HrmpNewChannelOpenRequestHandler = (); type HrmpChannelAcceptedHandler = (); type HrmpChannelClosingHandler = (); + type XcmRecorder = XcmPallet; } pub type LocalOriginToLocation = SignedToAccountId32; diff --git a/substrate/frame/contracts/mock-network/src/tests.rs b/substrate/frame/contracts/mock-network/src/tests.rs index 39aa9bebc0f5943627ae40a109dab357ae19dd07..48a94e172a027e9687d515f549d45ce444453f7b 100644 --- a/substrate/frame/contracts/mock-network/src/tests.rs +++ b/substrate/frame/contracts/mock-network/src/tests.rs @@ -22,45 +22,31 @@ use crate::{ relay_chain, MockNet, ParaA, ParachainBalances, Relay, ALICE, BOB, INITIAL_BALANCE, }; use codec::{Decode, Encode}; -use frame_support::{ - pallet_prelude::Weight, - traits::{fungibles::Mutate, Currency}, -}; -use pallet_balances::{BalanceLock, Reasons}; -use pallet_contracts::{Code, CollectEvents, DebugInfo, Determinism}; +use frame_support::traits::{fungibles::Mutate, Currency}; +use pallet_contracts::{test_utils::builder::*, Code}; 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); }}; } +fn bare_call(dest: sp_runtime::AccountId32) -> BareCallBuilder { + BareCallBuilder::::bare_call(ALICE, dest) +} + /// 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(); // Instantiate contract. let contract_addr = ParaA::execute_with(|| { - ParachainContracts::bare_instantiate( - ALICE, - 0, - Weight::MAX, - None, - Code::Upload(wasm), - vec![], - vec![], - DebugInfo::UnsafeDebug, - CollectEvents::Skip, - ) - .result - .unwrap() - .account_id + BareInstantiateBuilder::::bare_instantiate(ALICE, Code::Upload(wasm)) + .build_and_unwrap_account_id() }); // Funds contract account with some balance and assets. @@ -85,27 +71,18 @@ fn test_xcm_execute() { // Execute XCM instructions through the contract. ParaA::execute_with(|| { let amount: u128 = 10 * CENTS; + let assets: Asset = (Here, amount).into(); + let beneficiary = AccountId32 { network: None, id: BOB.clone().into() }; // The XCM used to transfer funds to Bob. - let message: Xcm<()> = Xcm(vec![ - WithdrawAsset(vec![(Here, amount).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().encode(), - DebugInfo::UnsafeDebug, - CollectEvents::UnsafeCollect, - Determinism::Enforced, - ); + let message: Xcm<()> = Xcm::builder_unsafe() + .withdraw_asset(assets.clone()) + .deposit_asset(assets, beneficiary) + .build(); + + let result = bare_call(contract_addr.clone()) + .data(VersionedXcm::V4(message).encode()) + .build(); assert_eq!(result.gas_consumed, result.gas_required); assert_return_code!(&result.result.unwrap(), ReturnErrorCode::Success); @@ -127,29 +104,22 @@ fn test_xcm_execute_incomplete() { // Execute XCM instructions through the contract. ParaA::execute_with(|| { + let assets: Asset = (Here, amount).into(); + let beneficiary = AccountId32 { network: None, id: BOB.clone().into() }; + // The XCM used to transfer funds to Bob. - let message: Xcm<()> = Xcm(vec![ - WithdrawAsset(vec![(Here, amount).into()].into()), + let message: Xcm<()> = Xcm::builder_unsafe() + .withdraw_asset(assets.clone()) // 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().encode(), - DebugInfo::UnsafeDebug, - CollectEvents::UnsafeCollect, - Determinism::Enforced, - ); + .withdraw_asset((Here, INITIAL_BALANCE)) + .buy_execution(assets.clone(), Unlimited) + .deposit_asset(assets, beneficiary) + .build(); + + let result = bare_call(contract_addr.clone()) + .data(VersionedXcm::V4(message).encode()) + .build(); assert_eq!(result.gas_consumed, result.gas_required); assert_return_code!(&result.result.unwrap(), ReturnErrorCode::XcmExecutionFailed); @@ -175,28 +145,16 @@ fn test_xcm_execute_reentrant_call() { }); // The XCM used to transfer funds to Bob. - let message: Xcm = Xcm(vec![ - Transact { - origin_kind: OriginKind::Native, - require_weight_at_most: 1_000_000_000.into(), - call: transact_call.encode().into(), - }, - ExpectTransactStatus(MaybeErrorCode::Success), - ]); - - let result = ParachainContracts::bare_call( - ALICE, - contract_addr.clone(), - 0, - Weight::MAX, - None, - VersionedXcm::V4(message).encode().encode(), - DebugInfo::UnsafeDebug, - CollectEvents::UnsafeCollect, - Determinism::Enforced, - ); + let message: Xcm = Xcm::builder_unsafe() + .transact(OriginKind::Native, 1_000_000_000, transact_call.encode()) + .expect_transact_status(MaybeErrorCode::Success) + .build(); - assert_return_code!(&result.result.unwrap(), ReturnErrorCode::XcmExecutionFailed); + let result = bare_call(contract_addr.clone()) + .data(VersionedXcm::V4(message).encode()) + .build_and_unwrap_result(); + + assert_return_code!(&result, ReturnErrorCode::XcmExecutionFailed); // Funds should not change hands as the XCM transact failed. assert_eq!(ParachainBalances::free_balance(BOB), INITIAL_BALANCE); @@ -207,40 +165,36 @@ fn test_xcm_execute_reentrant_call() { fn test_xcm_send() { MockNet::reset(); let contract_addr = instantiate_test_contract("xcm_send"); + let amount = 1_000 * CENTS; let fee = parachain::estimate_message_fee(4); // Accounts for the `DescendOrigin` instruction added by `send_xcm` - // Send XCM instructions through the contract, to lock some funds on the relay chain. + // Send XCM instructions through the contract, to transfer some funds from the contract + // derivative account to Alice on the relay chain. ParaA::execute_with(|| { - let dest = Location::from(Parent); - let dest = VersionedLocation::V4(dest); - - let message: Xcm<()> = Xcm(vec![ - WithdrawAsset((Here, fee).into()), - BuyExecution { fees: (Here, fee).into(), weight_limit: WeightLimit::Unlimited }, - LockAsset { asset: (Here, 5 * CENTS).into(), unlocker: (Parachain(1)).into() }, - ]); - let message = VersionedXcm::V4(message); - let exec = ParachainContracts::bare_call( - ALICE, - contract_addr.clone(), - 0, - Weight::MAX, - None, - (dest, message.encode()).encode(), - DebugInfo::UnsafeDebug, - CollectEvents::UnsafeCollect, - Determinism::Enforced, - ); + let dest = VersionedLocation::V4(Parent.into()); + let assets: Asset = (Here, amount).into(); + let beneficiary = AccountId32 { network: None, id: ALICE.clone().into() }; + + let message: Xcm<()> = Xcm::builder() + .withdraw_asset(assets.clone()) + .buy_execution((Here, fee), Unlimited) + .deposit_asset(assets, beneficiary) + .build(); + + let result = bare_call(contract_addr.clone()) + .data((dest, VersionedXcm::V4(message)).encode()) + .build_and_unwrap_result(); - let mut data = &exec.result.unwrap().data[..]; + let mut data = &result.data[..]; XcmHash::decode(&mut data).expect("Failed to decode xcm_send message_id"); }); Relay::execute_with(|| { - // Check if the funds are locked on the relay chain. + let derived_contract_addr = ¶chain_account_sovereign_account_id(1, contract_addr); assert_eq!( - relay_chain::Balances::locks(¶chain_account_sovereign_account_id(1, contract_addr)), - vec![BalanceLock { id: *b"py/xcmlk", amount: 5 * CENTS, reasons: Reasons::All }] + INITIAL_BALANCE - amount, + relay_chain::Balances::free_balance(derived_contract_addr) ); + assert_eq!(INITIAL_BALANCE + amount - fee, relay_chain::Balances::free_balance(ALICE)); }); } diff --git a/substrate/frame/contracts/src/benchmarking/mod.rs b/substrate/frame/contracts/src/benchmarking/mod.rs index 676fd320a17299b2eb2471d485afcd2775168175..952ef180be21860b4a13a26fdf07bf03251f00a2 100644 --- a/substrate/frame/contracts/src/benchmarking/mod.rs +++ b/substrate/frame/contracts/src/benchmarking/mod.rs @@ -623,10 +623,13 @@ mod benchmarks { #[benchmark(pov_mode = Measured)] fn seal_caller(r: Linear<0, API_BENCHMARK_RUNS>) { call_builder!(func, WasmModule::getter("seal0", "seal_caller", r)); + + let res; #[block] { - func.call(); + res = func.call(); } + assert_eq!(res.did_revert(), false); } #[benchmark(pov_mode = Measured)] @@ -659,10 +662,13 @@ mod benchmarks { for acc in accounts.iter() { >::insert(acc, info.clone()); } + + let res; #[block] { - func.call(); + res = func.call(); } + assert_eq!(res.did_revert(), false); } #[benchmark(pov_mode = Measured)] @@ -703,19 +709,25 @@ mod benchmarks { for acc in accounts.iter() { >::insert(acc, info.clone()); } + + let res; #[block] { - func.call(); + res = func.call(); } + assert_eq!(res.did_revert(), false); } #[benchmark(pov_mode = Measured)] fn seal_own_code_hash(r: Linear<0, API_BENCHMARK_RUNS>) { call_builder!(func, WasmModule::getter("seal0", "seal_own_code_hash", r)); + + let res; #[block] { - func.call(); + res = func.call(); } + assert_eq!(res.did_revert(), false); } #[benchmark(pov_mode = Measured)] @@ -732,10 +744,13 @@ mod benchmarks { ..Default::default() }); call_builder!(func, code); + + let res; #[block] { - func.call(); + res = func.call(); } + assert_eq!(res.did_revert(), false); } #[benchmark(pov_mode = Measured)] @@ -754,73 +769,97 @@ mod benchmarks { let mut setup = CallSetup::::new(code); setup.set_origin(Origin::Root); call_builder!(func, setup: setup); + + let res; #[block] { - func.call(); + res = func.call(); } + assert_eq!(res.did_revert(), false); } #[benchmark(pov_mode = Measured)] fn seal_address(r: Linear<0, API_BENCHMARK_RUNS>) { call_builder!(func, WasmModule::getter("seal0", "seal_address", r)); + + let res; #[block] { - func.call(); + res = func.call(); } + assert_eq!(res.did_revert(), false); } #[benchmark(pov_mode = Measured)] fn seal_gas_left(r: Linear<0, API_BENCHMARK_RUNS>) { call_builder!(func, WasmModule::getter("seal1", "gas_left", r)); + + let res; #[block] { - func.call(); + res = func.call(); } + assert_eq!(res.did_revert(), false); } #[benchmark(pov_mode = Measured)] fn seal_balance(r: Linear<0, API_BENCHMARK_RUNS>) { call_builder!(func, WasmModule::getter("seal0", "seal_balance", r)); + + let res; #[block] { - func.call(); + res = func.call(); } + assert_eq!(res.did_revert(), false); } #[benchmark(pov_mode = Measured)] fn seal_value_transferred(r: Linear<0, API_BENCHMARK_RUNS>) { call_builder!(func, WasmModule::getter("seal0", "seal_value_transferred", r)); + + let res; #[block] { - func.call(); + res = func.call(); } + assert_eq!(res.did_revert(), false); } #[benchmark(pov_mode = Measured)] fn seal_minimum_balance(r: Linear<0, API_BENCHMARK_RUNS>) { call_builder!(func, WasmModule::getter("seal0", "seal_minimum_balance", r)); + + let res; #[block] { - func.call(); + res = func.call(); } + assert_eq!(res.did_revert(), false); } #[benchmark(pov_mode = Measured)] fn seal_block_number(r: Linear<0, API_BENCHMARK_RUNS>) { call_builder!(func, WasmModule::getter("seal0", "seal_block_number", r)); + + let res; #[block] { - func.call(); + res = func.call(); } + assert_eq!(res.did_revert(), false); } #[benchmark(pov_mode = Measured)] fn seal_now(r: Linear<0, API_BENCHMARK_RUNS>) { call_builder!(func, WasmModule::getter("seal0", "seal_now", r)); + + let res; #[block] { - func.call(); + res = func.call(); } + assert_eq!(res.did_revert(), false); } #[benchmark(pov_mode = Measured)] @@ -851,10 +890,13 @@ mod benchmarks { ..Default::default() }); call_builder!(func, code); + + let res; #[block] { - func.call(); + res = func.call(); } + assert_eq!(res.did_revert(), false); } #[benchmark(pov_mode = Measured)] @@ -880,10 +922,13 @@ mod benchmarks { }); call_builder!(func, code); + + let res; #[block] { - func.call(); + res = func.call(); } + assert_eq!(res.did_revert(), false); } #[benchmark(pov_mode = Measured)] @@ -944,10 +989,13 @@ mod benchmarks { ..Default::default() }); call_builder!(func, code); + + let res; #[block] { - func.call(); + res = func.call(); } + assert_eq!(res.did_revert(), false); } #[benchmark(pov_mode = Measured)] @@ -970,10 +1018,13 @@ mod benchmarks { ..Default::default() }); call_builder!(func, code); + + let res; #[block] { - func.call(); + res = func.call(); } + assert_eq!(res.did_revert(), false); } // The same argument as for `seal_return` is true here. @@ -1108,10 +1159,13 @@ mod benchmarks { }); call_builder!(func, code); + + let res; #[block] { - func.call(); + res = func.call(); } + assert_eq!(res.did_revert(), false); } // Overhead of calling the function without any topic. @@ -1140,10 +1194,13 @@ mod benchmarks { }); call_builder!(func, code); + + let res; #[block] { - func.call(); + res = func.call(); } + assert_eq!(res.did_revert(), false); } // Benchmark the overhead that topics generate. @@ -1177,10 +1234,13 @@ mod benchmarks { }); call_builder!(func, code); + + let res; #[block] { - func.call(); + res = func.call(); } + assert_eq!(res.did_revert(), false); } // Benchmark debug_message call with zero input data. @@ -1210,10 +1270,13 @@ mod benchmarks { let mut setup = CallSetup::::new(code); setup.enable_debug_message(); call_builder!(func, setup: setup); + + let res; #[block] { - func.call(); + res = func.call(); } + assert_eq!(res.did_revert(), false); Ok(()) } @@ -1260,10 +1323,13 @@ mod benchmarks { let mut setup = CallSetup::::new(code); setup.enable_debug_message(); call_builder!(func, setup: setup); + + let res; #[block] { - func.call(); + res = func.call(); } + assert_eq!(res.did_revert(), false); assert_eq!(setup.debug_message().unwrap().len() as u32, i); Ok(()) } @@ -1324,10 +1390,13 @@ mod benchmarks { ) .map_err(|_| "Failed to write to storage during setup.")?; } + + let res; #[block] { - func.call(); + res = func.call(); } + assert_eq!(res.did_revert(), false); Ok(()) } @@ -1366,10 +1435,13 @@ mod benchmarks { false, ) .map_err(|_| "Failed to write to storage during setup.")?; + + let res; #[block] { - func.call(); + res = func.call(); } + assert_eq!(res.did_revert(), false); Ok(()) } @@ -1409,10 +1481,13 @@ mod benchmarks { false, ) .map_err(|_| "Failed to write to storage during setup.")?; + + let res; #[block] { - func.call(); + res = func.call(); } + assert_eq!(res.did_revert(), false); Ok(()) } @@ -1463,10 +1538,13 @@ mod benchmarks { .map_err(|_| "Failed to write to storage during setup.")?; } >::insert(&instance.account_id, info); + + let res; #[block] { - func.call(); + res = func.call(); } + assert_eq!(res.did_revert(), false); Ok(()) } @@ -1504,10 +1582,12 @@ mod benchmarks { ) .map_err(|_| "Failed to write to storage during setup.")?; + let res; #[block] { - func.call(); + res = func.call(); } + assert_eq!(res.did_revert(), false); Ok(()) } @@ -1564,10 +1644,13 @@ mod benchmarks { .map_err(|_| "Failed to write to storage during setup.")?; } >::insert(&instance.account_id, info); + + let res; #[block] { - func.call(); + res = func.call(); } + assert_eq!(res.did_revert(), false); Ok(()) } @@ -1613,10 +1696,13 @@ mod benchmarks { ) .map_err(|_| "Failed to write to storage during setup.")?; >::insert(&instance.account_id, info); + + let res; #[block] { - func.call(); + res = func.call(); } + assert_eq!(res.did_revert(), false); Ok(()) } @@ -1667,10 +1753,13 @@ mod benchmarks { .map_err(|_| "Failed to write to storage during setup.")?; } >::insert(&instance.account_id, info); + + let res; #[block] { - func.call(); + res = func.call(); } + assert_eq!(res.did_revert(), false); Ok(()) } @@ -1708,10 +1797,13 @@ mod benchmarks { ) .map_err(|_| "Failed to write to storage during setup.")?; >::insert(&instance.account_id, info); + + let res; #[block] { - func.call(); + res = func.call(); } + assert_eq!(res.did_revert(), false); Ok(()) } @@ -1767,10 +1859,13 @@ mod benchmarks { .map_err(|_| "Failed to write to storage during setup.")?; } >::insert(&instance.account_id, info); + + let res; #[block] { - func.call(); + res = func.call(); } + assert_eq!(res.did_revert(), false); Ok(()) } @@ -1816,10 +1911,13 @@ mod benchmarks { ) .map_err(|_| "Failed to write to storage during setup.")?; >::insert(&instance.account_id, info); + + let res; #[block] { - func.call(); + res = func.call(); } + assert_eq!(res.did_revert(), false); Ok(()) } @@ -1867,10 +1965,12 @@ mod benchmarks { assert_eq!(T::Currency::total_balance(account), 0u32.into()); } + let res; #[block] { - func.call(); + res = func.call(); } + assert_eq!(res.did_revert(), false); for account in &accounts { assert_eq!(T::Currency::total_balance(account), value); @@ -1947,10 +2047,13 @@ mod benchmarks { let mut setup = CallSetup::::new(code); setup.set_storage_deposit_limit(BalanceOf::::from(u32::MAX.into())); call_builder!(func, setup: setup); + + let res; #[block] { - func.call(); + res = func.call(); } + assert_eq!(res.did_revert(), false); Ok(()) } @@ -2002,10 +2105,13 @@ mod benchmarks { ..Default::default() }); call_builder!(func, code); + + let res; #[block] { - func.call(); + res = func.call(); } + assert_eq!(res.did_revert(), false); Ok(()) } @@ -2057,10 +2163,13 @@ mod benchmarks { let mut setup = CallSetup::::new(code); setup.set_data(vec![42; c as usize]); call_builder!(func, setup: setup); + + let res; #[block] { - func.call(); + res = func.call(); } + assert_eq!(res.did_revert(), false); Ok(()) } @@ -2165,10 +2274,13 @@ mod benchmarks { return Err("Expected that contract does not exist at this point.".into()); } } + + let res; #[block] { - func.call(); + res = func.call(); } + assert_eq!(res.did_revert(), false); for addr in &addresses { ContractInfoOf::::get(&addr).ok_or("Contract should have been instantiated")?; } @@ -2240,10 +2352,13 @@ mod benchmarks { let mut setup = CallSetup::::new(code); setup.set_balance(value + (Pallet::::min_balance() * 2u32.into())); call_builder!(func, setup: setup); + + let res; #[block] { - func.call(); + res = func.call(); } + assert_eq!(res.did_revert(), false); Ok(()) } @@ -2251,80 +2366,104 @@ mod benchmarks { #[benchmark(pov_mode = Measured)] fn seal_hash_sha2_256(r: Linear<0, API_BENCHMARK_RUNS>) { call_builder!(func, WasmModule::hasher("seal_hash_sha2_256", r, 0)); + + let res; #[block] { - func.call(); + res = func.call(); } + assert_eq!(res.did_revert(), false); } // `n`: Input to hash in bytes #[benchmark(pov_mode = Measured)] fn seal_hash_sha2_256_per_byte(n: Linear<0, { code::max_pages::() * 64 * 1024 }>) { call_builder!(func, WasmModule::hasher("seal_hash_sha2_256", 1, n)); + + let res; #[block] { - func.call(); + res = func.call(); } + assert_eq!(res.did_revert(), false); } // Only the overhead of calling the function itself with minimal arguments. #[benchmark(pov_mode = Measured)] fn seal_hash_keccak_256(r: Linear<0, API_BENCHMARK_RUNS>) { call_builder!(func, WasmModule::hasher("seal_hash_keccak_256", r, 0)); + + let res; #[block] { - func.call(); + res = func.call(); } + assert_eq!(res.did_revert(), false); } // `n`: Input to hash in bytes #[benchmark(pov_mode = Measured)] fn seal_hash_keccak_256_per_byte(n: Linear<0, { code::max_pages::() * 64 * 1024 }>) { call_builder!(func, WasmModule::hasher("seal_hash_keccak_256", 1, n)); + + let res; #[block] { - func.call(); + res = func.call(); } + assert_eq!(res.did_revert(), false); } // Only the overhead of calling the function itself with minimal arguments. #[benchmark(pov_mode = Measured)] fn seal_hash_blake2_256(r: Linear<0, API_BENCHMARK_RUNS>) { call_builder!(func, WasmModule::hasher("seal_hash_blake2_256", r, 0)); + + let res; #[block] { - func.call(); + res = func.call(); } + assert_eq!(res.did_revert(), false); } // `n`: Input to hash in bytes #[benchmark(pov_mode = Measured)] fn seal_hash_blake2_256_per_byte(n: Linear<0, { code::max_pages::() * 64 * 1024 }>) { call_builder!(func, WasmModule::hasher("seal_hash_blake2_256", 1, n)); + + let res; #[block] { - func.call(); + res = func.call(); } + assert_eq!(res.did_revert(), false); } // Only the overhead of calling the function itself with minimal arguments. #[benchmark(pov_mode = Measured)] fn seal_hash_blake2_128(r: Linear<0, API_BENCHMARK_RUNS>) { call_builder!(func, WasmModule::hasher("seal_hash_blake2_128", r, 0)); + + let res; #[block] { - func.call(); + res = func.call(); } + assert_eq!(res.did_revert(), false); } // `n`: Input to hash in bytes #[benchmark(pov_mode = Measured)] fn seal_hash_blake2_128_per_byte(n: Linear<0, { code::max_pages::() * 64 * 1024 }>) { call_builder!(func, WasmModule::hasher("seal_hash_blake2_128", 1, n)); + + let res; #[block] { - func.call(); + res = func.call(); } + assert_eq!(res.did_revert(), false); } // `n`: Message input length to verify in bytes. @@ -2368,10 +2507,13 @@ mod benchmarks { }); call_builder!(func, code); + + let res; #[block] { - func.call(); + res = func.call(); } + assert_eq!(res.did_revert(), false); Ok(()) } @@ -2425,10 +2567,13 @@ mod benchmarks { ..Default::default() }); call_builder!(func, code); + + let res; #[block] { - func.call(); + res = func.call(); } + assert_eq!(res.did_revert(), false); Ok(()) } @@ -2475,10 +2620,13 @@ mod benchmarks { ..Default::default() }); call_builder!(func, code); + + let res; #[block] { - func.call(); + res = func.call(); } + assert_eq!(res.did_revert(), false); Ok(()) } @@ -2515,10 +2663,13 @@ mod benchmarks { ..Default::default() }); call_builder!(func, code); + + let res; #[block] { - func.call(); + res = func.call(); } + assert_eq!(res.did_revert(), false); Ok(()) } @@ -2556,10 +2707,13 @@ mod benchmarks { ..Default::default() }); call_builder!(func, code); + + let res; #[block] { - func.call(); + res = func.call(); } + assert_eq!(res.did_revert(), false); Ok(()) } @@ -2598,10 +2752,13 @@ mod benchmarks { ..Default::default() }); call_builder!(func, code); + + let res; #[block] { - func.call(); + res = func.call(); } + assert_eq!(res.did_revert(), false); Ok(()) } @@ -2656,10 +2813,13 @@ mod benchmarks { ..Default::default() }); call_builder!(func, code); + + let res; #[block] { - func.call(); + res = func.call(); } + assert_eq!(res.did_revert(), false); Ok(()) } @@ -2713,10 +2873,13 @@ mod benchmarks { ..Default::default() }); call_builder!(func, code); + + let res; #[block] { - func.call(); + res = func.call(); } + assert_eq!(res.did_revert(), false); Ok(()) } @@ -2734,10 +2897,13 @@ mod benchmarks { ..Default::default() }); call_builder!(func, code); + + let res; #[block] { - func.call(); + res = func.call(); } + assert_eq!(res.did_revert(), false); } // We load `i64` values from random linear memory locations and store the loaded diff --git a/substrate/frame/contracts/src/lib.rs b/substrate/frame/contracts/src/lib.rs index edc4c872bfce14e21d84ca14fc8877d88c362ff0..3e87eb9f37ea7fc023a76d8ac7dc048f7bed9f7d 100644 --- a/substrate/frame/contracts/src/lib.rs +++ b/substrate/frame/contracts/src/lib.rs @@ -101,6 +101,7 @@ mod wasm; pub mod chain_extension; pub mod debug; pub mod migration; +pub mod test_utils; pub mod weights; #[cfg(test)] @@ -222,14 +223,14 @@ pub struct Environment { pub struct ApiVersion(u16); impl Default for ApiVersion { fn default() -> Self { - Self(2) + Self(3) } } #[test] fn api_version_is_up_to_date() { assert_eq!( - 109, + 111, crate::wasm::STABLE_API_COUNT, "Stable API count has changed. Bump the returned value of ApiVersion::default() and update the test." ); diff --git a/substrate/frame/contracts/src/test_utils.rs b/substrate/frame/contracts/src/test_utils.rs new file mode 100644 index 0000000000000000000000000000000000000000..564b2d2e3bd237ae57263a3fe7ea1ddda95df408 --- /dev/null +++ b/substrate/frame/contracts/src/test_utils.rs @@ -0,0 +1,30 @@ +// 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. + +//! Shared utilities for testing contracts. +//! This is not part of the tests module because it is made public for other crates to use. +#![cfg(feature = "std")] +use frame_support::weights::Weight; +pub use sp_runtime::AccountId32; + +pub const ALICE: AccountId32 = AccountId32::new([1u8; 32]); +pub const BOB: AccountId32 = AccountId32::new([2u8; 32]); +pub const CHARLIE: AccountId32 = AccountId32::new([3u8; 32]); +pub const DJANGO: AccountId32 = AccountId32::new([4u8; 32]); + +pub const GAS_LIMIT: Weight = Weight::from_parts(100_000_000_000, 3 * 1024 * 1024); +pub mod builder; diff --git a/substrate/frame/contracts/src/test_utils/builder.rs b/substrate/frame/contracts/src/test_utils/builder.rs new file mode 100644 index 0000000000000000000000000000000000000000..94540eca5b4bf2c02a6b58e45857e112f1f18c05 --- /dev/null +++ b/substrate/frame/contracts/src/test_utils/builder.rs @@ -0,0 +1,220 @@ +// 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::GAS_LIMIT; +use crate::{ + AccountIdLookupOf, AccountIdOf, BalanceOf, Code, CodeHash, CollectEvents, Config, + ContractExecResult, ContractInstantiateResult, DebugInfo, Determinism, EventRecordOf, + ExecReturnValue, InstantiateReturnValue, OriginFor, Pallet, Weight, +}; +use codec::{Encode, HasCompact}; +use core::fmt::Debug; +use frame_support::pallet_prelude::DispatchResultWithPostInfo; +use paste::paste; +use scale_info::TypeInfo; + +/// Helper macro to generate a builder for contract API calls. +macro_rules! builder { + // Entry point to generate a builder for the given method. + ( + $method:ident($($field:ident: $type:ty,)*) -> $result:ty; + $($extra:item)* + ) => { + paste!{ + builder!([< $method:camel Builder >], $method($($field: $type,)* ) -> $result; $($extra)*); + } + }; + // Generate the builder struct and its methods. + ( + $name:ident, + $method:ident($($field:ident: $type:ty,)*) -> $result:ty; + $($extra:item)* + ) => { + #[doc = concat!("A builder to construct a ", stringify!($method), " call")] + pub struct $name { + $($field: $type,)* + } + + #[allow(dead_code)] + impl $name + where + as HasCompact>::Type: Clone + Eq + PartialEq + Debug + TypeInfo + Encode, + { + $( + #[doc = concat!("Set the ", stringify!($field))] + pub fn $field(mut self, value: $type) -> Self { + self.$field = value; + self + } + )* + + #[doc = concat!("Build the ", stringify!($method), " call")] + pub fn build(self) -> $result { + Pallet::::$method( + $(self.$field,)* + ) + } + + $($extra)* + } + } +} + +builder!( + instantiate_with_code( + origin: OriginFor, + value: BalanceOf, + gas_limit: Weight, + storage_deposit_limit: Option< as codec::HasCompact>::Type>, + code: Vec, + data: Vec, + salt: Vec, + ) -> DispatchResultWithPostInfo; + + /// Create an [`InstantiateWithCodeBuilder`] with default values. + pub fn instantiate_with_code(origin: OriginFor, code: Vec) -> Self { + Self { + origin: origin, + value: 0u32.into(), + gas_limit: GAS_LIMIT, + storage_deposit_limit: None, + code, + data: vec![], + salt: vec![], + } + } +); + +builder!( + instantiate( + origin: OriginFor, + value: BalanceOf, + gas_limit: Weight, + storage_deposit_limit: Option< as codec::HasCompact>::Type>, + code_hash: CodeHash, + data: Vec, + salt: Vec, + ) -> DispatchResultWithPostInfo; + + /// Create an [`InstantiateBuilder`] with default values. + pub fn instantiate(origin: OriginFor, code_hash: CodeHash) -> Self { + Self { + origin, + value: 0u32.into(), + gas_limit: GAS_LIMIT, + storage_deposit_limit: None, + code_hash, + data: vec![], + salt: vec![], + } + } +); + +builder!( + bare_instantiate( + origin: AccountIdOf, + value: BalanceOf, + gas_limit: Weight, + storage_deposit_limit: Option>, + code: Code>, + data: Vec, + salt: Vec, + debug: DebugInfo, + collect_events: CollectEvents, + ) -> ContractInstantiateResult, BalanceOf, EventRecordOf>; + + /// Build the instantiate call and unwrap the result. + pub fn build_and_unwrap_result(self) -> InstantiateReturnValue> { + self.build().result.unwrap() + } + + /// Build the instantiate call and unwrap the account id. + pub fn build_and_unwrap_account_id(self) -> AccountIdOf { + self.build().result.unwrap().account_id + } + + pub fn bare_instantiate(origin: AccountIdOf, code: Code>) -> Self { + Self { + origin, + value: 0u32.into(), + gas_limit: GAS_LIMIT, + storage_deposit_limit: None, + code, + data: vec![], + salt: vec![], + debug: DebugInfo::Skip, + collect_events: CollectEvents::Skip, + } + } +); + +builder!( + call( + origin: OriginFor, + dest: AccountIdLookupOf, + value: BalanceOf, + gas_limit: Weight, + storage_deposit_limit: Option< as codec::HasCompact>::Type>, + data: Vec, + ) -> DispatchResultWithPostInfo; + + /// Create a [`CallBuilder`] with default values. + pub fn call(origin: OriginFor, dest: AccountIdLookupOf) -> Self { + CallBuilder { + origin, + dest, + value: 0u32.into(), + gas_limit: GAS_LIMIT, + storage_deposit_limit: None, + data: vec![], + } + } +); + +builder!( + bare_call( + origin: AccountIdOf, + dest: AccountIdOf, + value: BalanceOf, + gas_limit: Weight, + storage_deposit_limit: Option>, + data: Vec, + debug: DebugInfo, + collect_events: CollectEvents, + determinism: Determinism, + ) -> ContractExecResult, EventRecordOf>; + + /// Build the call and unwrap the result. + pub fn build_and_unwrap_result(self) -> ExecReturnValue { + self.build().result.unwrap() + } + + /// Create a [`BareCallBuilder`] with default values. + pub fn bare_call(origin: AccountIdOf, dest: AccountIdOf) -> Self { + Self { + origin, + dest, + value: 0u32.into(), + gas_limit: GAS_LIMIT, + storage_deposit_limit: None, + data: vec![], + debug: DebugInfo::Skip, + collect_events: CollectEvents::Skip, + determinism: Determinism::Enforced, + } + } +); diff --git a/substrate/frame/contracts/src/tests.rs b/substrate/frame/contracts/src/tests.rs index 57b804a51e4175a9c92683e9431a95de8c2cb397..8fe845fcf0f83e8658e7638ea2536bee2794d73f 100644 --- a/substrate/frame/contracts/src/tests.rs +++ b/substrate/frame/contracts/src/tests.rs @@ -15,7 +15,6 @@ // See the License for the specific language governing permissions and // limitations under the License. -mod builder; mod pallet_dummy; mod test_debug; @@ -98,7 +97,6 @@ macro_rules! assert_refcount { } pub mod test_utils { - use super::{Contracts, DepositPerByte, DepositPerItem, Hash, SysConfig, Test}; use crate::{ exec::AccountIdOf, BalanceOf, CodeHash, CodeInfo, CodeInfoOf, Config, ContractInfo, @@ -166,6 +164,38 @@ pub mod test_utils { } } +mod builder { + use super::Test; + use crate::{ + test_utils::{builder::*, AccountId32, ALICE}, + tests::RuntimeOrigin, + AccountIdLookupOf, Code, CodeHash, + }; + + pub fn bare_instantiate(code: Code>) -> BareInstantiateBuilder { + BareInstantiateBuilder::::bare_instantiate(ALICE, code) + } + + pub fn bare_call(dest: AccountId32) -> BareCallBuilder { + BareCallBuilder::::bare_call(ALICE, dest) + } + + pub fn instantiate_with_code(code: Vec) -> InstantiateWithCodeBuilder { + InstantiateWithCodeBuilder::::instantiate_with_code( + RuntimeOrigin::signed(ALICE), + code, + ) + } + + pub fn instantiate(code_hash: CodeHash) -> InstantiateBuilder { + InstantiateBuilder::::instantiate(RuntimeOrigin::signed(ALICE), code_hash) + } + + pub fn call(dest: AccountIdLookupOf) -> CallBuilder { + CallBuilder::::call(RuntimeOrigin::signed(ALICE), dest) + } +} + impl Test { pub fn set_unstable_interface(unstable_interface: bool) { UNSTABLE_INTERFACE.with(|v| *v.borrow_mut() = unstable_interface); @@ -2439,14 +2469,7 @@ fn failed_deposit_charge_should_roll_back_call() { transfer_proxy_call, ); - >::call( - RuntimeOrigin::signed(ALICE), - addr_caller.clone(), - 0, - GAS_LIMIT, - None, - data.encode(), - ) + builder::call(addr_caller).data(data.encode()).build() }) }; diff --git a/substrate/frame/contracts/src/tests/builder.rs b/substrate/frame/contracts/src/tests/builder.rs deleted file mode 100644 index 08d12503a290ad30a08c44daf73647e278b9a398..0000000000000000000000000000000000000000 --- a/substrate/frame/contracts/src/tests/builder.rs +++ /dev/null @@ -1,219 +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 super::{AccountId32, Test, ALICE, GAS_LIMIT}; -use crate::{ - tests::RuntimeOrigin, AccountIdLookupOf, AccountIdOf, BalanceOf, Code, CodeHash, CollectEvents, - ContractExecResult, ContractInstantiateResult, DebugInfo, Determinism, EventRecordOf, - ExecReturnValue, OriginFor, Pallet, Weight, -}; -use codec::Compact; -use frame_support::pallet_prelude::DispatchResultWithPostInfo; -use paste::paste; - -/// Helper macro to generate a builder for contract API calls. -macro_rules! builder { - // Entry point to generate a builder for the given method. - ( - $method:ident($($field:ident: $type:ty,)*) -> $result:ty - ) => { - paste!{ - builder!([< $method:camel Builder >], $method($($field: $type,)* ) -> $result); - } - }; - // Generate the builder struct and its methods. - ( - $name:ident, - $method:ident( - $($field:ident: $type:ty,)* - ) -> $result:ty - ) => { - #[doc = concat!("A builder to construct a ", stringify!($method), " call")] - pub struct $name { - $($field: $type,)* - } - - #[allow(dead_code)] - impl $name - { - $( - #[doc = concat!("Set the ", stringify!($field))] - pub fn $field(mut self, value: $type) -> Self { - self.$field = value; - self - } - )* - - #[doc = concat!("Build the ", stringify!($method), " call")] - pub fn build(self) -> $result { - Pallet::::$method( - $(self.$field,)* - ) - } - } - } -} - -builder!( - instantiate_with_code( - origin: OriginFor, - value: BalanceOf, - gas_limit: Weight, - storage_deposit_limit: Option>>, - code: Vec, - data: Vec, - salt: Vec, - ) -> DispatchResultWithPostInfo -); - -builder!( - instantiate( - origin: OriginFor, - value: BalanceOf, - gas_limit: Weight, - storage_deposit_limit: Option>>, - code_hash: CodeHash, - data: Vec, - salt: Vec, - ) -> DispatchResultWithPostInfo -); - -builder!( - bare_instantiate( - origin: AccountIdOf, - value: BalanceOf, - gas_limit: Weight, - storage_deposit_limit: Option>, - code: Code>, - data: Vec, - salt: Vec, - debug: DebugInfo, - collect_events: CollectEvents, - ) -> ContractInstantiateResult, BalanceOf, EventRecordOf> -); - -builder!( - call( - origin: OriginFor, - dest: AccountIdLookupOf, - value: BalanceOf, - gas_limit: Weight, - storage_deposit_limit: Option>>, - data: Vec, - ) -> DispatchResultWithPostInfo -); - -builder!( - bare_call( - origin: AccountIdOf, - dest: AccountIdOf, - value: BalanceOf, - gas_limit: Weight, - storage_deposit_limit: Option>, - data: Vec, - debug: DebugInfo, - collect_events: CollectEvents, - determinism: Determinism, - ) -> ContractExecResult, EventRecordOf> -); - -/// Create a [`BareInstantiateBuilder`] with default values. -pub fn bare_instantiate(code: Code>) -> BareInstantiateBuilder { - BareInstantiateBuilder { - origin: ALICE, - value: 0, - gas_limit: GAS_LIMIT, - storage_deposit_limit: None, - code, - data: vec![], - salt: vec![], - debug: DebugInfo::Skip, - collect_events: CollectEvents::Skip, - } -} - -impl BareInstantiateBuilder { - /// Build the instantiate call and unwrap the result. - pub fn build_and_unwrap_result(self) -> crate::InstantiateReturnValue> { - self.build().result.unwrap() - } - - /// Build the instantiate call and unwrap the account id. - pub fn build_and_unwrap_account_id(self) -> AccountIdOf { - self.build().result.unwrap().account_id - } -} - -/// Create a [`BareCallBuilder`] with default values. -pub fn bare_call(dest: AccountId32) -> BareCallBuilder { - BareCallBuilder { - origin: ALICE, - dest, - value: 0, - gas_limit: GAS_LIMIT, - storage_deposit_limit: None, - data: vec![], - debug: DebugInfo::Skip, - collect_events: CollectEvents::Skip, - determinism: Determinism::Enforced, - } -} - -impl BareCallBuilder { - /// Build the call and unwrap the result. - pub fn build_and_unwrap_result(self) -> ExecReturnValue { - self.build().result.unwrap() - } -} - -/// Create an [`InstantiateWithCodeBuilder`] with default values. -pub fn instantiate_with_code(code: Vec) -> InstantiateWithCodeBuilder { - InstantiateWithCodeBuilder { - origin: RuntimeOrigin::signed(ALICE), - value: 0, - gas_limit: GAS_LIMIT, - storage_deposit_limit: None, - code, - data: vec![], - salt: vec![], - } -} - -/// Create an [`InstantiateBuilder`] with default values. -pub fn instantiate(code_hash: CodeHash) -> InstantiateBuilder { - InstantiateBuilder { - origin: RuntimeOrigin::signed(ALICE), - value: 0, - gas_limit: GAS_LIMIT, - storage_deposit_limit: None, - code_hash, - data: vec![], - salt: vec![], - } -} - -/// Create a [`CallBuilder`] with default values. -pub fn call(dest: AccountIdLookupOf) -> CallBuilder { - CallBuilder { - origin: RuntimeOrigin::signed(ALICE), - dest, - value: 0, - gas_limit: GAS_LIMIT, - storage_deposit_limit: None, - data: vec![], - } -} diff --git a/substrate/frame/contracts/src/wasm/runtime.rs b/substrate/frame/contracts/src/wasm/runtime.rs index 28a08ab0224ddf4603c881b50c9359d4a6f54d46..3212aff31269a91d66ce0043f60c8130b2d4bc9a 100644 --- a/substrate/frame/contracts/src/wasm/runtime.rs +++ b/substrate/frame/contracts/src/wasm/runtime.rs @@ -38,6 +38,8 @@ use sp_runtime::{ use sp_std::{fmt, prelude::*}; use wasmi::{core::HostError, errors::LinkerError, Linker, Memory, Store}; +type CallOf = ::RuntimeCall; + /// The maximum nesting depth a contract can use when encoding types. const MAX_DECODE_NESTING: u32 = 256; @@ -2074,7 +2076,6 @@ pub mod env { /// Execute an XCM program locally, using the contract's address as the origin. /// See [`pallet_contracts_uapi::HostFn::execute_xcm`]. - #[unstable] fn xcm_execute( ctx: _, memory: _, @@ -2082,13 +2083,15 @@ pub mod env { msg_len: u32, ) -> Result { use frame_support::dispatch::DispatchInfo; + use xcm::VersionedXcm; use xcm_builder::{ExecuteController, ExecuteControllerWeightInfo}; ctx.charge_gas(RuntimeCosts::CopyFromContract(msg_len))?; - let message = ctx.read_sandbox_memory_as_unbounded(memory, msg_ptr, msg_len)?; + let message: VersionedXcm> = + ctx.read_sandbox_memory_as_unbounded(memory, msg_ptr, msg_len)?; let execute_weight = - <::Xcm as ExecuteController<_, _>>::WeightInfo::execute_blob(); + <::Xcm as ExecuteController<_, _>>::WeightInfo::execute(); let weight = ctx.ext.gas_meter().gas_left().max(execute_weight); let dispatch_info = DispatchInfo { weight, ..Default::default() }; @@ -2097,9 +2100,9 @@ pub mod env { RuntimeCosts::CallXcmExecute, |ctx| { let origin = crate::RawOrigin::Signed(ctx.ext.address().clone()).into(); - let weight_used = <::Xcm>::execute_blob( + let weight_used = <::Xcm>::execute( origin, - message, + Box::new(message), weight.saturating_sub(execute_weight), )?; @@ -2110,7 +2113,6 @@ pub mod env { /// Send an XCM program from the contract to the specified destination. /// See [`pallet_contracts_uapi::HostFn::send_xcm`]. - #[unstable] fn xcm_send( ctx: _, memory: _, @@ -2119,18 +2121,19 @@ pub mod env { msg_len: u32, output_ptr: u32, ) -> Result { - use xcm::VersionedLocation; + use xcm::{VersionedLocation, VersionedXcm}; use xcm_builder::{SendController, SendControllerWeightInfo}; ctx.charge_gas(RuntimeCosts::CopyFromContract(msg_len))?; let dest: VersionedLocation = ctx.read_sandbox_memory_as(memory, dest_ptr)?; - let message = ctx.read_sandbox_memory_as_unbounded(memory, msg_ptr, msg_len)?; - let weight = <::Xcm as SendController<_>>::WeightInfo::send_blob(); + let message: VersionedXcm<()> = + ctx.read_sandbox_memory_as_unbounded(memory, msg_ptr, msg_len)?; + let weight = <::Xcm as SendController<_>>::WeightInfo::send(); ctx.charge_gas(RuntimeCosts::CallRuntime(weight))?; let origin = crate::RawOrigin::Signed(ctx.ext.address().clone()).into(); - match <::Xcm>::send_blob(origin, dest.into(), message) { + match <::Xcm>::send(origin, dest.into(), message.into()) { Ok(message_id) => { ctx.write_sandbox_memory(memory, output_ptr, &message_id.encode())?; Ok(ReturnErrorCode::Success) diff --git a/substrate/frame/contracts/src/weights.rs b/substrate/frame/contracts/src/weights.rs index ca7f58cf5b0cada995a268cc241b36a0599cb709..b95b1d1a9a2e5ae47ca0d9fe1715031f47e43986 100644 --- a/substrate/frame/contracts/src/weights.rs +++ b/substrate/frame/contracts/src/weights.rs @@ -18,7 +18,7 @@ //! Autogenerated weights for `pallet_contracts` //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 32.0.0 -//! DATE: 2024-04-10, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! DATE: 2024-04-15, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` //! WORST CASE MAP SIZE: `1000000` //! HOSTNAME: `runner-anb7yjbi-project-674-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` //! WASM-EXECUTION: `Compiled`, CHAIN: `Some("dev")`, DB CACHE: `1024` @@ -143,8 +143,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `142` // Estimated: `1627` - // Minimum execution time: 2_047_000 picoseconds. - Weight::from_parts(2_116_000, 1627) + // Minimum execution time: 2_149_000 picoseconds. + Weight::from_parts(2_274_000, 1627) .saturating_add(T::DbWeight::get().reads(1_u64)) } /// Storage: `Skipped::Metadata` (r:0 w:0) @@ -154,10 +154,10 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `452 + k * (69 ±0)` // Estimated: `442 + k * (70 ±0)` - // Minimum execution time: 12_474_000 picoseconds. - Weight::from_parts(12_767_000, 442) - // Standard Error: 1_081 - .saturating_add(Weight::from_parts(1_187_278, 0).saturating_mul(k.into())) + // Minimum execution time: 12_863_000 picoseconds. + Weight::from_parts(13_188_000, 442) + // Standard Error: 1_053 + .saturating_add(Weight::from_parts(1_105_325, 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)) @@ -171,10 +171,10 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `211 + c * (1 ±0)` // Estimated: `6149 + c * (1 ±0)` - // Minimum execution time: 8_307_000 picoseconds. - Weight::from_parts(8_939_322, 6149) + // Minimum execution time: 8_432_000 picoseconds. + Weight::from_parts(9_203_290, 6149) // Standard Error: 1 - .saturating_add(Weight::from_parts(1_190, 0).saturating_mul(c.into())) + .saturating_add(Weight::from_parts(1_186, 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())) @@ -187,8 +187,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `510` // Estimated: `6450` - // Minimum execution time: 16_915_000 picoseconds. - Weight::from_parts(17_638_000, 6450) + // Minimum execution time: 17_177_000 picoseconds. + Weight::from_parts(17_663_000, 6450) .saturating_add(T::DbWeight::get().reads(3_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -201,10 +201,10 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `171 + k * (1 ±0)` // Estimated: `3635 + k * (1 ±0)` - // Minimum execution time: 3_607_000 picoseconds. - Weight::from_parts(1_979_323, 3635) - // Standard Error: 1_018 - .saturating_add(Weight::from_parts(1_196_162, 0).saturating_mul(k.into())) + // Minimum execution time: 3_636_000 picoseconds. + Weight::from_parts(3_774_000, 3635) + // Standard Error: 542 + .saturating_add(Weight::from_parts(1_260_058, 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()))) @@ -225,10 +225,10 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `328 + c * (1 ±0)` // Estimated: `6266 + c * (1 ±0)` - // Minimum execution time: 21_056_000 picoseconds. - Weight::from_parts(21_633_895, 6266) + // Minimum execution time: 21_585_000 picoseconds. + Weight::from_parts(22_069_944, 6266) // Standard Error: 1 - .saturating_add(Weight::from_parts(390, 0).saturating_mul(c.into())) + .saturating_add(Weight::from_parts(404, 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())) @@ -239,8 +239,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `440` // Estimated: `6380` - // Minimum execution time: 12_860_000 picoseconds. - Weight::from_parts(13_525_000, 6380) + // Minimum execution time: 13_283_000 picoseconds. + Weight::from_parts(14_015_000, 6380) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -254,8 +254,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `352` // Estimated: `6292` - // Minimum execution time: 46_926_000 picoseconds. - Weight::from_parts(47_828_000, 6292) + // Minimum execution time: 48_022_000 picoseconds. + Weight::from_parts(49_627_000, 6292) .saturating_add(T::DbWeight::get().reads(4_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -267,8 +267,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `594` // Estimated: `6534` - // Minimum execution time: 55_081_000 picoseconds. - Weight::from_parts(56_899_000, 6534) + // Minimum execution time: 58_374_000 picoseconds. + Weight::from_parts(59_615_000, 6534) .saturating_add(T::DbWeight::get().reads(4_u64)) .saturating_add(T::DbWeight::get().writes(2_u64)) } @@ -278,8 +278,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `409` // Estimated: `6349` - // Minimum execution time: 12_595_000 picoseconds. - Weight::from_parts(13_059_000, 6349) + // Minimum execution time: 12_559_000 picoseconds. + Weight::from_parts(12_947_000, 6349) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -290,7 +290,7 @@ impl WeightInfo for SubstrateWeight { // Measured: `142` // Estimated: `1627` // Minimum execution time: 2_480_000 picoseconds. - Weight::from_parts(2_663_000, 1627) + Weight::from_parts(2_680_000, 1627) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -302,8 +302,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `166` // Estimated: `3631` - // Minimum execution time: 12_115_000 picoseconds. - Weight::from_parts(12_506_000, 3631) + // Minimum execution time: 12_625_000 picoseconds. + Weight::from_parts(13_094_000, 3631) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(2_u64)) } @@ -313,8 +313,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `142` // Estimated: `3607` - // Minimum execution time: 4_757_000 picoseconds. - Weight::from_parts(5_082_000, 3607) + // Minimum execution time: 4_836_000 picoseconds. + Weight::from_parts(5_182_000, 3607) .saturating_add(T::DbWeight::get().reads(1_u64)) } /// Storage: UNKNOWN KEY `0x4342193e496fab7ec59d615ed0dc55304e7b9012096b41c4eb3aaf947f6ea429` (r:1 w:0) @@ -325,8 +325,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `167` // Estimated: `3632` - // Minimum execution time: 6_017_000 picoseconds. - Weight::from_parts(6_421_000, 3632) + // Minimum execution time: 6_319_000 picoseconds. + Weight::from_parts(6_582_000, 3632) .saturating_add(T::DbWeight::get().reads(2_u64)) } /// Storage: UNKNOWN KEY `0x4342193e496fab7ec59d615ed0dc55304e7b9012096b41c4eb3aaf947f6ea429` (r:1 w:0) @@ -337,8 +337,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `142` // Estimated: `3607` - // Minimum execution time: 6_238_000 picoseconds. - Weight::from_parts(6_587_000, 3607) + // Minimum execution time: 6_532_000 picoseconds. + Weight::from_parts(6_909_000, 3607) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -363,10 +363,10 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `804 + c * (1 ±0)` // Estimated: `9217 + c * (1 ±0)` - // Minimum execution time: 288_968_000 picoseconds. - Weight::from_parts(267_291_922, 9217) - // Standard Error: 78 - .saturating_add(Weight::from_parts(34_879, 0).saturating_mul(c.into())) + // Minimum execution time: 305_778_000 picoseconds. + Weight::from_parts(282_321_249, 9217) + // Standard Error: 72 + .saturating_add(Weight::from_parts(33_456, 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())) @@ -398,14 +398,14 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `326` // Estimated: `8740` - // Minimum execution time: 3_948_426_000 picoseconds. - Weight::from_parts(440_017_623, 8740) - // Standard Error: 555 - .saturating_add(Weight::from_parts(71_483, 0).saturating_mul(c.into())) - // Standard Error: 66 - .saturating_add(Weight::from_parts(1_831, 0).saturating_mul(i.into())) - // Standard Error: 66 - .saturating_add(Weight::from_parts(1_694, 0).saturating_mul(s.into())) + // Minimum execution time: 3_810_809_000 picoseconds. + Weight::from_parts(739_511_598, 8740) + // Standard Error: 140 + .saturating_add(Weight::from_parts(67_574, 0).saturating_mul(c.into())) + // Standard Error: 16 + .saturating_add(Weight::from_parts(1_488, 0).saturating_mul(i.into())) + // Standard Error: 16 + .saturating_add(Weight::from_parts(1_537, 0).saturating_mul(s.into())) .saturating_add(T::DbWeight::get().reads(14_u64)) .saturating_add(T::DbWeight::get().writes(10_u64)) } @@ -435,12 +435,12 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `563` // Estimated: `8982` - // Minimum execution time: 2_011_037_000 picoseconds. - Weight::from_parts(2_047_025_000, 8982) - // Standard Error: 28 - .saturating_add(Weight::from_parts(968, 0).saturating_mul(i.into())) - // Standard Error: 28 - .saturating_add(Weight::from_parts(780, 0).saturating_mul(s.into())) + // Minimum execution time: 1_986_789_000 picoseconds. + Weight::from_parts(2_017_466_000, 8982) + // Standard Error: 26 + .saturating_add(Weight::from_parts(827, 0).saturating_mul(i.into())) + // Standard Error: 26 + .saturating_add(Weight::from_parts(781, 0).saturating_mul(s.into())) .saturating_add(T::DbWeight::get().reads(13_u64)) .saturating_add(T::DbWeight::get().writes(7_u64)) } @@ -464,8 +464,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `829` // Estimated: `9244` - // Minimum execution time: 202_190_000 picoseconds. - Weight::from_parts(209_378_000, 9244) + // Minimum execution time: 210_724_000 picoseconds. + Weight::from_parts(218_608_000, 9244) .saturating_add(T::DbWeight::get().reads(11_u64)) .saturating_add(T::DbWeight::get().writes(4_u64)) } @@ -486,10 +486,10 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `145` // Estimated: `6085` - // Minimum execution time: 271_161_000 picoseconds. - Weight::from_parts(279_218_977, 6085) - // Standard Error: 80 - .saturating_add(Weight::from_parts(33_973, 0).saturating_mul(c.into())) + // Minimum execution time: 271_259_000 picoseconds. + Weight::from_parts(298_852_854, 6085) + // Standard Error: 65 + .saturating_add(Weight::from_parts(33_547, 0).saturating_mul(c.into())) .saturating_add(T::DbWeight::get().reads(6_u64)) .saturating_add(T::DbWeight::get().writes(4_u64)) } @@ -510,10 +510,10 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `145` // Estimated: `6085` - // Minimum execution time: 273_684_000 picoseconds. - Weight::from_parts(284_348_722, 6085) - // Standard Error: 79 - .saturating_add(Weight::from_parts(34_205, 0).saturating_mul(c.into())) + // Minimum execution time: 278_167_000 picoseconds. + Weight::from_parts(311_888_941, 6085) + // Standard Error: 58 + .saturating_add(Weight::from_parts(33_595, 0).saturating_mul(c.into())) .saturating_add(T::DbWeight::get().reads(6_u64)) .saturating_add(T::DbWeight::get().writes(4_u64)) } @@ -531,8 +531,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `315` // Estimated: `3780` - // Minimum execution time: 45_150_000 picoseconds. - Weight::from_parts(46_780_000, 3780) + // Minimum execution time: 47_403_000 picoseconds. + Weight::from_parts(48_707_000, 3780) .saturating_add(T::DbWeight::get().reads(4_u64)) .saturating_add(T::DbWeight::get().writes(4_u64)) } @@ -548,8 +548,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `552` // Estimated: `8967` - // Minimum execution time: 34_738_000 picoseconds. - Weight::from_parts(35_918_000, 8967) + // Minimum execution time: 35_361_000 picoseconds. + Weight::from_parts(36_714_000, 8967) .saturating_add(T::DbWeight::get().reads(7_u64)) .saturating_add(T::DbWeight::get().writes(6_u64)) } @@ -558,10 +558,10 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 9_094_000 picoseconds. - Weight::from_parts(10_253_702, 0) - // Standard Error: 223 - .saturating_add(Weight::from_parts(250_757, 0).saturating_mul(r.into())) + // Minimum execution time: 9_340_000 picoseconds. + Weight::from_parts(9_360_237, 0) + // Standard Error: 269 + .saturating_add(Weight::from_parts(249_611, 0).saturating_mul(r.into())) } /// Storage: `Contracts::ContractInfoOf` (r:1600 w:0) /// Proof: `Contracts::ContractInfoOf` (`max_values`: None, `max_size`: Some(1795), added: 4270, mode: `Measured`) @@ -570,10 +570,10 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `509 + r * (77 ±0)` // Estimated: `1467 + r * (2552 ±0)` - // Minimum execution time: 9_102_000 picoseconds. - Weight::from_parts(9_238_000, 1467) - // Standard Error: 6_076 - .saturating_add(Weight::from_parts(3_293_012, 0).saturating_mul(r.into())) + // Minimum execution time: 9_059_000 picoseconds. + Weight::from_parts(9_201_000, 1467) + // Standard Error: 5_643 + .saturating_add(Weight::from_parts(3_343_859, 0).saturating_mul(r.into())) .saturating_add(T::DbWeight::get().reads((1_u64).saturating_mul(r.into()))) .saturating_add(Weight::from_parts(0, 2552).saturating_mul(r.into())) } @@ -584,10 +584,10 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `517 + r * (170 ±0)` // Estimated: `1468 + r * (2645 ±0)` - // Minimum execution time: 9_255_000 picoseconds. - Weight::from_parts(9_406_000, 1468) - // Standard Error: 6_826 - .saturating_add(Weight::from_parts(4_205_039, 0).saturating_mul(r.into())) + // Minimum execution time: 9_220_000 picoseconds. + Weight::from_parts(9_399_000, 1468) + // Standard Error: 6_194 + .saturating_add(Weight::from_parts(4_172_011, 0).saturating_mul(r.into())) .saturating_add(T::DbWeight::get().reads((1_u64).saturating_mul(r.into()))) .saturating_add(Weight::from_parts(0, 2645).saturating_mul(r.into())) } @@ -596,50 +596,50 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 9_388_000 picoseconds. - Weight::from_parts(9_322_209, 0) - // Standard Error: 269 - .saturating_add(Weight::from_parts(358_189, 0).saturating_mul(r.into())) + // Minimum execution time: 9_707_000 picoseconds. + Weight::from_parts(10_100_456, 0) + // Standard Error: 234 + .saturating_add(Weight::from_parts(338_464, 0).saturating_mul(r.into())) } /// The range of component `r` is `[0, 1600]`. fn seal_caller_is_origin(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 9_300_000 picoseconds. - Weight::from_parts(10_268_326, 0) - // Standard Error: 72 - .saturating_add(Weight::from_parts(104_650, 0).saturating_mul(r.into())) + // Minimum execution time: 9_524_000 picoseconds. + Weight::from_parts(10_813_389, 0) + // Standard Error: 76 + .saturating_add(Weight::from_parts(102_535, 0).saturating_mul(r.into())) } /// The range of component `r` is `[0, 1600]`. fn seal_caller_is_root(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 9_162_000 picoseconds. - Weight::from_parts(10_059_984, 0) - // Standard Error: 87 - .saturating_add(Weight::from_parts(87_627, 0).saturating_mul(r.into())) + // Minimum execution time: 9_799_000 picoseconds. + Weight::from_parts(10_886_744, 0) + // Standard Error: 75 + .saturating_add(Weight::from_parts(80_901, 0).saturating_mul(r.into())) } /// The range of component `r` is `[0, 1600]`. fn seal_address(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 9_193_000 picoseconds. - Weight::from_parts(10_160_715, 0) - // Standard Error: 152 - .saturating_add(Weight::from_parts(263_703, 0).saturating_mul(r.into())) + // Minimum execution time: 9_895_000 picoseconds. + Weight::from_parts(10_658_338, 0) + // Standard Error: 189 + .saturating_add(Weight::from_parts(249_694, 0).saturating_mul(r.into())) } /// The range of component `r` is `[0, 1600]`. fn seal_gas_left(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 9_109_000 picoseconds. - Weight::from_parts(9_766_924, 0) - // Standard Error: 212 - .saturating_add(Weight::from_parts(291_694, 0).saturating_mul(r.into())) + // Minimum execution time: 9_643_000 picoseconds. + Weight::from_parts(10_932_126, 0) + // Standard Error: 153 + .saturating_add(Weight::from_parts(280_924, 0).saturating_mul(r.into())) } /// Storage: `System::Account` (r:1 w:0) /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `Measured`) @@ -648,10 +648,10 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `140` // Estimated: `3599` - // Minimum execution time: 9_463_000 picoseconds. - Weight::from_parts(9_541_000, 3599) - // Standard Error: 3_075 - .saturating_add(Weight::from_parts(1_606_043, 0).saturating_mul(r.into())) + // Minimum execution time: 9_548_000 picoseconds. + Weight::from_parts(9_737_000, 3599) + // Standard Error: 971 + .saturating_add(Weight::from_parts(1_704_134, 0).saturating_mul(r.into())) .saturating_add(T::DbWeight::get().reads(1_u64)) } /// The range of component `r` is `[0, 1600]`. @@ -659,40 +659,40 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 9_080_000 picoseconds. - Weight::from_parts(8_121_924, 0) - // Standard Error: 198 - .saturating_add(Weight::from_parts(247_527, 0).saturating_mul(r.into())) + // Minimum execution time: 9_172_000 picoseconds. + Weight::from_parts(18_255_933, 0) + // Standard Error: 540 + .saturating_add(Weight::from_parts(230_929, 0).saturating_mul(r.into())) } /// The range of component `r` is `[0, 1600]`. fn seal_minimum_balance(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 9_393_000 picoseconds. - Weight::from_parts(9_999_247, 0) - // Standard Error: 169 - .saturating_add(Weight::from_parts(244_563, 0).saturating_mul(r.into())) + // Minimum execution time: 9_232_000 picoseconds. + Weight::from_parts(9_796_584, 0) + // Standard Error: 208 + .saturating_add(Weight::from_parts(239_962, 0).saturating_mul(r.into())) } /// The range of component `r` is `[0, 1600]`. fn seal_block_number(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 9_236_000 picoseconds. - Weight::from_parts(9_561_435, 0) - // Standard Error: 195 - .saturating_add(Weight::from_parts(239_812, 0).saturating_mul(r.into())) + // Minimum execution time: 9_747_000 picoseconds. + Weight::from_parts(8_733_230, 0) + // Standard Error: 377 + .saturating_add(Weight::from_parts(253_801, 0).saturating_mul(r.into())) } /// The range of component `r` is `[0, 1600]`. fn seal_now(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 9_259_000 picoseconds. - Weight::from_parts(10_353_960, 0) - // Standard Error: 216 - .saturating_add(Weight::from_parts(243_754, 0).saturating_mul(r.into())) + // Minimum execution time: 9_214_000 picoseconds. + Weight::from_parts(10_194_153, 0) + // Standard Error: 516 + .saturating_add(Weight::from_parts(247_621, 0).saturating_mul(r.into())) } /// Storage: `TransactionPayment::NextFeeMultiplier` (r:1 w:0) /// Proof: `TransactionPayment::NextFeeMultiplier` (`max_values`: Some(1), `max_size`: Some(16), added: 511, mode: `Measured`) @@ -701,10 +701,10 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `67` // Estimated: `1552` - // Minimum execution time: 9_145_000 picoseconds. - Weight::from_parts(16_524_937, 1552) - // Standard Error: 438 - .saturating_add(Weight::from_parts(666_821, 0).saturating_mul(r.into())) + // Minimum execution time: 9_022_000 picoseconds. + Weight::from_parts(22_051_160, 1552) + // Standard Error: 697 + .saturating_add(Weight::from_parts(709_612, 0).saturating_mul(r.into())) .saturating_add(T::DbWeight::get().reads(1_u64)) } /// The range of component `r` is `[0, 1600]`. @@ -712,10 +712,10 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 9_179_000 picoseconds. - Weight::from_parts(8_893_261, 0) - // Standard Error: 215 - .saturating_add(Weight::from_parts(175_586, 0).saturating_mul(r.into())) + // Minimum execution time: 9_135_000 picoseconds. + Weight::from_parts(10_646_215, 0) + // Standard Error: 161 + .saturating_add(Weight::from_parts(170_336, 0).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`) @@ -738,10 +738,10 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `872` // Estimated: `9287` - // Minimum execution time: 259_315_000 picoseconds. - Weight::from_parts(137_461_362, 9287) - // Standard Error: 18 - .saturating_add(Weight::from_parts(1_388, 0).saturating_mul(n.into())) + // Minimum execution time: 273_896_000 picoseconds. + Weight::from_parts(148_309_654, 9287) + // Standard Error: 16 + .saturating_add(Weight::from_parts(1_355, 0).saturating_mul(n.into())) .saturating_add(T::DbWeight::get().reads(11_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) } @@ -750,20 +750,20 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 8_919_000 picoseconds. - Weight::from_parts(9_465_187, 0) - // Standard Error: 32_481 - .saturating_add(Weight::from_parts(992_912, 0).saturating_mul(r.into())) + // Minimum execution time: 8_906_000 picoseconds. + Weight::from_parts(9_264_446, 0) + // Standard Error: 19_760 + .saturating_add(Weight::from_parts(1_256_053, 0).saturating_mul(r.into())) } /// The range of component `n` is `[0, 1048576]`. fn seal_return_per_byte(n: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 10_244_000 picoseconds. - Weight::from_parts(10_654_989, 0) + // Minimum execution time: 10_266_000 picoseconds. + Weight::from_parts(10_602_261, 0) // Standard Error: 0 - .saturating_add(Weight::from_parts(315, 0).saturating_mul(n.into())) + .saturating_add(Weight::from_parts(318, 0).saturating_mul(n.into())) } /// Storage: `Contracts::MigrationInProgress` (r:1 w:0) /// Proof: `Contracts::MigrationInProgress` (`max_values`: Some(1), `max_size`: Some(1026), added: 1521, mode: `Measured`) @@ -792,10 +792,10 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `4805 + r * (2121 ±0)` // Estimated: `13220 + r * (81321 ±0)` - // Minimum execution time: 303_028_000 picoseconds. - Weight::from_parts(323_032_397, 13220) - // Standard Error: 848_406 - .saturating_add(Weight::from_parts(242_988_002, 0).saturating_mul(r.into())) + // Minimum execution time: 295_922_000 picoseconds. + Weight::from_parts(322_472_877, 13220) + // Standard Error: 993_812 + .saturating_add(Weight::from_parts(259_075_422, 0).saturating_mul(r.into())) .saturating_add(T::DbWeight::get().reads(11_u64)) .saturating_add(T::DbWeight::get().reads((36_u64).saturating_mul(r.into()))) .saturating_add(T::DbWeight::get().writes(3_u64)) @@ -809,10 +809,10 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `76` // Estimated: `1561` - // Minimum execution time: 9_227_000 picoseconds. - Weight::from_parts(14_055_283, 1561) - // Standard Error: 758 - .saturating_add(Weight::from_parts(1_104_996, 0).saturating_mul(r.into())) + // Minimum execution time: 9_427_000 picoseconds. + Weight::from_parts(12_996_213, 1561) + // Standard Error: 845 + .saturating_add(Weight::from_parts(1_182_642, 0).saturating_mul(r.into())) .saturating_add(T::DbWeight::get().reads(1_u64)) } /// The range of component `r` is `[0, 1600]`. @@ -820,10 +820,10 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 9_483_000 picoseconds. - Weight::from_parts(20_453_059, 0) - // Standard Error: 3_271 - .saturating_add(Weight::from_parts(1_713_468, 0).saturating_mul(r.into())) + // Minimum execution time: 9_304_000 picoseconds. + Weight::from_parts(25_678_842, 0) + // Standard Error: 1_855 + .saturating_add(Weight::from_parts(1_814_511, 0).saturating_mul(r.into())) } /// Storage: `System::EventTopics` (r:4 w:4) /// Proof: `System::EventTopics` (`max_values`: None, `max_size`: None, mode: `Measured`) @@ -833,12 +833,12 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `990 + t * (2475 ±0)` - // Minimum execution time: 23_517_000 picoseconds. - Weight::from_parts(15_543_153, 990) - // Standard Error: 13_814 - .saturating_add(Weight::from_parts(2_357_255, 0).saturating_mul(t.into())) - // Standard Error: 3 - .saturating_add(Weight::from_parts(573, 0).saturating_mul(n.into())) + // Minimum execution time: 23_425_000 picoseconds. + Weight::from_parts(15_229_010, 990) + // Standard Error: 14_380 + .saturating_add(Weight::from_parts(2_545_653, 0).saturating_mul(t.into())) + // Standard Error: 4 + .saturating_add(Weight::from_parts(594, 0).saturating_mul(n.into())) .saturating_add(T::DbWeight::get().reads((1_u64).saturating_mul(t.into()))) .saturating_add(T::DbWeight::get().writes((1_u64).saturating_mul(t.into()))) .saturating_add(Weight::from_parts(0, 2475).saturating_mul(t.into())) @@ -848,20 +848,20 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 8_448_000 picoseconds. - Weight::from_parts(9_845_841, 0) - // Standard Error: 58 - .saturating_add(Weight::from_parts(105_442, 0).saturating_mul(r.into())) + // Minimum execution time: 11_117_000 picoseconds. + Weight::from_parts(12_887_533, 0) + // Standard Error: 83 + .saturating_add(Weight::from_parts(99_373, 0).saturating_mul(r.into())) } /// The range of component `i` is `[0, 1048576]`. fn seal_debug_message_per_byte(i: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 10_869_000 picoseconds. - Weight::from_parts(11_024_000, 0) + // Minimum execution time: 10_982_000 picoseconds. + Weight::from_parts(11_176_000, 0) // Standard Error: 8 - .saturating_add(Weight::from_parts(991, 0).saturating_mul(i.into())) + .saturating_add(Weight::from_parts(983, 0).saturating_mul(i.into())) } /// Storage: `Skipped::Metadata` (r:0 w:0) /// Proof: `Skipped::Metadata` (`max_values`: None, `max_size`: None, mode: `Measured`) @@ -870,10 +870,10 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `108 + r * (150 ±0)` // Estimated: `105 + r * (151 ±0)` - // Minimum execution time: 9_119_000 picoseconds. - Weight::from_parts(9_270_000, 105) - // Standard Error: 8_960 - .saturating_add(Weight::from_parts(5_215_976, 0).saturating_mul(r.into())) + // Minimum execution time: 9_150_000 picoseconds. + Weight::from_parts(9_269_000, 105) + // Standard Error: 8_147 + .saturating_add(Weight::from_parts(5_339_554, 0).saturating_mul(r.into())) .saturating_add(T::DbWeight::get().reads((1_u64).saturating_mul(r.into()))) .saturating_add(T::DbWeight::get().writes((1_u64).saturating_mul(r.into()))) .saturating_add(Weight::from_parts(0, 151).saturating_mul(r.into())) @@ -885,10 +885,10 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `245` // Estimated: `245` - // Minimum execution time: 17_833_000 picoseconds. - Weight::from_parts(18_940_114, 245) - // Standard Error: 2 - .saturating_add(Weight::from_parts(316, 0).saturating_mul(n.into())) + // Minimum execution time: 19_085_000 picoseconds. + Weight::from_parts(20_007_323, 245) + // Standard Error: 3 + .saturating_add(Weight::from_parts(291, 0).saturating_mul(n.into())) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -899,10 +899,10 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `248 + n * (1 ±0)` // Estimated: `248 + n * (1 ±0)` - // Minimum execution time: 18_428_000 picoseconds. - Weight::from_parts(19_372_726, 248) - // Standard Error: 2 - .saturating_add(Weight::from_parts(85, 0).saturating_mul(n.into())) + // Minimum execution time: 19_127_000 picoseconds. + Weight::from_parts(21_152_987, 248) + // Standard Error: 3 + .saturating_add(Weight::from_parts(42, 0).saturating_mul(n.into())) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) .saturating_add(Weight::from_parts(0, 1).saturating_mul(n.into())) @@ -914,10 +914,10 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `108 + r * (150 ±0)` // Estimated: `105 + r * (151 ±0)` - // Minimum execution time: 9_335_000 picoseconds. - Weight::from_parts(9_459_000, 105) - // Standard Error: 9_156 - .saturating_add(Weight::from_parts(5_166_621, 0).saturating_mul(r.into())) + // Minimum execution time: 9_264_000 picoseconds. + Weight::from_parts(9_449_000, 105) + // Standard Error: 8_196 + .saturating_add(Weight::from_parts(5_325_578, 0).saturating_mul(r.into())) .saturating_add(T::DbWeight::get().reads((1_u64).saturating_mul(r.into()))) .saturating_add(T::DbWeight::get().writes((1_u64).saturating_mul(r.into()))) .saturating_add(Weight::from_parts(0, 151).saturating_mul(r.into())) @@ -929,10 +929,10 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `248 + n * (1 ±0)` // Estimated: `248 + n * (1 ±0)` - // Minimum execution time: 18_308_000 picoseconds. - Weight::from_parts(19_421_433, 248) + // Minimum execution time: 18_489_000 picoseconds. + Weight::from_parts(19_916_153, 248) // Standard Error: 2 - .saturating_add(Weight::from_parts(83, 0).saturating_mul(n.into())) + .saturating_add(Weight::from_parts(97, 0).saturating_mul(n.into())) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) .saturating_add(Weight::from_parts(0, 1).saturating_mul(n.into())) @@ -944,10 +944,10 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `108 + r * (150 ±0)` // Estimated: `105 + r * (151 ±0)` - // Minimum execution time: 9_184_000 picoseconds. - Weight::from_parts(9_245_000, 105) - // Standard Error: 8_442 - .saturating_add(Weight::from_parts(4_543_991, 0).saturating_mul(r.into())) + // Minimum execution time: 9_299_000 picoseconds. + Weight::from_parts(9_464_000, 105) + // Standard Error: 6_827 + .saturating_add(Weight::from_parts(4_720_699, 0).saturating_mul(r.into())) .saturating_add(T::DbWeight::get().reads((1_u64).saturating_mul(r.into()))) .saturating_add(Weight::from_parts(0, 151).saturating_mul(r.into())) } @@ -958,10 +958,10 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `248 + n * (1 ±0)` // Estimated: `248 + n * (1 ±0)` - // Minimum execution time: 17_194_000 picoseconds. - Weight::from_parts(19_032_094, 248) + // Minimum execution time: 17_981_000 picoseconds. + Weight::from_parts(19_802_353, 248) // Standard Error: 3 - .saturating_add(Weight::from_parts(590, 0).saturating_mul(n.into())) + .saturating_add(Weight::from_parts(617, 0).saturating_mul(n.into())) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(Weight::from_parts(0, 1).saturating_mul(n.into())) } @@ -972,10 +972,10 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `108 + r * (150 ±0)` // Estimated: `105 + r * (151 ±0)` - // Minimum execution time: 9_380_000 picoseconds. - Weight::from_parts(9_501_000, 105) - // Standard Error: 7_029 - .saturating_add(Weight::from_parts(4_406_690, 0).saturating_mul(r.into())) + // Minimum execution time: 9_891_000 picoseconds. + Weight::from_parts(10_046_000, 105) + // Standard Error: 6_993 + .saturating_add(Weight::from_parts(4_601_167, 0).saturating_mul(r.into())) .saturating_add(T::DbWeight::get().reads((1_u64).saturating_mul(r.into()))) .saturating_add(Weight::from_parts(0, 151).saturating_mul(r.into())) } @@ -986,10 +986,10 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `248 + n * (1 ±0)` // Estimated: `248 + n * (1 ±0)` - // Minimum execution time: 16_400_000 picoseconds. - Weight::from_parts(17_993_941, 248) + // Minimum execution time: 17_229_000 picoseconds. + Weight::from_parts(18_302_733, 248) // Standard Error: 2 - .saturating_add(Weight::from_parts(68, 0).saturating_mul(n.into())) + .saturating_add(Weight::from_parts(112, 0).saturating_mul(n.into())) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(Weight::from_parts(0, 1).saturating_mul(n.into())) } @@ -1000,10 +1000,10 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `108 + r * (150 ±0)` // Estimated: `105 + r * (151 ±0)` - // Minimum execution time: 9_109_000 picoseconds. - Weight::from_parts(9_265_000, 105) - // Standard Error: 8_733 - .saturating_add(Weight::from_parts(5_218_811, 0).saturating_mul(r.into())) + // Minimum execution time: 9_323_000 picoseconds. + Weight::from_parts(9_462_000, 105) + // Standard Error: 8_031 + .saturating_add(Weight::from_parts(5_433_981, 0).saturating_mul(r.into())) .saturating_add(T::DbWeight::get().reads((1_u64).saturating_mul(r.into()))) .saturating_add(T::DbWeight::get().writes((1_u64).saturating_mul(r.into()))) .saturating_add(Weight::from_parts(0, 151).saturating_mul(r.into())) @@ -1015,10 +1015,10 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `248 + n * (1 ±0)` // Estimated: `248 + n * (1 ±0)` - // Minimum execution time: 18_423_000 picoseconds. - Weight::from_parts(20_025_132, 248) + // Minimum execution time: 18_711_000 picoseconds. + Weight::from_parts(20_495_670, 248) // Standard Error: 3 - .saturating_add(Weight::from_parts(628, 0).saturating_mul(n.into())) + .saturating_add(Weight::from_parts(640, 0).saturating_mul(n.into())) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) .saturating_add(Weight::from_parts(0, 1).saturating_mul(n.into())) @@ -1030,10 +1030,10 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `770` // Estimated: `4221 + r * (2475 ±0)` - // Minimum execution time: 9_043_000 picoseconds. - Weight::from_parts(9_176_000, 4221) - // Standard Error: 12_901 - .saturating_add(Weight::from_parts(32_297_438, 0).saturating_mul(r.into())) + // Minimum execution time: 9_226_000 picoseconds. + Weight::from_parts(9_394_000, 4221) + // Standard Error: 14_741 + .saturating_add(Weight::from_parts(34_179_316, 0).saturating_mul(r.into())) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().reads((1_u64).saturating_mul(r.into()))) .saturating_add(T::DbWeight::get().writes(1_u64)) @@ -1055,10 +1055,10 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `520 + r * (170 ±0)` // Estimated: `6463 + r * (2646 ±0)` - // Minimum execution time: 9_299_000 picoseconds. - Weight::from_parts(9_427_000, 6463) - // Standard Error: 101_949 - .saturating_add(Weight::from_parts(244_143_691, 0).saturating_mul(r.into())) + // Minimum execution time: 9_455_000 picoseconds. + Weight::from_parts(9_671_000, 6463) + // Standard Error: 126_080 + .saturating_add(Weight::from_parts(244_204_040, 0).saturating_mul(r.into())) .saturating_add(T::DbWeight::get().reads(5_u64)) .saturating_add(T::DbWeight::get().reads((2_u64).saturating_mul(r.into()))) .saturating_add(T::DbWeight::get().writes(2_u64)) @@ -1079,11 +1079,11 @@ impl WeightInfo for SubstrateWeight { fn seal_delegate_call(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0 + r * (527 ±0)` - // Estimated: `6447 + r * (2583 ±3)` - // Minimum execution time: 9_359_000 picoseconds. - Weight::from_parts(9_425_000, 6447) - // Standard Error: 193_938 - .saturating_add(Weight::from_parts(244_904_401, 0).saturating_mul(r.into())) + // Estimated: `6447 + r * (2583 ±10)` + // Minimum execution time: 9_274_000 picoseconds. + Weight::from_parts(9_437_000, 6447) + // Standard Error: 150_832 + .saturating_add(Weight::from_parts(244_196_269, 0).saturating_mul(r.into())) .saturating_add(T::DbWeight::get().reads((3_u64).saturating_mul(r.into()))) .saturating_add(T::DbWeight::get().writes((1_u64).saturating_mul(r.into()))) .saturating_add(Weight::from_parts(0, 2583).saturating_mul(r.into())) @@ -1106,12 +1106,12 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `699 + t * (277 ±0)` // Estimated: `6639 + t * (3458 ±0)` - // Minimum execution time: 214_588_000 picoseconds. - Weight::from_parts(129_214_481, 6639) - // Standard Error: 2_468_090 - .saturating_add(Weight::from_parts(32_514_739, 0).saturating_mul(t.into())) + // Minimum execution time: 214_483_000 picoseconds. + Weight::from_parts(122_634_366, 6639) + // Standard Error: 2_499_235 + .saturating_add(Weight::from_parts(41_326_008, 0).saturating_mul(t.into())) // Standard Error: 3 - .saturating_add(Weight::from_parts(418, 0).saturating_mul(c.into())) + .saturating_add(Weight::from_parts(422, 0).saturating_mul(c.into())) .saturating_add(T::DbWeight::get().reads(7_u64)) .saturating_add(T::DbWeight::get().reads((2_u64).saturating_mul(t.into()))) .saturating_add(T::DbWeight::get().writes(4_u64)) @@ -1126,10 +1126,10 @@ impl WeightInfo for SubstrateWeight { /// Proof: `Contracts::Nonce` (`max_values`: Some(1), `max_size`: Some(8), added: 503, mode: `Measured`) /// Storage: `Contracts::ContractInfoOf` (r:800 w:801) /// Proof: `Contracts::ContractInfoOf` (`max_values`: None, `max_size`: Some(1795), added: 4270, mode: `Measured`) - /// 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:802 w:802) /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `Measured`) + /// Storage: `Parameters::Parameters` (r:2 w:0) + /// Proof: `Parameters::Parameters` (`max_values`: None, `max_size`: Some(36), added: 2511, mode: `Measured`) /// Storage: `System::EventTopics` (r:801 w:801) /// Proof: `System::EventTopics` (`max_values`: None, `max_size`: None, mode: `Measured`) /// The range of component `r` is `[1, 800]`. @@ -1137,10 +1137,10 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `1097 + r * (188 ±0)` // Estimated: `6990 + r * (2664 ±0)` - // Minimum execution time: 352_925_000 picoseconds. - Weight::from_parts(355_487_000, 6990) - // Standard Error: 261_528 - .saturating_add(Weight::from_parts(337_897_187, 0).saturating_mul(r.into())) + // Minimum execution time: 341_569_000 picoseconds. + Weight::from_parts(360_574_000, 6990) + // Standard Error: 259_746 + .saturating_add(Weight::from_parts(337_944_674, 0).saturating_mul(r.into())) .saturating_add(T::DbWeight::get().reads(6_u64)) .saturating_add(T::DbWeight::get().reads((5_u64).saturating_mul(r.into()))) .saturating_add(T::DbWeight::get().writes(4_u64)) @@ -1155,10 +1155,10 @@ impl WeightInfo for SubstrateWeight { /// Proof: `Contracts::Nonce` (`max_values`: Some(1), `max_size`: Some(8), added: 503, mode: `Measured`) /// Storage: `Contracts::ContractInfoOf` (r:1 w:2) /// Proof: `Contracts::ContractInfoOf` (`max_values`: None, `max_size`: Some(1795), added: 4270, mode: `Measured`) - /// 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:3 w:3) /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `Measured`) + /// Storage: `Parameters::Parameters` (r:2 w:0) + /// Proof: `Parameters::Parameters` (`max_values`: None, `max_size`: Some(36), added: 2511, mode: `Measured`) /// Storage: `System::EventTopics` (r:2 w:2) /// Proof: `System::EventTopics` (`max_values`: None, `max_size`: None, mode: `Measured`) /// The range of component `t` is `[0, 1]`. @@ -1168,12 +1168,14 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `760 + t * (104 ±0)` // Estimated: `6719 + t * (2549 ±1)` - // Minimum execution time: 1_870_832_000 picoseconds. - Weight::from_parts(949_110_245, 6719) - // Standard Error: 24 - .saturating_add(Weight::from_parts(1_084, 0).saturating_mul(i.into())) - // Standard Error: 24 - .saturating_add(Weight::from_parts(1_206, 0).saturating_mul(s.into())) + // Minimum execution time: 1_863_119_000 picoseconds. + Weight::from_parts(900_189_174, 6719) + // Standard Error: 13_040_979 + .saturating_add(Weight::from_parts(4_056_063, 0).saturating_mul(t.into())) + // Standard Error: 20 + .saturating_add(Weight::from_parts(1_028, 0).saturating_mul(i.into())) + // Standard Error: 20 + .saturating_add(Weight::from_parts(1_173, 0).saturating_mul(s.into())) .saturating_add(T::DbWeight::get().reads(10_u64)) .saturating_add(T::DbWeight::get().reads((1_u64).saturating_mul(t.into()))) .saturating_add(T::DbWeight::get().writes(7_u64)) @@ -1185,58 +1187,58 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 9_142_000 picoseconds. - Weight::from_parts(9_787_220, 0) - // Standard Error: 236 - .saturating_add(Weight::from_parts(267_264, 0).saturating_mul(r.into())) + // Minimum execution time: 9_211_000 picoseconds. + Weight::from_parts(11_696_412, 0) + // Standard Error: 388 + .saturating_add(Weight::from_parts(265_538, 0).saturating_mul(r.into())) } /// The range of component `n` is `[0, 1048576]`. fn seal_hash_sha2_256_per_byte(n: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 10_485_000 picoseconds. - Weight::from_parts(1_870_250, 0) + // Minimum execution time: 10_296_000 picoseconds. + Weight::from_parts(572_494, 0) // Standard Error: 1 - .saturating_add(Weight::from_parts(1_073, 0).saturating_mul(n.into())) + .saturating_add(Weight::from_parts(1_067, 0).saturating_mul(n.into())) } /// The range of component `r` is `[0, 1600]`. fn seal_hash_keccak_256(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 9_005_000 picoseconds. - Weight::from_parts(8_943_937, 0) - // Standard Error: 1_385 - .saturating_add(Weight::from_parts(665_970, 0).saturating_mul(r.into())) + // Minimum execution time: 9_177_000 picoseconds. + Weight::from_parts(8_620_481, 0) + // Standard Error: 249 + .saturating_add(Weight::from_parts(674_502, 0).saturating_mul(r.into())) } /// The range of component `n` is `[0, 1048576]`. fn seal_hash_keccak_256_per_byte(n: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 10_965_000 picoseconds. - Weight::from_parts(11_749_746, 0) - // Standard Error: 6 - .saturating_add(Weight::from_parts(3_330, 0).saturating_mul(n.into())) + // Minimum execution time: 11_240_000 picoseconds. + Weight::from_parts(8_696_186, 0) + // Standard Error: 0 + .saturating_add(Weight::from_parts(3_328, 0).saturating_mul(n.into())) } /// The range of component `r` is `[0, 1600]`. fn seal_hash_blake2_256(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 10_400_000 picoseconds. - Weight::from_parts(13_857_546, 0) - // Standard Error: 246 - .saturating_add(Weight::from_parts(326_483, 0).saturating_mul(r.into())) + // Minimum execution time: 9_889_000 picoseconds. + Weight::from_parts(16_103_170, 0) + // Standard Error: 343 + .saturating_add(Weight::from_parts(328_939, 0).saturating_mul(r.into())) } /// The range of component `n` is `[0, 1048576]`. fn seal_hash_blake2_256_per_byte(n: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 10_064_000 picoseconds. - Weight::from_parts(1_885_873, 0) + // Minimum execution time: 10_405_000 picoseconds. + Weight::from_parts(2_264_024, 0) // Standard Error: 0 .saturating_add(Weight::from_parts(1_196, 0).saturating_mul(n.into())) } @@ -1245,60 +1247,60 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 9_068_000 picoseconds. - Weight::from_parts(17_169_362, 0) - // Standard Error: 1_580 - .saturating_add(Weight::from_parts(330_195, 0).saturating_mul(r.into())) + // Minimum execution time: 9_215_000 picoseconds. + Weight::from_parts(10_505_632, 0) + // Standard Error: 240 + .saturating_add(Weight::from_parts(324_854, 0).saturating_mul(r.into())) } /// The range of component `n` is `[0, 1048576]`. fn seal_hash_blake2_128_per_byte(n: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 10_169_000 picoseconds. - Weight::from_parts(2_159_277, 0) - // Standard Error: 0 - .saturating_add(Weight::from_parts(1_200, 0).saturating_mul(n.into())) + // Minimum execution time: 10_440_000 picoseconds. + Weight::from_parts(2_575_889, 0) + // Standard Error: 1 + .saturating_add(Weight::from_parts(1_199, 0).saturating_mul(n.into())) } /// The range of component `n` is `[0, 125697]`. fn seal_sr25519_verify_per_byte(n: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 53_863_000 picoseconds. - Weight::from_parts(54_902_157, 0) - // Standard Error: 9 - .saturating_add(Weight::from_parts(4_588, 0).saturating_mul(n.into())) + // Minimum execution time: 55_119_000 picoseconds. + Weight::from_parts(56_732_248, 0) + // Standard Error: 8 + .saturating_add(Weight::from_parts(4_639, 0).saturating_mul(n.into())) } /// The range of component `r` is `[0, 160]`. fn seal_sr25519_verify(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 9_107_000 picoseconds. - Weight::from_parts(24_115_247, 0) - // Standard Error: 7_427 - .saturating_add(Weight::from_parts(41_116_827, 0).saturating_mul(r.into())) + // Minimum execution time: 9_176_000 picoseconds. + Weight::from_parts(9_861_102, 0) + // Standard Error: 6_029 + .saturating_add(Weight::from_parts(45_948_571, 0).saturating_mul(r.into())) } /// The range of component `r` is `[0, 160]`. fn seal_ecdsa_recover(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 9_404_000 picoseconds. - Weight::from_parts(31_763_334, 0) - // Standard Error: 9_833 - .saturating_add(Weight::from_parts(45_529_880, 0).saturating_mul(r.into())) + // Minimum execution time: 9_293_000 picoseconds. + Weight::from_parts(28_785_765, 0) + // Standard Error: 9_160 + .saturating_add(Weight::from_parts(45_566_150, 0).saturating_mul(r.into())) } /// The range of component `r` is `[0, 160]`. fn seal_ecdsa_to_eth_address(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 11_409_000 picoseconds. - Weight::from_parts(15_072_835, 0) - // Standard Error: 4_591 - .saturating_add(Weight::from_parts(11_619_283, 0).saturating_mul(r.into())) + // Minimum execution time: 9_206_000 picoseconds. + Weight::from_parts(12_420_664, 0) + // Standard Error: 3_489 + .saturating_add(Weight::from_parts(11_628_989, 0).saturating_mul(r.into())) } /// Storage: `Contracts::CodeInfoOf` (r:1536 w:1536) /// Proof: `Contracts::CodeInfoOf` (`max_values`: None, `max_size`: Some(93), added: 2568, mode: `Measured`) @@ -1312,11 +1314,11 @@ impl WeightInfo for SubstrateWeight { fn seal_set_code_hash(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0 + r * (926 ±0)` - // Estimated: `8969 + r * (3047 ±10)` - // Minimum execution time: 9_269_000 picoseconds. - Weight::from_parts(9_372_000, 8969) - // Standard Error: 61_354 - .saturating_add(Weight::from_parts(26_280_409, 0).saturating_mul(r.into())) + // Estimated: `8969 + r * (3047 ±7)` + // Minimum execution time: 9_219_000 picoseconds. + Weight::from_parts(9_385_000, 8969) + // Standard Error: 45_562 + .saturating_add(Weight::from_parts(26_360_661, 0).saturating_mul(r.into())) .saturating_add(T::DbWeight::get().reads((3_u64).saturating_mul(r.into()))) .saturating_add(T::DbWeight::get().writes((2_u64).saturating_mul(r.into()))) .saturating_add(Weight::from_parts(0, 3047).saturating_mul(r.into())) @@ -1328,10 +1330,10 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `274 + r * (78 ±0)` // Estimated: `1265 + r * (2553 ±0)` - // Minimum execution time: 9_103_000 picoseconds. - Weight::from_parts(14_404_626, 1265) - // Standard Error: 9_343 - .saturating_add(Weight::from_parts(5_154_949, 0).saturating_mul(r.into())) + // Minimum execution time: 9_355_000 picoseconds. + Weight::from_parts(15_071_309, 1265) + // Standard Error: 9_722 + .saturating_add(Weight::from_parts(5_328_717, 0).saturating_mul(r.into())) .saturating_add(T::DbWeight::get().reads((1_u64).saturating_mul(r.into()))) .saturating_add(T::DbWeight::get().writes((1_u64).saturating_mul(r.into()))) .saturating_add(Weight::from_parts(0, 2553).saturating_mul(r.into())) @@ -1343,10 +1345,10 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `275 + r * (78 ±0)` // Estimated: `990 + r * (2568 ±0)` - // Minimum execution time: 9_219_000 picoseconds. - Weight::from_parts(14_085_456, 990) - // Standard Error: 11_206 - .saturating_add(Weight::from_parts(4_422_122, 0).saturating_mul(r.into())) + // Minimum execution time: 8_979_000 picoseconds. + Weight::from_parts(14_362_224, 990) + // Standard Error: 9_137 + .saturating_add(Weight::from_parts(4_488_748, 0).saturating_mul(r.into())) .saturating_add(T::DbWeight::get().reads((1_u64).saturating_mul(r.into()))) .saturating_add(T::DbWeight::get().writes((1_u64).saturating_mul(r.into()))) .saturating_add(Weight::from_parts(0, 2568).saturating_mul(r.into())) @@ -1372,10 +1374,10 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `861 + r * (3 ±0)` // Estimated: `9282 + r * (3 ±0)` - // Minimum execution time: 269_333_000 picoseconds. - Weight::from_parts(286_922_618, 9282) - // Standard Error: 443 - .saturating_add(Weight::from_parts(168_869, 0).saturating_mul(r.into())) + // Minimum execution time: 269_704_000 picoseconds. + Weight::from_parts(289_916_035, 9282) + // Standard Error: 408 + .saturating_add(Weight::from_parts(166_040, 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())) @@ -1385,10 +1387,10 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 9_328_000 picoseconds. - Weight::from_parts(14_019_583, 0) - // Standard Error: 171 - .saturating_add(Weight::from_parts(88_751, 0).saturating_mul(r.into())) + // Minimum execution time: 9_361_000 picoseconds. + Weight::from_parts(11_633_836, 0) + // Standard Error: 86 + .saturating_add(Weight::from_parts(83_083, 0).saturating_mul(r.into())) } /// Storage: `Contracts::Nonce` (r:1 w:0) /// Proof: `Contracts::Nonce` (`max_values`: Some(1), `max_size`: Some(8), added: 503, mode: `Measured`) @@ -1397,10 +1399,10 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `219` // Estimated: `1704` - // Minimum execution time: 9_267_000 picoseconds. - Weight::from_parts(15_304_284, 1704) - // Standard Error: 1_219 - .saturating_add(Weight::from_parts(74_696, 0).saturating_mul(r.into())) + // Minimum execution time: 9_133_000 picoseconds. + Weight::from_parts(13_259_836, 1704) + // Standard Error: 121 + .saturating_add(Weight::from_parts(76_878, 0).saturating_mul(r.into())) .saturating_add(T::DbWeight::get().reads(1_u64)) } /// The range of component `r` is `[0, 5000]`. @@ -1408,10 +1410,10 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 911_000 picoseconds. - Weight::from_parts(449_666, 0) - // Standard Error: 26 - .saturating_add(Weight::from_parts(14_797, 0).saturating_mul(r.into())) + // Minimum execution time: 851_000 picoseconds. + Weight::from_parts(587_883, 0) + // Standard Error: 16 + .saturating_add(Weight::from_parts(14_912, 0).saturating_mul(r.into())) } } @@ -1423,8 +1425,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `142` // Estimated: `1627` - // Minimum execution time: 2_047_000 picoseconds. - Weight::from_parts(2_116_000, 1627) + // Minimum execution time: 2_149_000 picoseconds. + Weight::from_parts(2_274_000, 1627) .saturating_add(RocksDbWeight::get().reads(1_u64)) } /// Storage: `Skipped::Metadata` (r:0 w:0) @@ -1434,10 +1436,10 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `452 + k * (69 ±0)` // Estimated: `442 + k * (70 ±0)` - // Minimum execution time: 12_474_000 picoseconds. - Weight::from_parts(12_767_000, 442) - // Standard Error: 1_081 - .saturating_add(Weight::from_parts(1_187_278, 0).saturating_mul(k.into())) + // Minimum execution time: 12_863_000 picoseconds. + Weight::from_parts(13_188_000, 442) + // Standard Error: 1_053 + .saturating_add(Weight::from_parts(1_105_325, 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)) @@ -1451,10 +1453,10 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `211 + c * (1 ±0)` // Estimated: `6149 + c * (1 ±0)` - // Minimum execution time: 8_307_000 picoseconds. - Weight::from_parts(8_939_322, 6149) + // Minimum execution time: 8_432_000 picoseconds. + Weight::from_parts(9_203_290, 6149) // Standard Error: 1 - .saturating_add(Weight::from_parts(1_190, 0).saturating_mul(c.into())) + .saturating_add(Weight::from_parts(1_186, 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())) @@ -1467,8 +1469,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `510` // Estimated: `6450` - // Minimum execution time: 16_915_000 picoseconds. - Weight::from_parts(17_638_000, 6450) + // Minimum execution time: 17_177_000 picoseconds. + Weight::from_parts(17_663_000, 6450) .saturating_add(RocksDbWeight::get().reads(3_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -1481,10 +1483,10 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `171 + k * (1 ±0)` // Estimated: `3635 + k * (1 ±0)` - // Minimum execution time: 3_607_000 picoseconds. - Weight::from_parts(1_979_323, 3635) - // Standard Error: 1_018 - .saturating_add(Weight::from_parts(1_196_162, 0).saturating_mul(k.into())) + // Minimum execution time: 3_636_000 picoseconds. + Weight::from_parts(3_774_000, 3635) + // Standard Error: 542 + .saturating_add(Weight::from_parts(1_260_058, 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()))) @@ -1505,10 +1507,10 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `328 + c * (1 ±0)` // Estimated: `6266 + c * (1 ±0)` - // Minimum execution time: 21_056_000 picoseconds. - Weight::from_parts(21_633_895, 6266) + // Minimum execution time: 21_585_000 picoseconds. + Weight::from_parts(22_069_944, 6266) // Standard Error: 1 - .saturating_add(Weight::from_parts(390, 0).saturating_mul(c.into())) + .saturating_add(Weight::from_parts(404, 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())) @@ -1519,8 +1521,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `440` // Estimated: `6380` - // Minimum execution time: 12_860_000 picoseconds. - Weight::from_parts(13_525_000, 6380) + // Minimum execution time: 13_283_000 picoseconds. + Weight::from_parts(14_015_000, 6380) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -1534,8 +1536,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `352` // Estimated: `6292` - // Minimum execution time: 46_926_000 picoseconds. - Weight::from_parts(47_828_000, 6292) + // Minimum execution time: 48_022_000 picoseconds. + Weight::from_parts(49_627_000, 6292) .saturating_add(RocksDbWeight::get().reads(4_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -1547,8 +1549,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `594` // Estimated: `6534` - // Minimum execution time: 55_081_000 picoseconds. - Weight::from_parts(56_899_000, 6534) + // Minimum execution time: 58_374_000 picoseconds. + Weight::from_parts(59_615_000, 6534) .saturating_add(RocksDbWeight::get().reads(4_u64)) .saturating_add(RocksDbWeight::get().writes(2_u64)) } @@ -1558,8 +1560,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `409` // Estimated: `6349` - // Minimum execution time: 12_595_000 picoseconds. - Weight::from_parts(13_059_000, 6349) + // Minimum execution time: 12_559_000 picoseconds. + Weight::from_parts(12_947_000, 6349) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -1570,7 +1572,7 @@ impl WeightInfo for () { // Measured: `142` // Estimated: `1627` // Minimum execution time: 2_480_000 picoseconds. - Weight::from_parts(2_663_000, 1627) + Weight::from_parts(2_680_000, 1627) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -1582,8 +1584,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `166` // Estimated: `3631` - // Minimum execution time: 12_115_000 picoseconds. - Weight::from_parts(12_506_000, 3631) + // Minimum execution time: 12_625_000 picoseconds. + Weight::from_parts(13_094_000, 3631) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(2_u64)) } @@ -1593,8 +1595,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `142` // Estimated: `3607` - // Minimum execution time: 4_757_000 picoseconds. - Weight::from_parts(5_082_000, 3607) + // Minimum execution time: 4_836_000 picoseconds. + Weight::from_parts(5_182_000, 3607) .saturating_add(RocksDbWeight::get().reads(1_u64)) } /// Storage: UNKNOWN KEY `0x4342193e496fab7ec59d615ed0dc55304e7b9012096b41c4eb3aaf947f6ea429` (r:1 w:0) @@ -1605,8 +1607,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `167` // Estimated: `3632` - // Minimum execution time: 6_017_000 picoseconds. - Weight::from_parts(6_421_000, 3632) + // Minimum execution time: 6_319_000 picoseconds. + Weight::from_parts(6_582_000, 3632) .saturating_add(RocksDbWeight::get().reads(2_u64)) } /// Storage: UNKNOWN KEY `0x4342193e496fab7ec59d615ed0dc55304e7b9012096b41c4eb3aaf947f6ea429` (r:1 w:0) @@ -1617,8 +1619,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `142` // Estimated: `3607` - // Minimum execution time: 6_238_000 picoseconds. - Weight::from_parts(6_587_000, 3607) + // Minimum execution time: 6_532_000 picoseconds. + Weight::from_parts(6_909_000, 3607) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -1643,10 +1645,10 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `804 + c * (1 ±0)` // Estimated: `9217 + c * (1 ±0)` - // Minimum execution time: 288_968_000 picoseconds. - Weight::from_parts(267_291_922, 9217) - // Standard Error: 78 - .saturating_add(Weight::from_parts(34_879, 0).saturating_mul(c.into())) + // Minimum execution time: 305_778_000 picoseconds. + Weight::from_parts(282_321_249, 9217) + // Standard Error: 72 + .saturating_add(Weight::from_parts(33_456, 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())) @@ -1678,14 +1680,14 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `326` // Estimated: `8740` - // Minimum execution time: 3_948_426_000 picoseconds. - Weight::from_parts(440_017_623, 8740) - // Standard Error: 555 - .saturating_add(Weight::from_parts(71_483, 0).saturating_mul(c.into())) - // Standard Error: 66 - .saturating_add(Weight::from_parts(1_831, 0).saturating_mul(i.into())) - // Standard Error: 66 - .saturating_add(Weight::from_parts(1_694, 0).saturating_mul(s.into())) + // Minimum execution time: 3_810_809_000 picoseconds. + Weight::from_parts(739_511_598, 8740) + // Standard Error: 140 + .saturating_add(Weight::from_parts(67_574, 0).saturating_mul(c.into())) + // Standard Error: 16 + .saturating_add(Weight::from_parts(1_488, 0).saturating_mul(i.into())) + // Standard Error: 16 + .saturating_add(Weight::from_parts(1_537, 0).saturating_mul(s.into())) .saturating_add(RocksDbWeight::get().reads(14_u64)) .saturating_add(RocksDbWeight::get().writes(10_u64)) } @@ -1715,12 +1717,12 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `563` // Estimated: `8982` - // Minimum execution time: 2_011_037_000 picoseconds. - Weight::from_parts(2_047_025_000, 8982) - // Standard Error: 28 - .saturating_add(Weight::from_parts(968, 0).saturating_mul(i.into())) - // Standard Error: 28 - .saturating_add(Weight::from_parts(780, 0).saturating_mul(s.into())) + // Minimum execution time: 1_986_789_000 picoseconds. + Weight::from_parts(2_017_466_000, 8982) + // Standard Error: 26 + .saturating_add(Weight::from_parts(827, 0).saturating_mul(i.into())) + // Standard Error: 26 + .saturating_add(Weight::from_parts(781, 0).saturating_mul(s.into())) .saturating_add(RocksDbWeight::get().reads(13_u64)) .saturating_add(RocksDbWeight::get().writes(7_u64)) } @@ -1744,8 +1746,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `829` // Estimated: `9244` - // Minimum execution time: 202_190_000 picoseconds. - Weight::from_parts(209_378_000, 9244) + // Minimum execution time: 210_724_000 picoseconds. + Weight::from_parts(218_608_000, 9244) .saturating_add(RocksDbWeight::get().reads(11_u64)) .saturating_add(RocksDbWeight::get().writes(4_u64)) } @@ -1766,10 +1768,10 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `145` // Estimated: `6085` - // Minimum execution time: 271_161_000 picoseconds. - Weight::from_parts(279_218_977, 6085) - // Standard Error: 80 - .saturating_add(Weight::from_parts(33_973, 0).saturating_mul(c.into())) + // Minimum execution time: 271_259_000 picoseconds. + Weight::from_parts(298_852_854, 6085) + // Standard Error: 65 + .saturating_add(Weight::from_parts(33_547, 0).saturating_mul(c.into())) .saturating_add(RocksDbWeight::get().reads(6_u64)) .saturating_add(RocksDbWeight::get().writes(4_u64)) } @@ -1790,10 +1792,10 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `145` // Estimated: `6085` - // Minimum execution time: 273_684_000 picoseconds. - Weight::from_parts(284_348_722, 6085) - // Standard Error: 79 - .saturating_add(Weight::from_parts(34_205, 0).saturating_mul(c.into())) + // Minimum execution time: 278_167_000 picoseconds. + Weight::from_parts(311_888_941, 6085) + // Standard Error: 58 + .saturating_add(Weight::from_parts(33_595, 0).saturating_mul(c.into())) .saturating_add(RocksDbWeight::get().reads(6_u64)) .saturating_add(RocksDbWeight::get().writes(4_u64)) } @@ -1811,8 +1813,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `315` // Estimated: `3780` - // Minimum execution time: 45_150_000 picoseconds. - Weight::from_parts(46_780_000, 3780) + // Minimum execution time: 47_403_000 picoseconds. + Weight::from_parts(48_707_000, 3780) .saturating_add(RocksDbWeight::get().reads(4_u64)) .saturating_add(RocksDbWeight::get().writes(4_u64)) } @@ -1828,8 +1830,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `552` // Estimated: `8967` - // Minimum execution time: 34_738_000 picoseconds. - Weight::from_parts(35_918_000, 8967) + // Minimum execution time: 35_361_000 picoseconds. + Weight::from_parts(36_714_000, 8967) .saturating_add(RocksDbWeight::get().reads(7_u64)) .saturating_add(RocksDbWeight::get().writes(6_u64)) } @@ -1838,10 +1840,10 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 9_094_000 picoseconds. - Weight::from_parts(10_253_702, 0) - // Standard Error: 223 - .saturating_add(Weight::from_parts(250_757, 0).saturating_mul(r.into())) + // Minimum execution time: 9_340_000 picoseconds. + Weight::from_parts(9_360_237, 0) + // Standard Error: 269 + .saturating_add(Weight::from_parts(249_611, 0).saturating_mul(r.into())) } /// Storage: `Contracts::ContractInfoOf` (r:1600 w:0) /// Proof: `Contracts::ContractInfoOf` (`max_values`: None, `max_size`: Some(1795), added: 4270, mode: `Measured`) @@ -1850,10 +1852,10 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `509 + r * (77 ±0)` // Estimated: `1467 + r * (2552 ±0)` - // Minimum execution time: 9_102_000 picoseconds. - Weight::from_parts(9_238_000, 1467) - // Standard Error: 6_076 - .saturating_add(Weight::from_parts(3_293_012, 0).saturating_mul(r.into())) + // Minimum execution time: 9_059_000 picoseconds. + Weight::from_parts(9_201_000, 1467) + // Standard Error: 5_643 + .saturating_add(Weight::from_parts(3_343_859, 0).saturating_mul(r.into())) .saturating_add(RocksDbWeight::get().reads((1_u64).saturating_mul(r.into()))) .saturating_add(Weight::from_parts(0, 2552).saturating_mul(r.into())) } @@ -1864,10 +1866,10 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `517 + r * (170 ±0)` // Estimated: `1468 + r * (2645 ±0)` - // Minimum execution time: 9_255_000 picoseconds. - Weight::from_parts(9_406_000, 1468) - // Standard Error: 6_826 - .saturating_add(Weight::from_parts(4_205_039, 0).saturating_mul(r.into())) + // Minimum execution time: 9_220_000 picoseconds. + Weight::from_parts(9_399_000, 1468) + // Standard Error: 6_194 + .saturating_add(Weight::from_parts(4_172_011, 0).saturating_mul(r.into())) .saturating_add(RocksDbWeight::get().reads((1_u64).saturating_mul(r.into()))) .saturating_add(Weight::from_parts(0, 2645).saturating_mul(r.into())) } @@ -1876,50 +1878,50 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 9_388_000 picoseconds. - Weight::from_parts(9_322_209, 0) - // Standard Error: 269 - .saturating_add(Weight::from_parts(358_189, 0).saturating_mul(r.into())) + // Minimum execution time: 9_707_000 picoseconds. + Weight::from_parts(10_100_456, 0) + // Standard Error: 234 + .saturating_add(Weight::from_parts(338_464, 0).saturating_mul(r.into())) } /// The range of component `r` is `[0, 1600]`. fn seal_caller_is_origin(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 9_300_000 picoseconds. - Weight::from_parts(10_268_326, 0) - // Standard Error: 72 - .saturating_add(Weight::from_parts(104_650, 0).saturating_mul(r.into())) + // Minimum execution time: 9_524_000 picoseconds. + Weight::from_parts(10_813_389, 0) + // Standard Error: 76 + .saturating_add(Weight::from_parts(102_535, 0).saturating_mul(r.into())) } /// The range of component `r` is `[0, 1600]`. fn seal_caller_is_root(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 9_162_000 picoseconds. - Weight::from_parts(10_059_984, 0) - // Standard Error: 87 - .saturating_add(Weight::from_parts(87_627, 0).saturating_mul(r.into())) + // Minimum execution time: 9_799_000 picoseconds. + Weight::from_parts(10_886_744, 0) + // Standard Error: 75 + .saturating_add(Weight::from_parts(80_901, 0).saturating_mul(r.into())) } /// The range of component `r` is `[0, 1600]`. fn seal_address(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 9_193_000 picoseconds. - Weight::from_parts(10_160_715, 0) - // Standard Error: 152 - .saturating_add(Weight::from_parts(263_703, 0).saturating_mul(r.into())) + // Minimum execution time: 9_895_000 picoseconds. + Weight::from_parts(10_658_338, 0) + // Standard Error: 189 + .saturating_add(Weight::from_parts(249_694, 0).saturating_mul(r.into())) } /// The range of component `r` is `[0, 1600]`. fn seal_gas_left(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 9_109_000 picoseconds. - Weight::from_parts(9_766_924, 0) - // Standard Error: 212 - .saturating_add(Weight::from_parts(291_694, 0).saturating_mul(r.into())) + // Minimum execution time: 9_643_000 picoseconds. + Weight::from_parts(10_932_126, 0) + // Standard Error: 153 + .saturating_add(Weight::from_parts(280_924, 0).saturating_mul(r.into())) } /// Storage: `System::Account` (r:1 w:0) /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `Measured`) @@ -1928,10 +1930,10 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `140` // Estimated: `3599` - // Minimum execution time: 9_463_000 picoseconds. - Weight::from_parts(9_541_000, 3599) - // Standard Error: 3_075 - .saturating_add(Weight::from_parts(1_606_043, 0).saturating_mul(r.into())) + // Minimum execution time: 9_548_000 picoseconds. + Weight::from_parts(9_737_000, 3599) + // Standard Error: 971 + .saturating_add(Weight::from_parts(1_704_134, 0).saturating_mul(r.into())) .saturating_add(RocksDbWeight::get().reads(1_u64)) } /// The range of component `r` is `[0, 1600]`. @@ -1939,40 +1941,40 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 9_080_000 picoseconds. - Weight::from_parts(8_121_924, 0) - // Standard Error: 198 - .saturating_add(Weight::from_parts(247_527, 0).saturating_mul(r.into())) + // Minimum execution time: 9_172_000 picoseconds. + Weight::from_parts(18_255_933, 0) + // Standard Error: 540 + .saturating_add(Weight::from_parts(230_929, 0).saturating_mul(r.into())) } /// The range of component `r` is `[0, 1600]`. fn seal_minimum_balance(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 9_393_000 picoseconds. - Weight::from_parts(9_999_247, 0) - // Standard Error: 169 - .saturating_add(Weight::from_parts(244_563, 0).saturating_mul(r.into())) + // Minimum execution time: 9_232_000 picoseconds. + Weight::from_parts(9_796_584, 0) + // Standard Error: 208 + .saturating_add(Weight::from_parts(239_962, 0).saturating_mul(r.into())) } /// The range of component `r` is `[0, 1600]`. fn seal_block_number(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 9_236_000 picoseconds. - Weight::from_parts(9_561_435, 0) - // Standard Error: 195 - .saturating_add(Weight::from_parts(239_812, 0).saturating_mul(r.into())) + // Minimum execution time: 9_747_000 picoseconds. + Weight::from_parts(8_733_230, 0) + // Standard Error: 377 + .saturating_add(Weight::from_parts(253_801, 0).saturating_mul(r.into())) } /// The range of component `r` is `[0, 1600]`. fn seal_now(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 9_259_000 picoseconds. - Weight::from_parts(10_353_960, 0) - // Standard Error: 216 - .saturating_add(Weight::from_parts(243_754, 0).saturating_mul(r.into())) + // Minimum execution time: 9_214_000 picoseconds. + Weight::from_parts(10_194_153, 0) + // Standard Error: 516 + .saturating_add(Weight::from_parts(247_621, 0).saturating_mul(r.into())) } /// Storage: `TransactionPayment::NextFeeMultiplier` (r:1 w:0) /// Proof: `TransactionPayment::NextFeeMultiplier` (`max_values`: Some(1), `max_size`: Some(16), added: 511, mode: `Measured`) @@ -1981,10 +1983,10 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `67` // Estimated: `1552` - // Minimum execution time: 9_145_000 picoseconds. - Weight::from_parts(16_524_937, 1552) - // Standard Error: 438 - .saturating_add(Weight::from_parts(666_821, 0).saturating_mul(r.into())) + // Minimum execution time: 9_022_000 picoseconds. + Weight::from_parts(22_051_160, 1552) + // Standard Error: 697 + .saturating_add(Weight::from_parts(709_612, 0).saturating_mul(r.into())) .saturating_add(RocksDbWeight::get().reads(1_u64)) } /// The range of component `r` is `[0, 1600]`. @@ -1992,10 +1994,10 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 9_179_000 picoseconds. - Weight::from_parts(8_893_261, 0) - // Standard Error: 215 - .saturating_add(Weight::from_parts(175_586, 0).saturating_mul(r.into())) + // Minimum execution time: 9_135_000 picoseconds. + Weight::from_parts(10_646_215, 0) + // Standard Error: 161 + .saturating_add(Weight::from_parts(170_336, 0).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`) @@ -2018,10 +2020,10 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `872` // Estimated: `9287` - // Minimum execution time: 259_315_000 picoseconds. - Weight::from_parts(137_461_362, 9287) - // Standard Error: 18 - .saturating_add(Weight::from_parts(1_388, 0).saturating_mul(n.into())) + // Minimum execution time: 273_896_000 picoseconds. + Weight::from_parts(148_309_654, 9287) + // Standard Error: 16 + .saturating_add(Weight::from_parts(1_355, 0).saturating_mul(n.into())) .saturating_add(RocksDbWeight::get().reads(11_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) } @@ -2030,20 +2032,20 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 8_919_000 picoseconds. - Weight::from_parts(9_465_187, 0) - // Standard Error: 32_481 - .saturating_add(Weight::from_parts(992_912, 0).saturating_mul(r.into())) + // Minimum execution time: 8_906_000 picoseconds. + Weight::from_parts(9_264_446, 0) + // Standard Error: 19_760 + .saturating_add(Weight::from_parts(1_256_053, 0).saturating_mul(r.into())) } /// The range of component `n` is `[0, 1048576]`. fn seal_return_per_byte(n: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 10_244_000 picoseconds. - Weight::from_parts(10_654_989, 0) + // Minimum execution time: 10_266_000 picoseconds. + Weight::from_parts(10_602_261, 0) // Standard Error: 0 - .saturating_add(Weight::from_parts(315, 0).saturating_mul(n.into())) + .saturating_add(Weight::from_parts(318, 0).saturating_mul(n.into())) } /// Storage: `Contracts::MigrationInProgress` (r:1 w:0) /// Proof: `Contracts::MigrationInProgress` (`max_values`: Some(1), `max_size`: Some(1026), added: 1521, mode: `Measured`) @@ -2072,10 +2074,10 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `4805 + r * (2121 ±0)` // Estimated: `13220 + r * (81321 ±0)` - // Minimum execution time: 303_028_000 picoseconds. - Weight::from_parts(323_032_397, 13220) - // Standard Error: 848_406 - .saturating_add(Weight::from_parts(242_988_002, 0).saturating_mul(r.into())) + // Minimum execution time: 295_922_000 picoseconds. + Weight::from_parts(322_472_877, 13220) + // Standard Error: 993_812 + .saturating_add(Weight::from_parts(259_075_422, 0).saturating_mul(r.into())) .saturating_add(RocksDbWeight::get().reads(11_u64)) .saturating_add(RocksDbWeight::get().reads((36_u64).saturating_mul(r.into()))) .saturating_add(RocksDbWeight::get().writes(3_u64)) @@ -2089,10 +2091,10 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `76` // Estimated: `1561` - // Minimum execution time: 9_227_000 picoseconds. - Weight::from_parts(14_055_283, 1561) - // Standard Error: 758 - .saturating_add(Weight::from_parts(1_104_996, 0).saturating_mul(r.into())) + // Minimum execution time: 9_427_000 picoseconds. + Weight::from_parts(12_996_213, 1561) + // Standard Error: 845 + .saturating_add(Weight::from_parts(1_182_642, 0).saturating_mul(r.into())) .saturating_add(RocksDbWeight::get().reads(1_u64)) } /// The range of component `r` is `[0, 1600]`. @@ -2100,10 +2102,10 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 9_483_000 picoseconds. - Weight::from_parts(20_453_059, 0) - // Standard Error: 3_271 - .saturating_add(Weight::from_parts(1_713_468, 0).saturating_mul(r.into())) + // Minimum execution time: 9_304_000 picoseconds. + Weight::from_parts(25_678_842, 0) + // Standard Error: 1_855 + .saturating_add(Weight::from_parts(1_814_511, 0).saturating_mul(r.into())) } /// Storage: `System::EventTopics` (r:4 w:4) /// Proof: `System::EventTopics` (`max_values`: None, `max_size`: None, mode: `Measured`) @@ -2113,12 +2115,12 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `0` // Estimated: `990 + t * (2475 ±0)` - // Minimum execution time: 23_517_000 picoseconds. - Weight::from_parts(15_543_153, 990) - // Standard Error: 13_814 - .saturating_add(Weight::from_parts(2_357_255, 0).saturating_mul(t.into())) - // Standard Error: 3 - .saturating_add(Weight::from_parts(573, 0).saturating_mul(n.into())) + // Minimum execution time: 23_425_000 picoseconds. + Weight::from_parts(15_229_010, 990) + // Standard Error: 14_380 + .saturating_add(Weight::from_parts(2_545_653, 0).saturating_mul(t.into())) + // Standard Error: 4 + .saturating_add(Weight::from_parts(594, 0).saturating_mul(n.into())) .saturating_add(RocksDbWeight::get().reads((1_u64).saturating_mul(t.into()))) .saturating_add(RocksDbWeight::get().writes((1_u64).saturating_mul(t.into()))) .saturating_add(Weight::from_parts(0, 2475).saturating_mul(t.into())) @@ -2128,20 +2130,20 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 8_448_000 picoseconds. - Weight::from_parts(9_845_841, 0) - // Standard Error: 58 - .saturating_add(Weight::from_parts(105_442, 0).saturating_mul(r.into())) + // Minimum execution time: 11_117_000 picoseconds. + Weight::from_parts(12_887_533, 0) + // Standard Error: 83 + .saturating_add(Weight::from_parts(99_373, 0).saturating_mul(r.into())) } /// The range of component `i` is `[0, 1048576]`. fn seal_debug_message_per_byte(i: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 10_869_000 picoseconds. - Weight::from_parts(11_024_000, 0) + // Minimum execution time: 10_982_000 picoseconds. + Weight::from_parts(11_176_000, 0) // Standard Error: 8 - .saturating_add(Weight::from_parts(991, 0).saturating_mul(i.into())) + .saturating_add(Weight::from_parts(983, 0).saturating_mul(i.into())) } /// Storage: `Skipped::Metadata` (r:0 w:0) /// Proof: `Skipped::Metadata` (`max_values`: None, `max_size`: None, mode: `Measured`) @@ -2150,10 +2152,10 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `108 + r * (150 ±0)` // Estimated: `105 + r * (151 ±0)` - // Minimum execution time: 9_119_000 picoseconds. - Weight::from_parts(9_270_000, 105) - // Standard Error: 8_960 - .saturating_add(Weight::from_parts(5_215_976, 0).saturating_mul(r.into())) + // Minimum execution time: 9_150_000 picoseconds. + Weight::from_parts(9_269_000, 105) + // Standard Error: 8_147 + .saturating_add(Weight::from_parts(5_339_554, 0).saturating_mul(r.into())) .saturating_add(RocksDbWeight::get().reads((1_u64).saturating_mul(r.into()))) .saturating_add(RocksDbWeight::get().writes((1_u64).saturating_mul(r.into()))) .saturating_add(Weight::from_parts(0, 151).saturating_mul(r.into())) @@ -2165,10 +2167,10 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `245` // Estimated: `245` - // Minimum execution time: 17_833_000 picoseconds. - Weight::from_parts(18_940_114, 245) - // Standard Error: 2 - .saturating_add(Weight::from_parts(316, 0).saturating_mul(n.into())) + // Minimum execution time: 19_085_000 picoseconds. + Weight::from_parts(20_007_323, 245) + // Standard Error: 3 + .saturating_add(Weight::from_parts(291, 0).saturating_mul(n.into())) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -2179,10 +2181,10 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `248 + n * (1 ±0)` // Estimated: `248 + n * (1 ±0)` - // Minimum execution time: 18_428_000 picoseconds. - Weight::from_parts(19_372_726, 248) - // Standard Error: 2 - .saturating_add(Weight::from_parts(85, 0).saturating_mul(n.into())) + // Minimum execution time: 19_127_000 picoseconds. + Weight::from_parts(21_152_987, 248) + // Standard Error: 3 + .saturating_add(Weight::from_parts(42, 0).saturating_mul(n.into())) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) .saturating_add(Weight::from_parts(0, 1).saturating_mul(n.into())) @@ -2194,10 +2196,10 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `108 + r * (150 ±0)` // Estimated: `105 + r * (151 ±0)` - // Minimum execution time: 9_335_000 picoseconds. - Weight::from_parts(9_459_000, 105) - // Standard Error: 9_156 - .saturating_add(Weight::from_parts(5_166_621, 0).saturating_mul(r.into())) + // Minimum execution time: 9_264_000 picoseconds. + Weight::from_parts(9_449_000, 105) + // Standard Error: 8_196 + .saturating_add(Weight::from_parts(5_325_578, 0).saturating_mul(r.into())) .saturating_add(RocksDbWeight::get().reads((1_u64).saturating_mul(r.into()))) .saturating_add(RocksDbWeight::get().writes((1_u64).saturating_mul(r.into()))) .saturating_add(Weight::from_parts(0, 151).saturating_mul(r.into())) @@ -2209,10 +2211,10 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `248 + n * (1 ±0)` // Estimated: `248 + n * (1 ±0)` - // Minimum execution time: 18_308_000 picoseconds. - Weight::from_parts(19_421_433, 248) + // Minimum execution time: 18_489_000 picoseconds. + Weight::from_parts(19_916_153, 248) // Standard Error: 2 - .saturating_add(Weight::from_parts(83, 0).saturating_mul(n.into())) + .saturating_add(Weight::from_parts(97, 0).saturating_mul(n.into())) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) .saturating_add(Weight::from_parts(0, 1).saturating_mul(n.into())) @@ -2224,10 +2226,10 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `108 + r * (150 ±0)` // Estimated: `105 + r * (151 ±0)` - // Minimum execution time: 9_184_000 picoseconds. - Weight::from_parts(9_245_000, 105) - // Standard Error: 8_442 - .saturating_add(Weight::from_parts(4_543_991, 0).saturating_mul(r.into())) + // Minimum execution time: 9_299_000 picoseconds. + Weight::from_parts(9_464_000, 105) + // Standard Error: 6_827 + .saturating_add(Weight::from_parts(4_720_699, 0).saturating_mul(r.into())) .saturating_add(RocksDbWeight::get().reads((1_u64).saturating_mul(r.into()))) .saturating_add(Weight::from_parts(0, 151).saturating_mul(r.into())) } @@ -2238,10 +2240,10 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `248 + n * (1 ±0)` // Estimated: `248 + n * (1 ±0)` - // Minimum execution time: 17_194_000 picoseconds. - Weight::from_parts(19_032_094, 248) + // Minimum execution time: 17_981_000 picoseconds. + Weight::from_parts(19_802_353, 248) // Standard Error: 3 - .saturating_add(Weight::from_parts(590, 0).saturating_mul(n.into())) + .saturating_add(Weight::from_parts(617, 0).saturating_mul(n.into())) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(Weight::from_parts(0, 1).saturating_mul(n.into())) } @@ -2252,10 +2254,10 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `108 + r * (150 ±0)` // Estimated: `105 + r * (151 ±0)` - // Minimum execution time: 9_380_000 picoseconds. - Weight::from_parts(9_501_000, 105) - // Standard Error: 7_029 - .saturating_add(Weight::from_parts(4_406_690, 0).saturating_mul(r.into())) + // Minimum execution time: 9_891_000 picoseconds. + Weight::from_parts(10_046_000, 105) + // Standard Error: 6_993 + .saturating_add(Weight::from_parts(4_601_167, 0).saturating_mul(r.into())) .saturating_add(RocksDbWeight::get().reads((1_u64).saturating_mul(r.into()))) .saturating_add(Weight::from_parts(0, 151).saturating_mul(r.into())) } @@ -2266,10 +2268,10 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `248 + n * (1 ±0)` // Estimated: `248 + n * (1 ±0)` - // Minimum execution time: 16_400_000 picoseconds. - Weight::from_parts(17_993_941, 248) + // Minimum execution time: 17_229_000 picoseconds. + Weight::from_parts(18_302_733, 248) // Standard Error: 2 - .saturating_add(Weight::from_parts(68, 0).saturating_mul(n.into())) + .saturating_add(Weight::from_parts(112, 0).saturating_mul(n.into())) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(Weight::from_parts(0, 1).saturating_mul(n.into())) } @@ -2280,10 +2282,10 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `108 + r * (150 ±0)` // Estimated: `105 + r * (151 ±0)` - // Minimum execution time: 9_109_000 picoseconds. - Weight::from_parts(9_265_000, 105) - // Standard Error: 8_733 - .saturating_add(Weight::from_parts(5_218_811, 0).saturating_mul(r.into())) + // Minimum execution time: 9_323_000 picoseconds. + Weight::from_parts(9_462_000, 105) + // Standard Error: 8_031 + .saturating_add(Weight::from_parts(5_433_981, 0).saturating_mul(r.into())) .saturating_add(RocksDbWeight::get().reads((1_u64).saturating_mul(r.into()))) .saturating_add(RocksDbWeight::get().writes((1_u64).saturating_mul(r.into()))) .saturating_add(Weight::from_parts(0, 151).saturating_mul(r.into())) @@ -2295,10 +2297,10 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `248 + n * (1 ±0)` // Estimated: `248 + n * (1 ±0)` - // Minimum execution time: 18_423_000 picoseconds. - Weight::from_parts(20_025_132, 248) + // Minimum execution time: 18_711_000 picoseconds. + Weight::from_parts(20_495_670, 248) // Standard Error: 3 - .saturating_add(Weight::from_parts(628, 0).saturating_mul(n.into())) + .saturating_add(Weight::from_parts(640, 0).saturating_mul(n.into())) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) .saturating_add(Weight::from_parts(0, 1).saturating_mul(n.into())) @@ -2310,10 +2312,10 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `770` // Estimated: `4221 + r * (2475 ±0)` - // Minimum execution time: 9_043_000 picoseconds. - Weight::from_parts(9_176_000, 4221) - // Standard Error: 12_901 - .saturating_add(Weight::from_parts(32_297_438, 0).saturating_mul(r.into())) + // Minimum execution time: 9_226_000 picoseconds. + Weight::from_parts(9_394_000, 4221) + // Standard Error: 14_741 + .saturating_add(Weight::from_parts(34_179_316, 0).saturating_mul(r.into())) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().reads((1_u64).saturating_mul(r.into()))) .saturating_add(RocksDbWeight::get().writes(1_u64)) @@ -2335,10 +2337,10 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `520 + r * (170 ±0)` // Estimated: `6463 + r * (2646 ±0)` - // Minimum execution time: 9_299_000 picoseconds. - Weight::from_parts(9_427_000, 6463) - // Standard Error: 101_949 - .saturating_add(Weight::from_parts(244_143_691, 0).saturating_mul(r.into())) + // Minimum execution time: 9_455_000 picoseconds. + Weight::from_parts(9_671_000, 6463) + // Standard Error: 126_080 + .saturating_add(Weight::from_parts(244_204_040, 0).saturating_mul(r.into())) .saturating_add(RocksDbWeight::get().reads(5_u64)) .saturating_add(RocksDbWeight::get().reads((2_u64).saturating_mul(r.into()))) .saturating_add(RocksDbWeight::get().writes(2_u64)) @@ -2359,11 +2361,11 @@ impl WeightInfo for () { fn seal_delegate_call(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0 + r * (527 ±0)` - // Estimated: `6447 + r * (2583 ±3)` - // Minimum execution time: 9_359_000 picoseconds. - Weight::from_parts(9_425_000, 6447) - // Standard Error: 193_938 - .saturating_add(Weight::from_parts(244_904_401, 0).saturating_mul(r.into())) + // Estimated: `6447 + r * (2583 ±10)` + // Minimum execution time: 9_274_000 picoseconds. + Weight::from_parts(9_437_000, 6447) + // Standard Error: 150_832 + .saturating_add(Weight::from_parts(244_196_269, 0).saturating_mul(r.into())) .saturating_add(RocksDbWeight::get().reads((3_u64).saturating_mul(r.into()))) .saturating_add(RocksDbWeight::get().writes((1_u64).saturating_mul(r.into()))) .saturating_add(Weight::from_parts(0, 2583).saturating_mul(r.into())) @@ -2386,12 +2388,12 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `699 + t * (277 ±0)` // Estimated: `6639 + t * (3458 ±0)` - // Minimum execution time: 214_588_000 picoseconds. - Weight::from_parts(129_214_481, 6639) - // Standard Error: 2_468_090 - .saturating_add(Weight::from_parts(32_514_739, 0).saturating_mul(t.into())) + // Minimum execution time: 214_483_000 picoseconds. + Weight::from_parts(122_634_366, 6639) + // Standard Error: 2_499_235 + .saturating_add(Weight::from_parts(41_326_008, 0).saturating_mul(t.into())) // Standard Error: 3 - .saturating_add(Weight::from_parts(418, 0).saturating_mul(c.into())) + .saturating_add(Weight::from_parts(422, 0).saturating_mul(c.into())) .saturating_add(RocksDbWeight::get().reads(7_u64)) .saturating_add(RocksDbWeight::get().reads((2_u64).saturating_mul(t.into()))) .saturating_add(RocksDbWeight::get().writes(4_u64)) @@ -2406,10 +2408,10 @@ impl WeightInfo for () { /// Proof: `Contracts::Nonce` (`max_values`: Some(1), `max_size`: Some(8), added: 503, mode: `Measured`) /// Storage: `Contracts::ContractInfoOf` (r:800 w:801) /// Proof: `Contracts::ContractInfoOf` (`max_values`: None, `max_size`: Some(1795), added: 4270, mode: `Measured`) - /// 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:802 w:802) /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `Measured`) + /// Storage: `Parameters::Parameters` (r:2 w:0) + /// Proof: `Parameters::Parameters` (`max_values`: None, `max_size`: Some(36), added: 2511, mode: `Measured`) /// Storage: `System::EventTopics` (r:801 w:801) /// Proof: `System::EventTopics` (`max_values`: None, `max_size`: None, mode: `Measured`) /// The range of component `r` is `[1, 800]`. @@ -2417,10 +2419,10 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `1097 + r * (188 ±0)` // Estimated: `6990 + r * (2664 ±0)` - // Minimum execution time: 352_925_000 picoseconds. - Weight::from_parts(355_487_000, 6990) - // Standard Error: 261_528 - .saturating_add(Weight::from_parts(337_897_187, 0).saturating_mul(r.into())) + // Minimum execution time: 341_569_000 picoseconds. + Weight::from_parts(360_574_000, 6990) + // Standard Error: 259_746 + .saturating_add(Weight::from_parts(337_944_674, 0).saturating_mul(r.into())) .saturating_add(RocksDbWeight::get().reads(6_u64)) .saturating_add(RocksDbWeight::get().reads((5_u64).saturating_mul(r.into()))) .saturating_add(RocksDbWeight::get().writes(4_u64)) @@ -2435,10 +2437,10 @@ impl WeightInfo for () { /// Proof: `Contracts::Nonce` (`max_values`: Some(1), `max_size`: Some(8), added: 503, mode: `Measured`) /// Storage: `Contracts::ContractInfoOf` (r:1 w:2) /// Proof: `Contracts::ContractInfoOf` (`max_values`: None, `max_size`: Some(1795), added: 4270, mode: `Measured`) - /// 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:3 w:3) /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `Measured`) + /// Storage: `Parameters::Parameters` (r:2 w:0) + /// Proof: `Parameters::Parameters` (`max_values`: None, `max_size`: Some(36), added: 2511, mode: `Measured`) /// Storage: `System::EventTopics` (r:2 w:2) /// Proof: `System::EventTopics` (`max_values`: None, `max_size`: None, mode: `Measured`) /// The range of component `t` is `[0, 1]`. @@ -2448,12 +2450,14 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `760 + t * (104 ±0)` // Estimated: `6719 + t * (2549 ±1)` - // Minimum execution time: 1_870_832_000 picoseconds. - Weight::from_parts(949_110_245, 6719) - // Standard Error: 24 - .saturating_add(Weight::from_parts(1_084, 0).saturating_mul(i.into())) - // Standard Error: 24 - .saturating_add(Weight::from_parts(1_206, 0).saturating_mul(s.into())) + // Minimum execution time: 1_863_119_000 picoseconds. + Weight::from_parts(900_189_174, 6719) + // Standard Error: 13_040_979 + .saturating_add(Weight::from_parts(4_056_063, 0).saturating_mul(t.into())) + // Standard Error: 20 + .saturating_add(Weight::from_parts(1_028, 0).saturating_mul(i.into())) + // Standard Error: 20 + .saturating_add(Weight::from_parts(1_173, 0).saturating_mul(s.into())) .saturating_add(RocksDbWeight::get().reads(10_u64)) .saturating_add(RocksDbWeight::get().reads((1_u64).saturating_mul(t.into()))) .saturating_add(RocksDbWeight::get().writes(7_u64)) @@ -2465,58 +2469,58 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 9_142_000 picoseconds. - Weight::from_parts(9_787_220, 0) - // Standard Error: 236 - .saturating_add(Weight::from_parts(267_264, 0).saturating_mul(r.into())) + // Minimum execution time: 9_211_000 picoseconds. + Weight::from_parts(11_696_412, 0) + // Standard Error: 388 + .saturating_add(Weight::from_parts(265_538, 0).saturating_mul(r.into())) } /// The range of component `n` is `[0, 1048576]`. fn seal_hash_sha2_256_per_byte(n: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 10_485_000 picoseconds. - Weight::from_parts(1_870_250, 0) + // Minimum execution time: 10_296_000 picoseconds. + Weight::from_parts(572_494, 0) // Standard Error: 1 - .saturating_add(Weight::from_parts(1_073, 0).saturating_mul(n.into())) + .saturating_add(Weight::from_parts(1_067, 0).saturating_mul(n.into())) } /// The range of component `r` is `[0, 1600]`. fn seal_hash_keccak_256(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 9_005_000 picoseconds. - Weight::from_parts(8_943_937, 0) - // Standard Error: 1_385 - .saturating_add(Weight::from_parts(665_970, 0).saturating_mul(r.into())) + // Minimum execution time: 9_177_000 picoseconds. + Weight::from_parts(8_620_481, 0) + // Standard Error: 249 + .saturating_add(Weight::from_parts(674_502, 0).saturating_mul(r.into())) } /// The range of component `n` is `[0, 1048576]`. fn seal_hash_keccak_256_per_byte(n: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 10_965_000 picoseconds. - Weight::from_parts(11_749_746, 0) - // Standard Error: 6 - .saturating_add(Weight::from_parts(3_330, 0).saturating_mul(n.into())) + // Minimum execution time: 11_240_000 picoseconds. + Weight::from_parts(8_696_186, 0) + // Standard Error: 0 + .saturating_add(Weight::from_parts(3_328, 0).saturating_mul(n.into())) } /// The range of component `r` is `[0, 1600]`. fn seal_hash_blake2_256(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 10_400_000 picoseconds. - Weight::from_parts(13_857_546, 0) - // Standard Error: 246 - .saturating_add(Weight::from_parts(326_483, 0).saturating_mul(r.into())) + // Minimum execution time: 9_889_000 picoseconds. + Weight::from_parts(16_103_170, 0) + // Standard Error: 343 + .saturating_add(Weight::from_parts(328_939, 0).saturating_mul(r.into())) } /// The range of component `n` is `[0, 1048576]`. fn seal_hash_blake2_256_per_byte(n: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 10_064_000 picoseconds. - Weight::from_parts(1_885_873, 0) + // Minimum execution time: 10_405_000 picoseconds. + Weight::from_parts(2_264_024, 0) // Standard Error: 0 .saturating_add(Weight::from_parts(1_196, 0).saturating_mul(n.into())) } @@ -2525,60 +2529,60 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 9_068_000 picoseconds. - Weight::from_parts(17_169_362, 0) - // Standard Error: 1_580 - .saturating_add(Weight::from_parts(330_195, 0).saturating_mul(r.into())) + // Minimum execution time: 9_215_000 picoseconds. + Weight::from_parts(10_505_632, 0) + // Standard Error: 240 + .saturating_add(Weight::from_parts(324_854, 0).saturating_mul(r.into())) } /// The range of component `n` is `[0, 1048576]`. fn seal_hash_blake2_128_per_byte(n: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 10_169_000 picoseconds. - Weight::from_parts(2_159_277, 0) - // Standard Error: 0 - .saturating_add(Weight::from_parts(1_200, 0).saturating_mul(n.into())) + // Minimum execution time: 10_440_000 picoseconds. + Weight::from_parts(2_575_889, 0) + // Standard Error: 1 + .saturating_add(Weight::from_parts(1_199, 0).saturating_mul(n.into())) } /// The range of component `n` is `[0, 125697]`. fn seal_sr25519_verify_per_byte(n: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 53_863_000 picoseconds. - Weight::from_parts(54_902_157, 0) - // Standard Error: 9 - .saturating_add(Weight::from_parts(4_588, 0).saturating_mul(n.into())) + // Minimum execution time: 55_119_000 picoseconds. + Weight::from_parts(56_732_248, 0) + // Standard Error: 8 + .saturating_add(Weight::from_parts(4_639, 0).saturating_mul(n.into())) } /// The range of component `r` is `[0, 160]`. fn seal_sr25519_verify(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 9_107_000 picoseconds. - Weight::from_parts(24_115_247, 0) - // Standard Error: 7_427 - .saturating_add(Weight::from_parts(41_116_827, 0).saturating_mul(r.into())) + // Minimum execution time: 9_176_000 picoseconds. + Weight::from_parts(9_861_102, 0) + // Standard Error: 6_029 + .saturating_add(Weight::from_parts(45_948_571, 0).saturating_mul(r.into())) } /// The range of component `r` is `[0, 160]`. fn seal_ecdsa_recover(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 9_404_000 picoseconds. - Weight::from_parts(31_763_334, 0) - // Standard Error: 9_833 - .saturating_add(Weight::from_parts(45_529_880, 0).saturating_mul(r.into())) + // Minimum execution time: 9_293_000 picoseconds. + Weight::from_parts(28_785_765, 0) + // Standard Error: 9_160 + .saturating_add(Weight::from_parts(45_566_150, 0).saturating_mul(r.into())) } /// The range of component `r` is `[0, 160]`. fn seal_ecdsa_to_eth_address(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 11_409_000 picoseconds. - Weight::from_parts(15_072_835, 0) - // Standard Error: 4_591 - .saturating_add(Weight::from_parts(11_619_283, 0).saturating_mul(r.into())) + // Minimum execution time: 9_206_000 picoseconds. + Weight::from_parts(12_420_664, 0) + // Standard Error: 3_489 + .saturating_add(Weight::from_parts(11_628_989, 0).saturating_mul(r.into())) } /// Storage: `Contracts::CodeInfoOf` (r:1536 w:1536) /// Proof: `Contracts::CodeInfoOf` (`max_values`: None, `max_size`: Some(93), added: 2568, mode: `Measured`) @@ -2592,11 +2596,11 @@ impl WeightInfo for () { fn seal_set_code_hash(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0 + r * (926 ±0)` - // Estimated: `8969 + r * (3047 ±10)` - // Minimum execution time: 9_269_000 picoseconds. - Weight::from_parts(9_372_000, 8969) - // Standard Error: 61_354 - .saturating_add(Weight::from_parts(26_280_409, 0).saturating_mul(r.into())) + // Estimated: `8969 + r * (3047 ±7)` + // Minimum execution time: 9_219_000 picoseconds. + Weight::from_parts(9_385_000, 8969) + // Standard Error: 45_562 + .saturating_add(Weight::from_parts(26_360_661, 0).saturating_mul(r.into())) .saturating_add(RocksDbWeight::get().reads((3_u64).saturating_mul(r.into()))) .saturating_add(RocksDbWeight::get().writes((2_u64).saturating_mul(r.into()))) .saturating_add(Weight::from_parts(0, 3047).saturating_mul(r.into())) @@ -2608,10 +2612,10 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `274 + r * (78 ±0)` // Estimated: `1265 + r * (2553 ±0)` - // Minimum execution time: 9_103_000 picoseconds. - Weight::from_parts(14_404_626, 1265) - // Standard Error: 9_343 - .saturating_add(Weight::from_parts(5_154_949, 0).saturating_mul(r.into())) + // Minimum execution time: 9_355_000 picoseconds. + Weight::from_parts(15_071_309, 1265) + // Standard Error: 9_722 + .saturating_add(Weight::from_parts(5_328_717, 0).saturating_mul(r.into())) .saturating_add(RocksDbWeight::get().reads((1_u64).saturating_mul(r.into()))) .saturating_add(RocksDbWeight::get().writes((1_u64).saturating_mul(r.into()))) .saturating_add(Weight::from_parts(0, 2553).saturating_mul(r.into())) @@ -2623,10 +2627,10 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `275 + r * (78 ±0)` // Estimated: `990 + r * (2568 ±0)` - // Minimum execution time: 9_219_000 picoseconds. - Weight::from_parts(14_085_456, 990) - // Standard Error: 11_206 - .saturating_add(Weight::from_parts(4_422_122, 0).saturating_mul(r.into())) + // Minimum execution time: 8_979_000 picoseconds. + Weight::from_parts(14_362_224, 990) + // Standard Error: 9_137 + .saturating_add(Weight::from_parts(4_488_748, 0).saturating_mul(r.into())) .saturating_add(RocksDbWeight::get().reads((1_u64).saturating_mul(r.into()))) .saturating_add(RocksDbWeight::get().writes((1_u64).saturating_mul(r.into()))) .saturating_add(Weight::from_parts(0, 2568).saturating_mul(r.into())) @@ -2652,10 +2656,10 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `861 + r * (3 ±0)` // Estimated: `9282 + r * (3 ±0)` - // Minimum execution time: 269_333_000 picoseconds. - Weight::from_parts(286_922_618, 9282) - // Standard Error: 443 - .saturating_add(Weight::from_parts(168_869, 0).saturating_mul(r.into())) + // Minimum execution time: 269_704_000 picoseconds. + Weight::from_parts(289_916_035, 9282) + // Standard Error: 408 + .saturating_add(Weight::from_parts(166_040, 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())) @@ -2665,10 +2669,10 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 9_328_000 picoseconds. - Weight::from_parts(14_019_583, 0) - // Standard Error: 171 - .saturating_add(Weight::from_parts(88_751, 0).saturating_mul(r.into())) + // Minimum execution time: 9_361_000 picoseconds. + Weight::from_parts(11_633_836, 0) + // Standard Error: 86 + .saturating_add(Weight::from_parts(83_083, 0).saturating_mul(r.into())) } /// Storage: `Contracts::Nonce` (r:1 w:0) /// Proof: `Contracts::Nonce` (`max_values`: Some(1), `max_size`: Some(8), added: 503, mode: `Measured`) @@ -2677,10 +2681,10 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `219` // Estimated: `1704` - // Minimum execution time: 9_267_000 picoseconds. - Weight::from_parts(15_304_284, 1704) - // Standard Error: 1_219 - .saturating_add(Weight::from_parts(74_696, 0).saturating_mul(r.into())) + // Minimum execution time: 9_133_000 picoseconds. + Weight::from_parts(13_259_836, 1704) + // Standard Error: 121 + .saturating_add(Weight::from_parts(76_878, 0).saturating_mul(r.into())) .saturating_add(RocksDbWeight::get().reads(1_u64)) } /// The range of component `r` is `[0, 5000]`. @@ -2688,9 +2692,9 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 911_000 picoseconds. - Weight::from_parts(449_666, 0) - // Standard Error: 26 - .saturating_add(Weight::from_parts(14_797, 0).saturating_mul(r.into())) + // Minimum execution time: 851_000 picoseconds. + Weight::from_parts(587_883, 0) + // Standard Error: 16 + .saturating_add(Weight::from_parts(14_912, 0).saturating_mul(r.into())) } } diff --git a/substrate/frame/contracts/uapi/Cargo.toml b/substrate/frame/contracts/uapi/Cargo.toml index d9a5ee14f0545a7481fcfd133887c74921659589..80de7a1d5d69077d91ec9e0b845128027aad55ca 100644 --- a/substrate/frame/contracts/uapi/Cargo.toml +++ b/substrate/frame/contracts/uapi/Cargo.toml @@ -15,7 +15,7 @@ workspace = true paste = { version = "1.0", default-features = false } bitflags = "1.0" scale-info = { version = "2.11.1", default-features = false, features = ["derive"], optional = true } -scale = { package = "parity-scale-codec", version = "3.6.1", default-features = false, features = [ +scale = { package = "parity-scale-codec", version = "3.6.12", default-features = false, features = [ "derive", "max-encoded-len", ], optional = true } diff --git a/substrate/frame/contracts/uapi/src/host.rs b/substrate/frame/contracts/uapi/src/host.rs index 459cb59bead94fc5af18fb43955621f0e72d7e75..92065eda5d635352a0d7f7facb743960ba9189b7 100644 --- a/substrate/frame/contracts/uapi/src/host.rs +++ b/substrate/frame/contracts/uapi/src/host.rs @@ -790,7 +790,7 @@ pub trait HostFn { /// /// # Parameters /// - /// - `dest`: The XCM destination, should be decodable as [MultiLocation](https://paritytech.github.io/polkadot-sdk/master/staging_xcm/enum.VersionedLocation.html), + /// - `dest`: The XCM destination, should be decodable as [VersionedLocation](https://paritytech.github.io/polkadot-sdk/master/staging_xcm/enum.VersionedLocation.html), /// 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. diff --git a/substrate/frame/conviction-voting/Cargo.toml b/substrate/frame/conviction-voting/Cargo.toml index ffb5122ed7f980a547e2d299f0a687641f0d9161..20de4d858ad62e4e499e5c4ee6786b1f5ee2f6c4 100644 --- a/substrate/frame/conviction-voting/Cargo.toml +++ b/substrate/frame/conviction-voting/Cargo.toml @@ -17,7 +17,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] assert_matches = "1.3.0" -codec = { package = "parity-scale-codec", version = "3.6.1", default-features = false, features = [ +codec = { package = "parity-scale-codec", version = "3.6.12", default-features = false, features = [ "derive", "max-encoded-len", ] } diff --git a/substrate/frame/core-fellowship/Cargo.toml b/substrate/frame/core-fellowship/Cargo.toml index b4258281b7010855bb1f81aae4bce1cd64fb774e..8773a124cd02accb450daa2218c161563a68d8bf 100644 --- a/substrate/frame/core-fellowship/Cargo.toml +++ b/substrate/frame/core-fellowship/Cargo.toml @@ -16,7 +16,7 @@ workspace = true targets = ["x86_64-unknown-linux-gnu"] [dependencies] -codec = { package = "parity-scale-codec", version = "3.6.1", default-features = false, features = ["derive"] } +codec = { package = "parity-scale-codec", version = "3.6.12", default-features = false, features = ["derive"] } log = { workspace = true } scale-info = { version = "2.11.1", default-features = false, features = ["derive"] } frame-benchmarking = { path = "../benchmarking", default-features = false, optional = true } diff --git a/substrate/frame/delegated-staking/Cargo.toml b/substrate/frame/delegated-staking/Cargo.toml new file mode 100644 index 0000000000000000000000000000000000000000..4a4898827110105c4b05f81841494e19c14411f4 --- /dev/null +++ b/substrate/frame/delegated-staking/Cargo.toml @@ -0,0 +1,69 @@ +[package] +name = "pallet-delegated-staking" +version = "1.0.0" +authors.workspace = true +edition.workspace = true +license = "Apache-2.0" +homepage = "https://substrate.io" +repository.workspace = true +description = "FRAME delegated staking pallet" + +[package.metadata.docs.rs] +targets = ["x86_64-unknown-linux-gnu"] + +[dependencies] +codec = { package = "parity-scale-codec", version = "3.6.12", default-features = false, features = ["derive"] } +frame-support = { path = "../support", default-features = false } +frame-system = { path = "../system", default-features = false } +scale-info = { version = "2.10.0", default-features = false, features = ["derive"] } +sp-std = { path = "../../primitives/std", default-features = false } +sp-runtime = { path = "../../primitives/runtime", default-features = false } +sp-staking = { path = "../../primitives/staking", default-features = false } + +[dev-dependencies] +sp-core = { path = "../../primitives/core" } +sp-io = { path = "../../primitives/io" } +substrate-test-utils = { path = "../../test-utils" } +sp-tracing = { path = "../../primitives/tracing" } +pallet-staking = { path = "../staking" } +pallet-balances = { path = "../balances" } +pallet-timestamp = { path = "../timestamp" } +pallet-staking-reward-curve = { path = "../staking/reward-curve" } +frame-election-provider-support = { path = "../election-provider-support", default-features = false } + +[features] +default = ["std"] +std = [ + "codec/std", + "frame-election-provider-support/std", + "frame-support/std", + "frame-system/std", + "pallet-balances/std", + "pallet-staking/std", + "pallet-timestamp/std", + "scale-info/std", + "sp-core/std", + "sp-io/std", + "sp-runtime/std", + "sp-staking/std", + "sp-std/std", +] +runtime-benchmarks = [ + "frame-election-provider-support/runtime-benchmarks", + "frame-support/runtime-benchmarks", + "frame-system/runtime-benchmarks", + "pallet-balances/runtime-benchmarks", + "pallet-staking/runtime-benchmarks", + "pallet-timestamp/runtime-benchmarks", + "sp-runtime/runtime-benchmarks", + "sp-staking/runtime-benchmarks", +] +try-runtime = [ + "frame-election-provider-support/try-runtime", + "frame-support/try-runtime", + "frame-system/try-runtime", + "pallet-balances/try-runtime", + "pallet-staking/try-runtime", + "pallet-timestamp/try-runtime", + "sp-runtime/try-runtime", +] diff --git a/substrate/frame/delegated-staking/src/impls.rs b/substrate/frame/delegated-staking/src/impls.rs new file mode 100644 index 0000000000000000000000000000000000000000..b1945b0ce3769affb7537d9b575adb85890304e6 --- /dev/null +++ b/substrate/frame/delegated-staking/src/impls.rs @@ -0,0 +1,149 @@ +// 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 . + +//! Implementations of public traits, namely [`DelegationInterface`] and [`OnStakingUpdate`]. + +use super::*; +use sp_staking::{DelegationInterface, DelegationMigrator, OnStakingUpdate}; + +impl DelegationInterface for Pallet { + type Balance = BalanceOf; + type AccountId = T::AccountId; + + /// Effective balance of the `Agent` account. + fn agent_balance(who: &Self::AccountId) -> Self::Balance { + Agent::::get(who) + .map(|agent| agent.ledger.effective_balance()) + .unwrap_or_default() + } + + fn delegator_balance(delegator: &Self::AccountId) -> Self::Balance { + Delegation::::get(delegator).map(|d| d.amount).unwrap_or_default() + } + + /// Delegate funds to an `Agent`. + fn delegate( + who: &Self::AccountId, + agent: &Self::AccountId, + reward_account: &Self::AccountId, + amount: Self::Balance, + ) -> DispatchResult { + Pallet::::register_agent( + RawOrigin::Signed(agent.clone()).into(), + reward_account.clone(), + )?; + + // Delegate the funds from who to the `Agent` account. + Pallet::::delegate_to_agent(RawOrigin::Signed(who.clone()).into(), agent.clone(), amount) + } + + /// Add more delegation to the `Agent` account. + fn delegate_extra( + who: &Self::AccountId, + agent: &Self::AccountId, + amount: Self::Balance, + ) -> DispatchResult { + Pallet::::delegate_to_agent(RawOrigin::Signed(who.clone()).into(), agent.clone(), amount) + } + + /// Withdraw delegation of `delegator` to `Agent`. + /// + /// If there are funds in `Agent` account that can be withdrawn, then those funds would be + /// unlocked/released in the delegator's account. + fn withdraw_delegation( + delegator: &Self::AccountId, + agent: &Self::AccountId, + amount: Self::Balance, + num_slashing_spans: u32, + ) -> DispatchResult { + Pallet::::release_delegation( + RawOrigin::Signed(agent.clone()).into(), + delegator.clone(), + amount, + num_slashing_spans, + ) + } + + /// Returns true if the `Agent` have any slash pending to be applied. + fn has_pending_slash(agent: &Self::AccountId) -> bool { + Agent::::get(agent) + .map(|d| !d.ledger.pending_slash.is_zero()) + .unwrap_or(false) + } + + fn delegator_slash( + agent: &Self::AccountId, + delegator: &Self::AccountId, + value: Self::Balance, + maybe_reporter: Option, + ) -> sp_runtime::DispatchResult { + Pallet::::do_slash(agent.clone(), delegator.clone(), value, maybe_reporter) + } +} + +impl DelegationMigrator for Pallet { + type Balance = BalanceOf; + type AccountId = T::AccountId; + + fn migrate_nominator_to_agent( + agent: &Self::AccountId, + reward_account: &Self::AccountId, + ) -> DispatchResult { + Pallet::::migrate_to_agent( + RawOrigin::Signed(agent.clone()).into(), + reward_account.clone(), + ) + } + + fn migrate_delegation( + agent: &Self::AccountId, + delegator: &Self::AccountId, + value: Self::Balance, + ) -> DispatchResult { + Pallet::::migrate_delegation( + RawOrigin::Signed(agent.clone()).into(), + delegator.clone(), + value, + ) + } +} + +impl OnStakingUpdate> for Pallet { + fn on_slash( + who: &T::AccountId, + _slashed_active: BalanceOf, + _slashed_unlocking: &sp_std::collections::btree_map::BTreeMap>, + slashed_total: BalanceOf, + ) { + >::mutate(who, |maybe_register| match maybe_register { + // if existing agent, register the slashed amount as pending slash. + Some(register) => register.pending_slash.saturating_accrue(slashed_total), + None => { + // nothing to do + }, + }); + } + + fn on_withdraw(stash: &T::AccountId, amount: BalanceOf) { + // if there is a withdraw to the agent, then add it to the unclaimed withdrawals. + let _ = Agent::::get(stash) + // can't do anything if there is an overflow error. Just raise a defensive error. + .and_then(|agent| agent.add_unclaimed_withdraw(amount).defensive()) + .map(|agent| agent.save()); + } +} diff --git a/substrate/frame/delegated-staking/src/lib.rs b/substrate/frame/delegated-staking/src/lib.rs new file mode 100644 index 0000000000000000000000000000000000000000..210f69d9c839d5b977506c177a11f425c26e87f6 --- /dev/null +++ b/substrate/frame/delegated-staking/src/lib.rs @@ -0,0 +1,815 @@ +// 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. + +//! # Delegated Staking Pallet +//! +//! This pallet implements [`sp_staking::DelegationInterface`] that provides delegation +//! functionality to `delegators` and `agents`. It is designed to be used in conjunction with +//! [`StakingInterface`] and relies on [`Config::CoreStaking`] to provide primitive staking +//! functions. +//! +//! Currently, it does not expose any dispatchable calls but is written with a vision to expose them +//! in the future such that it can be utilised by any external account, off-chain entity or xcm +//! `MultiLocation` such as a parachain or a smart contract. +//! +//! ## Key Terminologies +//! - **Agent**: An account who accepts delegations from other accounts and act as an agent on their +//! behalf for staking these delegated funds. Also, sometimes referred as `Delegatee`. +//! - **Delegator**: An account who delegates their funds to an `agent` and authorises them to use +//! it for staking. +//! - **AgentLedger**: A data structure that holds important information about the `agent` such as +//! total delegations they have received, any slashes posted to them, etc. +//! - **Delegation**: A data structure that stores the amount of funds delegated to an `agent` by a +//! `delegator`. +//! +//! ## Goals +//! +//! Direct nomination on the Staking pallet does not scale well. Nominations pools were created to +//! address this by pooling delegator funds into one account and then staking it. This though had +//! a very critical limitation that the funds were moved from delegator account to pool account +//! and hence the delegator lost control over their funds for using it for other purposes such as +//! governance. This pallet aims to solve this by extending the staking pallet to support a new +//! primitive function: delegation of funds to an `agent` with the intent of staking. The agent can +//! then stake the delegated funds to [`Config::CoreStaking`] on behalf of the delegators. +//! +//! ### Withdrawal Management +//! Agent unbonding does not regulate ordering of consequent withdrawal for delegators. This is upto +//! the consumer of this pallet to implement in what order unbondable funds from +//! [`Config::CoreStaking`] can be withdrawn by the delegators. +//! +//! ### Reward and Slashing +//! This pallet does not enforce any specific strategy for how rewards or slashes are applied. It +//! is upto the `agent` account to decide how to apply the rewards and slashes. +//! +//! This importantly allows clients of this pallet to build their own strategies for reward/slashes. +//! For example, an `agent` account can choose to first slash the reward pot before slashing the +//! delegators. Or part of the reward can go to an insurance fund that can be used to cover any +//! potential future slashes. The goal is to eventually allow foreign MultiLocations +//! (smart contracts or pallets on another chain) to build their own pooled staking solutions +//! similar to `NominationPools`. + +//! ## Core functions +//! +//! - Allow an account to receive delegations. See [`Pallet::register_agent`]. +//! - Delegate funds to an `agent` account. See [`Pallet::delegate_to_agent`]. +//! - Release delegated funds from an `agent` account to the `delegator`. See +//! [`Pallet::release_delegation`]. +//! - Migrate a `Nominator` account to an `agent` account. See [`Pallet::migrate_to_agent`]. +//! Explained in more detail in the `Migration` section. +//! - Migrate unclaimed delegated funds from `agent` to delegator. When a nominator migrates to an +//! agent, the funds are held in a proxy account. This function allows the delegator to claim their +//! share of the funds from the proxy account. See [`Pallet::migrate_delegation`]. +//! +//! ## Lazy Slashing +//! One of the reasons why direct nominators on staking pallet cannot scale well is because all +//! nominators are slashed at the same time. This is expensive and needs to be bounded operation. +//! +//! This pallet implements a lazy slashing mechanism. Any slashes to the `agent` are posted in its +//! `AgentLedger` as a pending slash. Since the actual amount is held in the multiple +//! `delegator` accounts, this pallet has no way to know how to apply slash. It is the `agent`'s +//! responsibility to apply slashes for each delegator, one at a time. Staking pallet ensures the +//! pending slash never exceeds staked amount and would freeze further withdraws until all pending +//! slashes are cleared. +//! +//! The user of this pallet can apply slash using +//! [DelegationInterface::delegator_slash](sp_staking::DelegationInterface::delegator_slash). +//! +//! ## Migration from Nominator to Agent +//! More details [here](https://hackmd.io/@ak0n/454-np-governance). +//! +//! ## Nomination Pool vs Delegation Staking +//! This pallet is not a replacement for Nomination Pool but adds a new primitive in addition to +//! staking pallet that can be used by Nomination Pool to support delegation based staking. It can +//! be thought of as an extension to the Staking Pallet in relation to Nomination Pools. +//! Technically, these changes could be made in one of those pallets as well but that would have +//! meant significant refactoring and high chances of introducing a regression. With this approach, +//! we can keep the existing pallets with minimal changes and introduce a new pallet that can be +//! optionally used by Nomination Pool. The vision is to build this in a configurable way such that +//! runtime can choose whether to use this pallet or not. +//! +//! With that said, following is the main difference between +//! #### Nomination Pool without delegation support +//! 1) transfer fund from delegator to pool account, and +//! 2) stake from pool account as a direct nominator. +//! +//! #### Nomination Pool with delegation support +//! 1) delegate fund from delegator to pool account, and +//! 2) stake from pool account as an `Agent` account on the staking pallet. +//! +//! The difference being, in the second approach, the delegated funds will be locked in-place in +//! user's account enabling them to participate in use cases that allows use of `held` funds such +//! as participation in governance voting. +//! +//! Nomination pool still does all the heavy lifting around pool administration, reward +//! distribution, lazy slashing and as such, is not meant to be replaced with this pallet. +//! +//! ## Limitations +//! - Rewards can not be auto-compounded. +//! - Slashes are lazy and hence there could be a period of time when an account can use funds for +//! operations such as voting in governance even though they should be slashed. + +#![cfg_attr(not(feature = "std"), no_std)] +#![deny(rustdoc::broken_intra_doc_links)] + +mod impls; +#[cfg(test)] +mod mock; +#[cfg(test)] +mod tests; +mod types; + +pub use pallet::*; + +use types::*; + +use frame_support::{ + pallet_prelude::*, + traits::{ + fungible::{ + hold::{ + Balanced as FunHoldBalanced, Inspect as FunHoldInspect, Mutate as FunHoldMutate, + }, + Balanced, Inspect as FunInspect, Mutate as FunMutate, + }, + tokens::{fungible::Credit, Fortitude, Precision, Preservation}, + Defensive, DefensiveOption, Imbalance, OnUnbalanced, + }, +}; +use sp_runtime::{ + traits::{AccountIdConversion, CheckedAdd, CheckedSub, Zero}, + ArithmeticError, DispatchResult, Perbill, RuntimeDebug, Saturating, +}; +use sp_staking::{EraIndex, StakingInterface, StakingUnchecked}; +use sp_std::{convert::TryInto, prelude::*}; + +pub type BalanceOf = + <::Currency as FunInspect<::AccountId>>::Balance; + +use frame_system::{ensure_signed, pallet_prelude::*, RawOrigin}; + +#[frame_support::pallet] +pub mod pallet { + use super::*; + + #[pallet::pallet] + pub struct Pallet(PhantomData); + + #[pallet::config] + pub trait Config: frame_system::Config { + /// The overarching event type. + type RuntimeEvent: From> + IsType<::RuntimeEvent>; + + /// Injected identifier for the pallet. + #[pallet::constant] + type PalletId: Get; + + /// Currency type. + type Currency: FunHoldMutate + + FunMutate + + FunHoldBalanced; + + /// Handler for the unbalanced reduction when slashing a delegator. + type OnSlash: OnUnbalanced>; + + /// Fraction of the slash that is rewarded to the caller of pending slash to the agent. + #[pallet::constant] + type SlashRewardFraction: Get; + + /// Overarching hold reason. + type RuntimeHoldReason: From; + + /// Core staking implementation. + type CoreStaking: StakingUnchecked, AccountId = Self::AccountId>; + } + + #[pallet::error] + pub enum Error { + /// The account cannot perform this operation. + NotAllowed, + /// An existing staker cannot perform this action. + AlreadyStaking, + /// Reward Destination cannot be same as `Agent` account. + InvalidRewardDestination, + /// Delegation conditions are not met. + /// + /// Possible issues are + /// 1) Cannot delegate to self, + /// 2) Cannot delegate to multiple delegates. + InvalidDelegation, + /// The account does not have enough funds to perform the operation. + NotEnoughFunds, + /// Not an existing `Agent` account. + NotAgent, + /// Not a Delegator account. + NotDelegator, + /// Some corruption in internal state. + BadState, + /// Unapplied pending slash restricts operation on `Agent`. + UnappliedSlash, + /// `Agent` has no pending slash to be applied. + NothingToSlash, + /// Failed to withdraw amount from Core Staking. + WithdrawFailed, + /// Operation not supported by this pallet. + NotSupported, + } + + /// A reason for placing a hold on funds. + #[pallet::composite_enum] + pub enum HoldReason { + /// Funds held for stake delegation to another account. + #[codec(index = 0)] + StakingDelegation, + } + + #[pallet::event] + #[pallet::generate_deposit(pub (super) fn deposit_event)] + pub enum Event { + /// Funds delegated by a delegator. + Delegated { agent: T::AccountId, delegator: T::AccountId, amount: BalanceOf }, + /// Funds released to a delegator. + Released { agent: T::AccountId, delegator: T::AccountId, amount: BalanceOf }, + /// Funds slashed from a delegator. + Slashed { agent: T::AccountId, delegator: T::AccountId, amount: BalanceOf }, + } + + /// Map of Delegators to their `Delegation`. + /// + /// Implementation note: We are not using a double map with `delegator` and `agent` account + /// as keys since we want to restrict delegators to delegate only to one account at a time. + #[pallet::storage] + pub(crate) type Delegators = + CountedStorageMap<_, Twox64Concat, T::AccountId, Delegation, OptionQuery>; + + /// Map of `Agent` to their `Ledger`. + #[pallet::storage] + pub(crate) type Agents = + CountedStorageMap<_, Twox64Concat, T::AccountId, AgentLedger, OptionQuery>; + + // This pallet is not currently written with the intention of exposing any calls. But the + // functions defined in the following impl block should act as a good reference for how the + // exposed calls would look like when exposed. + impl Pallet { + /// Register an account to become a stake `Agent`. Sometimes also called a `Delegatee`. + /// + /// Delegators can authorize `Agent`s to stake on their behalf by delegating their funds to + /// them. The `Agent` can then use the delegated funds to stake to [`Config::CoreStaking`]. + /// + /// An account that is directly staked to [`Config::CoreStaking`] cannot become an `Agent`. + /// However, they can migrate to become an agent using [`Self::migrate_to_agent`]. + /// + /// Implementation note: This function allows any account to become an agent. It is + /// important though that accounts that call [`StakingUnchecked::virtual_bond`] are keyless + /// accounts. This is not a problem for now since this is only used by other pallets in the + /// runtime which use keyless account as agents. If we later want to expose this as a + /// dispatchable call, we should derive a sub-account from the caller and use that as the + /// agent account. + pub fn register_agent( + origin: OriginFor, + reward_account: T::AccountId, + ) -> DispatchResult { + let who = ensure_signed(origin)?; + + // Existing `agent` cannot register again and a delegator cannot become an `agent`. + ensure!(!Self::is_agent(&who) && !Self::is_delegator(&who), Error::::NotAllowed); + + // They cannot be already a direct staker in the staking pallet. + ensure!(!Self::is_direct_staker(&who), Error::::AlreadyStaking); + + // Reward account cannot be same as `agent` account. + ensure!(reward_account != who, Error::::InvalidRewardDestination); + + Self::do_register_agent(&who, &reward_account); + Ok(()) + } + + /// Migrate from a `Nominator` account to `Agent` account. + /// + /// The origin needs to + /// - be a `Nominator` with [`Config::CoreStaking`], + /// - not already an `Agent`, + /// + /// This function will create a proxy account to the agent called `proxy_delegator` and + /// transfer the directly staked amount by the agent to it. The `proxy_delegator` delegates + /// the funds to the origin making origin an `Agent` account. The real `delegator` + /// accounts of the origin can later migrate their funds using [Self::migrate_delegation] to + /// claim back their share of delegated funds from `proxy_delegator` to self. + /// + /// Any free fund in the agent's account will be marked as unclaimed withdrawal. + pub fn migrate_to_agent( + origin: OriginFor, + reward_account: T::AccountId, + ) -> DispatchResult { + let who = ensure_signed(origin)?; + // ensure who is a staker in `CoreStaking` but not already an agent or a delegator. + ensure!( + Self::is_direct_staker(&who) && !Self::is_agent(&who) && !Self::is_delegator(&who), + Error::::NotAllowed + ); + + // Reward account cannot be same as `agent` account. + ensure!(reward_account != who, Error::::InvalidRewardDestination); + + Self::do_migrate_to_agent(&who, &reward_account) + } + + /// Release previously delegated funds by delegator to origin. + /// + /// Only agents can call this. + /// + /// Tries to withdraw unbonded funds from `CoreStaking` if needed and release amount to + /// `delegator`. + pub fn release_delegation( + origin: OriginFor, + delegator: T::AccountId, + amount: BalanceOf, + num_slashing_spans: u32, + ) -> DispatchResult { + let who = ensure_signed(origin)?; + Self::do_release(&who, &delegator, amount, num_slashing_spans) + } + + /// Migrate delegated funds that are held in `proxy_delegator` to the claiming `delegator`'s + /// account. If successful, the specified funds will be moved and delegated from `delegator` + /// account to the agent. + /// + /// This can be called by `agent` accounts that were previously a direct `Nominator` with + /// [`Config::CoreStaking`] and has some remaining unclaimed delegations. + /// + /// Internally, it moves some delegations from `proxy_delegator` account to `delegator` + /// account and reapplying the holds. + pub fn migrate_delegation( + origin: OriginFor, + delegator: T::AccountId, + amount: BalanceOf, + ) -> DispatchResult { + let agent = ensure_signed(origin)?; + + // Ensure they have minimum delegation. + ensure!(amount >= T::Currency::minimum_balance(), Error::::NotEnoughFunds); + + // Ensure delegator is sane. + ensure!(!Self::is_agent(&delegator), Error::::NotAllowed); + ensure!(!Self::is_delegator(&delegator), Error::::NotAllowed); + ensure!(!Self::is_direct_staker(&delegator), Error::::AlreadyStaking); + + // ensure agent is sane. + ensure!(Self::is_agent(&agent), Error::::NotAgent); + + // and has enough delegated balance to migrate. + let proxy_delegator = Self::sub_account(AccountType::ProxyDelegator, agent); + let balance_remaining = Self::held_balance_of(&proxy_delegator); + ensure!(balance_remaining >= amount, Error::::NotEnoughFunds); + + Self::do_migrate_delegation(&proxy_delegator, &delegator, amount) + } + + /// Delegate given `amount` of tokens to an `Agent` account. + /// + /// If `origin` is the first time delegator, we add them to state. If they are already + /// delegating, we increase the delegation. + /// + /// Conditions: + /// - Delegators cannot delegate to more than one agent. + /// - The `agent` account should already be registered as such. See + /// [`Self::register_agent`]. + pub fn delegate_to_agent( + origin: OriginFor, + agent: T::AccountId, + amount: BalanceOf, + ) -> DispatchResult { + let delegator = ensure_signed(origin)?; + + // ensure delegator is sane. + ensure!( + Delegation::::can_delegate(&delegator, &agent), + Error::::InvalidDelegation + ); + ensure!(!Self::is_direct_staker(&delegator), Error::::AlreadyStaking); + + // ensure agent is sane. + ensure!(Self::is_agent(&agent), Error::::NotAgent); + + // add to delegation. + Self::do_delegate(&delegator, &agent, amount)?; + + // bond the newly delegated amount to `CoreStaking`. + Self::do_bond(&agent, amount) + } + } + + #[pallet::hooks] + impl Hooks> for Pallet { + #[cfg(feature = "try-runtime")] + fn try_state(_n: BlockNumberFor) -> Result<(), sp_runtime::TryRuntimeError> { + Self::do_try_state() + } + } +} + +impl Pallet { + /// Derive a (keyless) pot account from the given agent account and account type. + pub(crate) fn sub_account(account_type: AccountType, agent: T::AccountId) -> T::AccountId { + T::PalletId::get().into_sub_account_truncating((account_type, agent.clone())) + } + + /// Held balance of a delegator. + pub(crate) fn held_balance_of(who: &T::AccountId) -> BalanceOf { + T::Currency::balance_on_hold(&HoldReason::StakingDelegation.into(), who) + } + + /// Returns true if who is registered as an `Agent`. + fn is_agent(who: &T::AccountId) -> bool { + >::contains_key(who) + } + + /// Returns true if who is delegating to an `Agent` account. + fn is_delegator(who: &T::AccountId) -> bool { + >::contains_key(who) + } + + /// Returns true if who is already staking on [`Config::CoreStaking`]. + fn is_direct_staker(who: &T::AccountId) -> bool { + T::CoreStaking::status(who).is_ok() + } + + /// Registers a new agent in the system. + fn do_register_agent(who: &T::AccountId, reward_account: &T::AccountId) { + AgentLedger::::new(reward_account).update(who); + + // Agent does not hold balance of its own but this pallet will provide for this to exist. + // This is expected to be a keyless account and not created by any user directly so safe. + // TODO: Someday if we allow anyone to be an agent, we should take a deposit for + // being a delegator. + frame_system::Pallet::::inc_providers(who); + } + + /// Migrate existing staker account `who` to an `Agent` account. + fn do_migrate_to_agent(who: &T::AccountId, reward_account: &T::AccountId) -> DispatchResult { + Self::do_register_agent(who, reward_account); + + // We create a proxy delegator that will keep all the delegation funds until funds are + // transferred to actual delegator. + let proxy_delegator = Self::sub_account(AccountType::ProxyDelegator, who.clone()); + + // Keep proxy delegator alive until all funds are migrated. + frame_system::Pallet::::inc_providers(&proxy_delegator); + + // Get current stake + let stake = T::CoreStaking::stake(who)?; + + // release funds from core staking. + T::CoreStaking::migrate_to_virtual_staker(who); + + // transfer just released staked amount plus any free amount. + let amount_to_transfer = + T::Currency::reducible_balance(who, Preservation::Expendable, Fortitude::Polite); + + // This should never fail but if it does, it indicates bad state and we abort. + T::Currency::transfer(who, &proxy_delegator, amount_to_transfer, Preservation::Expendable)?; + + T::CoreStaking::update_payee(who, reward_account)?; + // delegate all transferred funds back to agent. + Self::do_delegate(&proxy_delegator, who, amount_to_transfer)?; + + // if the transferred/delegated amount was greater than the stake, mark the extra as + // unclaimed withdrawal. + let unclaimed_withdraws = amount_to_transfer + .checked_sub(&stake.total) + .defensive_ok_or(ArithmeticError::Underflow)?; + + if !unclaimed_withdraws.is_zero() { + let mut ledger = AgentLedger::::get(who).ok_or(Error::::NotAgent)?; + ledger.unclaimed_withdrawals = ledger + .unclaimed_withdrawals + .checked_add(&unclaimed_withdraws) + .defensive_ok_or(ArithmeticError::Overflow)?; + ledger.update(who); + } + + Ok(()) + } + + /// Bond `amount` to `agent_acc` in [`Config::CoreStaking`]. + fn do_bond(agent_acc: &T::AccountId, amount: BalanceOf) -> DispatchResult { + let agent = Agent::::get(agent_acc)?; + + let available_to_bond = agent.available_to_bond(); + defensive_assert!(amount == available_to_bond, "not expected value to bond"); + + if agent.is_bonded() { + T::CoreStaking::bond_extra(&agent.key, amount) + } else { + T::CoreStaking::virtual_bond(&agent.key, amount, agent.reward_account()) + } + } + + /// Delegate `amount` from `delegator` to `agent`. + fn do_delegate( + delegator: &T::AccountId, + agent: &T::AccountId, + amount: BalanceOf, + ) -> DispatchResult { + let mut ledger = AgentLedger::::get(agent).ok_or(Error::::NotAgent)?; + // try to hold the funds. + T::Currency::hold(&HoldReason::StakingDelegation.into(), delegator, amount)?; + + let new_delegation_amount = + if let Some(existing_delegation) = Delegation::::get(delegator) { + ensure!(&existing_delegation.agent == agent, Error::::InvalidDelegation); + existing_delegation + .amount + .checked_add(&amount) + .ok_or(ArithmeticError::Overflow)? + } else { + amount + }; + + Delegation::::new(agent, new_delegation_amount).update_or_kill(delegator); + ledger.total_delegated = + ledger.total_delegated.checked_add(&amount).ok_or(ArithmeticError::Overflow)?; + ledger.update(agent); + + Self::deposit_event(Event::::Delegated { + agent: agent.clone(), + delegator: delegator.clone(), + amount, + }); + + Ok(()) + } + + /// Release `amount` of delegated funds from `agent` to `delegator`. + fn do_release( + who: &T::AccountId, + delegator: &T::AccountId, + amount: BalanceOf, + num_slashing_spans: u32, + ) -> DispatchResult { + let mut agent = Agent::::get(who)?; + let mut delegation = Delegation::::get(delegator).ok_or(Error::::NotDelegator)?; + + // make sure delegation to be released is sound. + ensure!(&delegation.agent == who, Error::::NotAgent); + ensure!(delegation.amount >= amount, Error::::NotEnoughFunds); + + // if we do not already have enough funds to be claimed, try withdraw some more. + // keep track if we killed the staker in the process. + let stash_killed = if agent.ledger.unclaimed_withdrawals < amount { + // withdraw account. + let killed = T::CoreStaking::withdraw_unbonded(who.clone(), num_slashing_spans) + .map_err(|_| Error::::WithdrawFailed)?; + // reload agent from storage since withdrawal might have changed the state. + agent = agent.refresh()?; + Some(killed) + } else { + None + }; + + // if we still do not have enough funds to release, abort. + ensure!(agent.ledger.unclaimed_withdrawals >= amount, Error::::NotEnoughFunds); + + // Claim withdraw from agent. Kill agent if no delegation left. + // TODO: Ideally if there is a register, there should be an unregister that should + // clean up the agent. Can be improved in future. + if agent.remove_unclaimed_withdraw(amount)?.update_or_kill()? { + match stash_killed { + Some(killed) => { + // this implies we did a `CoreStaking::withdraw` before release. Ensure + // we killed the staker as well. + ensure!(killed, Error::::BadState); + }, + None => { + // We did not do a `CoreStaking::withdraw` before release. Ensure staker is + // already killed in `CoreStaking`. + ensure!(T::CoreStaking::status(who).is_err(), Error::::BadState); + }, + } + + // Remove provider reference for `who`. + let _ = frame_system::Pallet::::dec_providers(who).defensive(); + } + + // book keep delegation + delegation.amount = delegation + .amount + .checked_sub(&amount) + .defensive_ok_or(ArithmeticError::Overflow)?; + + // remove delegator if nothing delegated anymore + delegation.update_or_kill(delegator); + + let released = T::Currency::release( + &HoldReason::StakingDelegation.into(), + delegator, + amount, + Precision::BestEffort, + )?; + + defensive_assert!(released == amount, "hold should have been released fully"); + + Self::deposit_event(Event::::Released { + agent: who.clone(), + delegator: delegator.clone(), + amount, + }); + + Ok(()) + } + + /// Migrates delegation of `amount` from `source` account to `destination` account. + fn do_migrate_delegation( + source_delegator: &T::AccountId, + destination_delegator: &T::AccountId, + amount: BalanceOf, + ) -> DispatchResult { + let mut source_delegation = + Delegators::::get(source_delegator).defensive_ok_or(Error::::BadState)?; + + // some checks that must have already been checked before. + ensure!(source_delegation.amount >= amount, Error::::NotEnoughFunds); + debug_assert!( + !Self::is_delegator(destination_delegator) && !Self::is_agent(destination_delegator) + ); + + // update delegations + Delegation::::new(&source_delegation.agent, amount) + .update_or_kill(destination_delegator); + + source_delegation.amount = source_delegation + .amount + .checked_sub(&amount) + .defensive_ok_or(Error::::BadState)?; + + source_delegation.update_or_kill(source_delegator); + + // release funds from source + let released = T::Currency::release( + &HoldReason::StakingDelegation.into(), + source_delegator, + amount, + Precision::BestEffort, + )?; + + defensive_assert!(released == amount, "hold should have been released fully"); + + // transfer the released amount to `destination_delegator`. + let post_balance = T::Currency::transfer( + source_delegator, + destination_delegator, + amount, + Preservation::Expendable, + ) + .map_err(|_| Error::::BadState)?; + + // if balance is zero, clear provider for source (proxy) delegator. + if post_balance == Zero::zero() { + let _ = frame_system::Pallet::::dec_providers(source_delegator).defensive(); + } + + // hold the funds again in the new delegator account. + T::Currency::hold(&HoldReason::StakingDelegation.into(), destination_delegator, amount)?; + + Ok(()) + } + + /// Take slash `amount` from agent's `pending_slash`counter and apply it to `delegator` account. + pub fn do_slash( + agent_acc: T::AccountId, + delegator: T::AccountId, + amount: BalanceOf, + maybe_reporter: Option, + ) -> DispatchResult { + let agent = Agent::::get(&agent_acc)?; + // ensure there is something to slash + ensure!(agent.ledger.pending_slash > Zero::zero(), Error::::NothingToSlash); + + let mut delegation = >::get(&delegator).ok_or(Error::::NotDelegator)?; + ensure!(delegation.agent == agent_acc, Error::::NotAgent); + ensure!(delegation.amount >= amount, Error::::NotEnoughFunds); + + // slash delegator + let (mut credit, missing) = + T::Currency::slash(&HoldReason::StakingDelegation.into(), &delegator, amount); + + defensive_assert!(missing.is_zero(), "slash should have been fully applied"); + + let actual_slash = credit.peek(); + + // remove the applied slashed amount from agent. + agent.remove_slash(actual_slash).save(); + delegation.amount = + delegation.amount.checked_sub(&actual_slash).ok_or(ArithmeticError::Overflow)?; + delegation.update_or_kill(&delegator); + + if let Some(reporter) = maybe_reporter { + let reward_payout: BalanceOf = T::SlashRewardFraction::get() * actual_slash; + let (reporter_reward, rest) = credit.split(reward_payout); + + // credit is the amount that we provide to `T::OnSlash`. + credit = rest; + + // reward reporter or drop it. + let _ = T::Currency::resolve(&reporter, reporter_reward); + } + + T::OnSlash::on_unbalanced(credit); + + Self::deposit_event(Event::::Slashed { agent: agent_acc, delegator, amount }); + + Ok(()) + } + + /// Total balance that is available for stake. Includes already staked amount. + #[cfg(test)] + pub(crate) fn stakeable_balance(who: &T::AccountId) -> BalanceOf { + Agent::::get(who) + .map(|agent| agent.ledger.stakeable_balance()) + .unwrap_or_default() + } +} + +#[cfg(any(test, feature = "try-runtime"))] +use sp_std::collections::btree_map::BTreeMap; + +#[cfg(any(test, feature = "try-runtime"))] +impl Pallet { + pub(crate) fn do_try_state() -> Result<(), sp_runtime::TryRuntimeError> { + // build map to avoid reading storage multiple times. + let delegation_map = Delegators::::iter().collect::>(); + let ledger_map = Agents::::iter().collect::>(); + + Self::check_delegates(ledger_map.clone())?; + Self::check_delegators(delegation_map, ledger_map)?; + + Ok(()) + } + + fn check_delegates( + ledgers: BTreeMap>, + ) -> Result<(), sp_runtime::TryRuntimeError> { + for (agent, ledger) in ledgers { + ensure!( + matches!( + T::CoreStaking::status(&agent).expect("agent should be bonded"), + sp_staking::StakerStatus::Nominator(_) | sp_staking::StakerStatus::Idle + ), + "agent should be bonded and not validator" + ); + + ensure!( + ledger.stakeable_balance() >= + T::CoreStaking::total_stake(&agent) + .expect("agent should exist as a nominator"), + "Cannot stake more than balance" + ); + } + + Ok(()) + } + + fn check_delegators( + delegations: BTreeMap>, + ledger: BTreeMap>, + ) -> Result<(), sp_runtime::TryRuntimeError> { + let mut delegation_aggregation = BTreeMap::>::new(); + for (delegator, delegation) in delegations.iter() { + ensure!( + T::CoreStaking::status(delegator).is_err(), + "delegator should not be directly staked" + ); + ensure!(!Self::is_agent(delegator), "delegator cannot be an agent"); + + delegation_aggregation + .entry(delegation.agent.clone()) + .and_modify(|e| *e += delegation.amount) + .or_insert(delegation.amount); + } + + for (agent, total_delegated) in delegation_aggregation { + ensure!(!Self::is_delegator(&agent), "agent cannot be delegator"); + + let ledger = ledger.get(&agent).expect("ledger should exist"); + ensure!( + ledger.total_delegated == total_delegated, + "ledger total delegated should match delegations" + ); + } + + Ok(()) + } +} diff --git a/substrate/frame/delegated-staking/src/mock.rs b/substrate/frame/delegated-staking/src/mock.rs new file mode 100644 index 0000000000000000000000000000000000000000..21a9fe6b227009abe3b31c9fa6a4bbdc81e831d7 --- /dev/null +++ b/substrate/frame/delegated-staking/src/mock.rs @@ -0,0 +1,308 @@ +// 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::{self as delegated_staking, types::Agent}; +use frame_support::{ + assert_ok, derive_impl, + pallet_prelude::*, + parameter_types, + traits::{ConstU64, Currency}, + PalletId, +}; + +use sp_runtime::{traits::IdentityLookup, BuildStorage, Perbill}; + +use frame_election_provider_support::{ + bounds::{ElectionBounds, ElectionBoundsBuilder}, + onchain, SequentialPhragmen, +}; +use frame_support::dispatch::RawOrigin; +use pallet_staking::{ActiveEra, ActiveEraInfo, CurrentEra}; +use sp_staking::{Stake, StakingInterface}; + +pub type T = Runtime; +type Block = frame_system::mocking::MockBlock; +pub type AccountId = u128; + +pub const GENESIS_VALIDATOR: AccountId = 1; +pub const GENESIS_NOMINATOR_ONE: AccountId = 101; +pub const GENESIS_NOMINATOR_TWO: AccountId = 102; + +#[derive_impl(frame_system::config_preludes::TestDefaultConfig as frame_system::DefaultConfig)] +impl frame_system::Config for Runtime { + type Block = Block; + type AccountData = pallet_balances::AccountData; + type AccountId = AccountId; + type Lookup = IdentityLookup; +} + +impl pallet_timestamp::Config for Runtime { + type Moment = u64; + type OnTimestampSet = (); + type MinimumPeriod = ConstU64<5>; + type WeightInfo = (); +} + +pub type Balance = u128; + +parameter_types! { + pub static ExistentialDeposit: Balance = 1; +} +impl pallet_balances::Config for Runtime { + type MaxLocks = ConstU32<128>; + type MaxReserves = (); + type ReserveIdentifier = [u8; 8]; + type Balance = Balance; + type RuntimeEvent = RuntimeEvent; + type DustRemoval = (); + type ExistentialDeposit = ExistentialDeposit; + type AccountStore = System; + type WeightInfo = (); + type FreezeIdentifier = RuntimeFreezeReason; + type MaxFreezes = ConstU32<1>; + type RuntimeHoldReason = RuntimeHoldReason; + type RuntimeFreezeReason = RuntimeFreezeReason; +} + +pallet_staking_reward_curve::build! { + const I_NPOS: sp_runtime::curve::PiecewiseLinear<'static> = curve!( + min_inflation: 0_025_000, + max_inflation: 0_100_000, + ideal_stake: 0_500_000, + falloff: 0_050_000, + max_piece_count: 40, + test_precision: 0_005_000, + ); +} + +parameter_types! { + pub const RewardCurve: &'static sp_runtime::curve::PiecewiseLinear<'static> = &I_NPOS; + pub static BondingDuration: u32 = 3; + pub static ElectionsBoundsOnChain: ElectionBounds = ElectionBoundsBuilder::default().build(); +} +pub struct OnChainSeqPhragmen; +impl onchain::Config for OnChainSeqPhragmen { + type System = Runtime; + type Solver = SequentialPhragmen; + type DataProvider = Staking; + type WeightInfo = (); + type MaxWinners = ConstU32<100>; + type Bounds = ElectionsBoundsOnChain; +} + +impl pallet_staking::Config for Runtime { + type Currency = Balances; + type CurrencyBalance = Balance; + type UnixTime = pallet_timestamp::Pallet; + type CurrencyToVote = (); + type RewardRemainder = (); + type RuntimeEvent = RuntimeEvent; + type Slash = (); + type Reward = (); + type SessionsPerEra = ConstU32<1>; + type SlashDeferDuration = (); + type AdminOrigin = frame_system::EnsureRoot; + type BondingDuration = BondingDuration; + type SessionInterface = (); + type EraPayout = pallet_staking::ConvertCurve; + type NextNewSession = (); + type HistoryDepth = ConstU32<84>; + type MaxExposurePageSize = ConstU32<64>; + type ElectionProvider = onchain::OnChainExecution; + type GenesisElectionProvider = Self::ElectionProvider; + type VoterList = pallet_staking::UseNominatorsAndValidatorsMap; + type TargetList = pallet_staking::UseValidatorsMap; + type NominationsQuota = pallet_staking::FixedNominationsQuota<16>; + type MaxUnlockingChunks = ConstU32<10>; + type MaxControllersInDeprecationBatch = ConstU32<100>; + type EventListeners = DelegatedStaking; + type BenchmarkingConfig = pallet_staking::TestBenchmarkingConfig; + type WeightInfo = (); + type DisablingStrategy = pallet_staking::UpToLimitDisablingStrategy; +} + +parameter_types! { + pub const DelegatedStakingPalletId: PalletId = PalletId(*b"py/dlstk"); + pub const SlashRewardFraction: Perbill = Perbill::from_percent(10); +} +impl delegated_staking::Config for Runtime { + type RuntimeEvent = RuntimeEvent; + type PalletId = DelegatedStakingPalletId; + type Currency = Balances; + type OnSlash = (); + type SlashRewardFraction = SlashRewardFraction; + type RuntimeHoldReason = RuntimeHoldReason; + type CoreStaking = Staking; +} + +parameter_types! { + pub static MaxUnbonding: u32 = 8; +} + +frame_support::construct_runtime!( + pub enum Runtime { + System: frame_system, + Timestamp: pallet_timestamp, + Balances: pallet_balances, + Staking: pallet_staking, + DelegatedStaking: delegated_staking, + } +); + +#[derive(Default)] +pub struct ExtBuilder {} + +impl ExtBuilder { + fn build(self) -> sp_io::TestExternalities { + sp_tracing::try_init_simple(); + let mut storage = + frame_system::GenesisConfig::::default().build_storage().unwrap(); + + let _ = pallet_balances::GenesisConfig:: { + balances: vec![ + (GENESIS_VALIDATOR, 10000), + (GENESIS_NOMINATOR_ONE, 1000), + (GENESIS_NOMINATOR_TWO, 2000), + ], + } + .assimilate_storage(&mut storage); + + let stakers = vec![ + ( + GENESIS_VALIDATOR, + GENESIS_VALIDATOR, + 1000, + sp_staking::StakerStatus::::Validator, + ), + ( + GENESIS_NOMINATOR_ONE, + GENESIS_NOMINATOR_ONE, + 100, + sp_staking::StakerStatus::::Nominator(vec![1]), + ), + ( + GENESIS_NOMINATOR_TWO, + GENESIS_NOMINATOR_TWO, + 200, + sp_staking::StakerStatus::::Nominator(vec![1]), + ), + ]; + + let _ = pallet_staking::GenesisConfig:: { + stakers: stakers.clone(), + // ideal validator count + validator_count: 2, + minimum_validator_count: 1, + invulnerables: vec![], + slash_reward_fraction: Perbill::from_percent(10), + min_nominator_bond: ExistentialDeposit::get(), + min_validator_bond: ExistentialDeposit::get(), + ..Default::default() + } + .assimilate_storage(&mut storage); + + let mut ext = sp_io::TestExternalities::from(storage); + + ext.execute_with(|| { + // for events to be deposited. + frame_system::Pallet::::set_block_number(1); + // set era for staking. + start_era(0); + }); + + ext + } + pub fn build_and_execute(self, test: impl FnOnce()) { + sp_tracing::try_init_simple(); + let mut ext = self.build(); + ext.execute_with(test); + ext.execute_with(|| { + #[cfg(feature = "try-runtime")] + >::try_state( + frame_system::Pallet::::block_number(), + frame_support::traits::TryStateSelect::All, + ) + .unwrap(); + #[cfg(not(feature = "try-runtime"))] + DelegatedStaking::do_try_state().unwrap(); + }); + } +} + +/// fund and return who. +pub(crate) fn fund(who: &AccountId, amount: Balance) { + let _ = Balances::deposit_creating(who, amount); +} + +/// Sets up delegation for passed delegators, returns total delegated amount. +/// +/// `delegate_amount` is incremented by the amount `increment` starting with `base_delegate_amount` +/// from lower index to higher index of delegators. +pub(crate) fn setup_delegation_stake( + agent: AccountId, + reward_acc: AccountId, + delegators: Vec, + base_delegate_amount: Balance, + increment: Balance, +) -> Balance { + fund(&agent, 100); + assert_ok!(DelegatedStaking::register_agent(RawOrigin::Signed(agent).into(), reward_acc)); + let mut delegated_amount: Balance = 0; + for (index, delegator) in delegators.iter().enumerate() { + let amount_to_delegate = base_delegate_amount + increment * index as Balance; + delegated_amount += amount_to_delegate; + + fund(delegator, amount_to_delegate + ExistentialDeposit::get()); + assert_ok!(DelegatedStaking::delegate_to_agent( + RawOrigin::Signed(*delegator).into(), + agent, + amount_to_delegate + )); + } + + // sanity checks + assert_eq!(DelegatedStaking::stakeable_balance(&agent), delegated_amount); + assert_eq!(Agent::::get(&agent).unwrap().available_to_bond(), 0); + + delegated_amount +} + +pub(crate) fn start_era(era: sp_staking::EraIndex) { + CurrentEra::::set(Some(era)); + ActiveEra::::set(Some(ActiveEraInfo { index: era, start: None })); +} + +pub(crate) fn eq_stake(who: AccountId, total: Balance, active: Balance) -> bool { + Staking::stake(&who).unwrap() == Stake { total, active } && + get_agent(&who).ledger.stakeable_balance() == total +} + +pub(crate) fn get_agent(agent: &AccountId) -> Agent { + Agent::::get(agent).expect("delegate should exist") +} + +parameter_types! { + static ObservedEventsDelegatedStaking: usize = 0; +} + +#[allow(unused)] +pub(crate) fn events_since_last_call() -> Vec> { + let events = System::read_events_for_pallet::>(); + let already_seen = ObservedEventsDelegatedStaking::get(); + ObservedEventsDelegatedStaking::set(events.len()); + events.into_iter().skip(already_seen).collect() +} diff --git a/substrate/frame/delegated-staking/src/tests.rs b/substrate/frame/delegated-staking/src/tests.rs new file mode 100644 index 0000000000000000000000000000000000000000..1f36f655beb865f138a87fb4a9546ea1ad97a3ae --- /dev/null +++ b/substrate/frame/delegated-staking/src/tests.rs @@ -0,0 +1,685 @@ +// This file is part of Substrate. + +// Copyright (C) Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +//! Tests for pallet-delegated-staking. + +use super::*; +use crate::mock::*; +use frame_support::{assert_noop, assert_ok, traits::fungible::InspectHold}; +use pallet_staking::Error as StakingError; +use sp_staking::DelegationInterface; + +#[test] +fn create_an_agent_with_first_delegator() { + ExtBuilder::default().build_and_execute(|| { + let agent: AccountId = 200; + let reward_account: AccountId = 201; + let delegator: AccountId = 202; + + // set intention to accept delegation. + fund(&agent, 1000); + assert_ok!(DelegatedStaking::register_agent( + RawOrigin::Signed(agent).into(), + reward_account + )); + + // delegate to this account + fund(&delegator, 1000); + assert_ok!(DelegatedStaking::delegate_to_agent( + RawOrigin::Signed(delegator).into(), + agent, + 100 + )); + + // verify + assert!(DelegatedStaking::is_agent(&agent)); + assert_eq!(DelegatedStaking::stakeable_balance(&agent), 100); + assert_eq!( + Balances::balance_on_hold(&HoldReason::StakingDelegation.into(), &delegator), + 100 + ); + assert_eq!(DelegatedStaking::held_balance_of(&delegator), 100); + }); +} + +#[test] +fn cannot_become_agent() { + ExtBuilder::default().build_and_execute(|| { + // cannot set reward account same as agent account + assert_noop!( + DelegatedStaking::register_agent(RawOrigin::Signed(100).into(), 100), + Error::::InvalidRewardDestination + ); + + // an existing validator cannot become agent + assert_noop!( + DelegatedStaking::register_agent( + RawOrigin::Signed(mock::GENESIS_VALIDATOR).into(), + 100 + ), + Error::::AlreadyStaking + ); + + // an existing direct staker to `CoreStaking` cannot become an agent. + assert_noop!( + DelegatedStaking::register_agent( + RawOrigin::Signed(mock::GENESIS_NOMINATOR_ONE).into(), + 100 + ), + Error::::AlreadyStaking + ); + assert_noop!( + DelegatedStaking::register_agent( + RawOrigin::Signed(mock::GENESIS_NOMINATOR_TWO).into(), + 100 + ), + Error::::AlreadyStaking + ); + }); +} + +#[test] +fn create_multiple_delegators() { + ExtBuilder::default().build_and_execute(|| { + let agent: AccountId = 200; + let reward_account: AccountId = 201; + + // stakeable balance is 0 for non agent + fund(&agent, 1000); + assert!(!DelegatedStaking::is_agent(&agent)); + assert_eq!(DelegatedStaking::stakeable_balance(&agent), 0); + + // set intention to accept delegation. + assert_ok!(DelegatedStaking::register_agent( + RawOrigin::Signed(agent).into(), + reward_account + )); + + // create 100 delegators + for i in 202..302 { + fund(&i, 100 + ExistentialDeposit::get()); + assert_ok!(DelegatedStaking::delegate_to_agent( + RawOrigin::Signed(i).into(), + agent, + 100 + )); + // Balance of 100 held on delegator account for delegating to the agent. + assert_eq!(Balances::balance_on_hold(&HoldReason::StakingDelegation.into(), &i), 100); + } + + // verify + assert!(DelegatedStaking::is_agent(&agent)); + assert_eq!(DelegatedStaking::stakeable_balance(&agent), 100 * 100); + }); +} + +#[test] +fn agent_restrictions() { + // Similar to creating a nomination pool + ExtBuilder::default().build_and_execute(|| { + let agent_one = 200; + let delegator_one = 210; + fund(&agent_one, 100); + assert_ok!(DelegatedStaking::register_agent( + RawOrigin::Signed(agent_one).into(), + agent_one + 1 + )); + fund(&delegator_one, 200); + assert_ok!(DelegatedStaking::delegate_to_agent( + RawOrigin::Signed(delegator_one).into(), + agent_one, + 100 + )); + + let agent_two = 300; + let delegator_two = 310; + fund(&agent_two, 100); + assert_ok!(DelegatedStaking::register_agent( + RawOrigin::Signed(agent_two).into(), + agent_two + 1 + )); + fund(&delegator_two, 200); + assert_ok!(DelegatedStaking::delegate_to_agent( + RawOrigin::Signed(delegator_two).into(), + agent_two, + 100 + )); + + // agent one tries to delegate to agent 2 + assert_noop!( + DelegatedStaking::delegate_to_agent(RawOrigin::Signed(agent_one).into(), agent_two, 10), + Error::::InvalidDelegation + ); + + // agent one tries to delegate to a delegator + assert_noop!( + DelegatedStaking::delegate_to_agent( + RawOrigin::Signed(agent_one).into(), + delegator_one, + 10 + ), + Error::::InvalidDelegation + ); + assert_noop!( + DelegatedStaking::delegate_to_agent( + RawOrigin::Signed(agent_one).into(), + delegator_two, + 10 + ), + Error::::InvalidDelegation + ); + + // delegator one tries to delegate to agent 2 as well (it already delegates to agent + // 1) + assert_noop!( + DelegatedStaking::delegate_to_agent( + RawOrigin::Signed(delegator_one).into(), + agent_two, + 10 + ), + Error::::InvalidDelegation + ); + + // cannot delegate to non agents. + let non_agent = 201; + // give it some funds + fund(&non_agent, 200); + assert_noop!( + DelegatedStaking::delegate_to_agent( + RawOrigin::Signed(delegator_one).into(), + non_agent, + 10 + ), + Error::::InvalidDelegation + ); + + // cannot delegate to a delegator + assert_noop!( + DelegatedStaking::delegate_to_agent( + RawOrigin::Signed(delegator_one).into(), + delegator_two, + 10 + ), + Error::::InvalidDelegation + ); + + // delegator cannot delegate to self + assert_noop!( + DelegatedStaking::delegate_to_agent( + RawOrigin::Signed(delegator_one).into(), + delegator_one, + 10 + ), + Error::::InvalidDelegation + ); + + // agent cannot delegate to self + assert_noop!( + DelegatedStaking::delegate_to_agent(RawOrigin::Signed(agent_one).into(), agent_one, 10), + Error::::InvalidDelegation + ); + }); +} + +#[test] +fn apply_pending_slash() { + ExtBuilder::default().build_and_execute(|| { + start_era(1); + let agent: AccountId = 200; + let reward_acc: AccountId = 201; + let delegators: Vec = (301..=350).collect(); + let reporter: AccountId = 400; + + let total_staked = setup_delegation_stake(agent, reward_acc, delegators.clone(), 10, 10); + + start_era(4); + // slash half of the stake + pallet_staking::slashing::do_slash::( + &agent, + total_staked / 2, + &mut Default::default(), + &mut Default::default(), + 3, + ); + + // agent cannot slash an account that is not its delegator. + setup_delegation_stake(210, 211, (351..=352).collect(), 100, 0); + assert_noop!( + ::delegator_slash(&agent, &351, 1, Some(400)), + Error::::NotAgent + ); + // or a non delegator account + fund(&353, 100); + assert_noop!( + ::delegator_slash(&agent, &353, 1, Some(400)), + Error::::NotDelegator + ); + + // ensure bookkept pending slash is correct. + assert_eq!(get_agent(&agent).ledger.pending_slash, total_staked / 2); + let mut old_reporter_balance = Balances::free_balance(reporter); + + // lets apply the pending slash on delegators. + for i in delegators { + // balance before slash + let initial_pending_slash = get_agent(&agent).ledger.pending_slash; + assert!(initial_pending_slash > 0); + let unslashed_balance = DelegatedStaking::held_balance_of(&i); + let slash = unslashed_balance / 2; + // slash half of delegator's delegation. + assert_ok!(::delegator_slash( + &agent, + &i, + slash, + Some(400) + )); + + // balance after slash. + assert_eq!(DelegatedStaking::held_balance_of(&i), unslashed_balance - slash); + // pending slash is reduced by the amount slashed. + assert_eq!(get_agent(&agent).ledger.pending_slash, initial_pending_slash - slash); + // reporter get 10% of the slash amount. + assert_eq!( + Balances::free_balance(reporter) - old_reporter_balance, + ::slash_reward_fraction() * slash, + ); + // update old balance + old_reporter_balance = Balances::free_balance(reporter); + } + + // nothing to slash anymore + assert_eq!(get_agent(&agent).ledger.pending_slash, 0); + + // cannot slash anymore + assert_noop!( + ::delegator_slash(&agent, &350, 1, None), + Error::::NothingToSlash + ); + }); +} + +/// Integration tests with pallet-staking. +mod staking_integration { + use super::*; + use pallet_staking::RewardDestination; + use sp_staking::Stake; + + #[test] + fn bond() { + ExtBuilder::default().build_and_execute(|| { + let agent: AccountId = 99; + let reward_acc: AccountId = 100; + assert_eq!(Staking::status(&agent), Err(StakingError::::NotStash.into())); + + // set intention to become an agent + fund(&agent, 100); + assert_ok!(DelegatedStaking::register_agent( + RawOrigin::Signed(agent).into(), + reward_acc + )); + assert_eq!(DelegatedStaking::stakeable_balance(&agent), 0); + + let mut delegated_balance: Balance = 0; + + // set some delegations + for delegator in 200..250 { + fund(&delegator, 200); + assert_ok!(DelegatedStaking::delegate_to_agent( + RawOrigin::Signed(delegator).into(), + agent, + 100 + )); + delegated_balance += 100; + assert_eq!( + Balances::balance_on_hold(&HoldReason::StakingDelegation.into(), &delegator), + 100 + ); + assert_eq!(DelegatedStaking::delegator_balance(&delegator), 100); + + let agent_obj = get_agent(&agent); + assert_eq!(agent_obj.ledger.stakeable_balance(), delegated_balance); + assert_eq!(agent_obj.available_to_bond(), 0); + assert_eq!(agent_obj.bonded_stake(), delegated_balance); + } + + assert_eq!(Staking::stake(&agent).unwrap(), Stake { total: 50 * 100, active: 50 * 100 }) + }); + } + + #[test] + fn withdraw_test() { + ExtBuilder::default().build_and_execute(|| { + // initial era + start_era(1); + let agent: AccountId = 200; + let reward_acc: AccountId = 201; + let delegators: Vec = (301..=350).collect(); + let total_staked = + setup_delegation_stake(agent, reward_acc, delegators.clone(), 10, 10); + + // lets go to a new era + start_era(2); + + assert!(eq_stake(agent, total_staked, total_staked)); + // Withdrawing without unbonding would fail. + assert_noop!( + DelegatedStaking::release_delegation(RawOrigin::Signed(agent).into(), 301, 50, 0), + Error::::NotEnoughFunds + ); + + // 305 wants to unbond 50 in era 2, withdrawable in era 5. + assert_ok!(Staking::unbond(RawOrigin::Signed(agent).into(), 50)); + + // 310 wants to unbond 100 in era 3, withdrawable in era 6. + start_era(3); + assert_ok!(Staking::unbond(RawOrigin::Signed(agent).into(), 100)); + + // 320 wants to unbond 200 in era 4, withdrawable in era 7. + start_era(4); + assert_ok!(Staking::unbond(RawOrigin::Signed(agent).into(), 200)); + + // active stake is now reduced.. + let expected_active = total_staked - (50 + 100 + 200); + assert!(eq_stake(agent, total_staked, expected_active)); + + // nothing to withdraw at era 4 + assert_noop!( + DelegatedStaking::release_delegation(RawOrigin::Signed(agent).into(), 305, 50, 0), + Error::::NotEnoughFunds + ); + + assert_eq!(get_agent(&agent).available_to_bond(), 0); + // full amount is still delegated + assert_eq!(get_agent(&agent).ledger.effective_balance(), total_staked); + + start_era(5); + // at era 5, 50 tokens are withdrawable, cannot withdraw more. + assert_noop!( + DelegatedStaking::release_delegation(RawOrigin::Signed(agent).into(), 305, 51, 0), + Error::::NotEnoughFunds + ); + // less is possible + assert_ok!(DelegatedStaking::release_delegation( + RawOrigin::Signed(agent).into(), + 305, + 30, + 0 + )); + assert_ok!(DelegatedStaking::release_delegation( + RawOrigin::Signed(agent).into(), + 305, + 20, + 0 + )); + + // Lets go to future era where everything is unbonded. Withdrawable amount: 100 + 200 + start_era(7); + // 305 has no more amount delegated so it cannot withdraw. + assert_noop!( + DelegatedStaking::release_delegation(RawOrigin::Signed(agent).into(), 305, 5, 0), + Error::::NotDelegator + ); + // 309 is an active delegator but has total delegation of 90, so it cannot withdraw more + // than that. + assert_noop!( + DelegatedStaking::release_delegation(RawOrigin::Signed(agent).into(), 309, 91, 0), + Error::::NotEnoughFunds + ); + // 310 cannot withdraw more than delegated funds. + assert_noop!( + DelegatedStaking::release_delegation(RawOrigin::Signed(agent).into(), 310, 101, 0), + Error::::NotEnoughFunds + ); + // but can withdraw all its delegation amount. + assert_ok!(DelegatedStaking::release_delegation( + RawOrigin::Signed(agent).into(), + 310, + 100, + 0 + )); + // 320 can withdraw all its delegation amount. + assert_ok!(DelegatedStaking::release_delegation( + RawOrigin::Signed(agent).into(), + 320, + 200, + 0 + )); + + // cannot withdraw anything more.. + assert_noop!( + DelegatedStaking::release_delegation(RawOrigin::Signed(agent).into(), 301, 1, 0), + Error::::NotEnoughFunds + ); + assert_noop!( + DelegatedStaking::release_delegation(RawOrigin::Signed(agent).into(), 350, 1, 0), + Error::::NotEnoughFunds + ); + }); + } + + #[test] + fn withdraw_happens_with_unbonded_balance_first() { + ExtBuilder::default().build_and_execute(|| { + start_era(1); + let agent = 200; + setup_delegation_stake(agent, 201, (300..350).collect(), 100, 0); + + // verify withdraw not possible yet + assert_noop!( + DelegatedStaking::release_delegation(RawOrigin::Signed(agent).into(), 300, 100, 0), + Error::::NotEnoughFunds + ); + + // fill up unlocking chunks in core staking. + // 10 is the max chunks + for i in 2..=11 { + start_era(i); + assert_ok!(Staking::unbond(RawOrigin::Signed(agent).into(), 10)); + // no withdrawals from core staking yet. + assert_eq!(get_agent(&agent).ledger.unclaimed_withdrawals, 0); + } + + // another unbond would trigger withdrawal + start_era(12); + assert_ok!(Staking::unbond(RawOrigin::Signed(agent).into(), 10)); + + // 8 previous unbonds would be withdrawn as they were already unlocked. Unlocking period + // is 3 eras. + assert_eq!(get_agent(&agent).ledger.unclaimed_withdrawals, 8 * 10); + + // release some delegation now. + assert_ok!(DelegatedStaking::release_delegation( + RawOrigin::Signed(agent).into(), + 300, + 40, + 0 + )); + assert_eq!(get_agent(&agent).ledger.unclaimed_withdrawals, 80 - 40); + + // cannot release more than available + assert_noop!( + DelegatedStaking::release_delegation(RawOrigin::Signed(agent).into(), 300, 50, 0), + Error::::NotEnoughFunds + ); + assert_ok!(DelegatedStaking::release_delegation( + RawOrigin::Signed(agent).into(), + 300, + 40, + 0 + )); + + assert_eq!(DelegatedStaking::held_balance_of(&300), 100 - 80); + }); + } + + #[test] + fn reward_destination_restrictions() { + ExtBuilder::default().build_and_execute(|| { + // give some funds to 200 + fund(&200, 1000); + let balance_200 = Balances::free_balance(200); + + // `Agent` account cannot be reward destination + assert_noop!( + DelegatedStaking::register_agent(RawOrigin::Signed(200).into(), 200), + Error::::InvalidRewardDestination + ); + + // different reward account works + assert_ok!(DelegatedStaking::register_agent(RawOrigin::Signed(200).into(), 201)); + // add some delegations to it + fund(&300, 1000); + assert_ok!(DelegatedStaking::delegate_to_agent( + RawOrigin::Signed(300).into(), + 200, + 100 + )); + + // update_payee to self fails. + assert_noop!( + ::update_payee(&200, &200), + StakingError::::RewardDestinationRestricted + ); + + // passing correct reward destination works + assert_ok!(::update_payee(&200, &201)); + + // amount is staked correctly + assert!(eq_stake(200, 100, 100)); + assert_eq!(get_agent(&200).available_to_bond(), 0); + assert_eq!(get_agent(&200).ledger.effective_balance(), 100); + + // free balance of delegate is untouched + assert_eq!(Balances::free_balance(200), balance_200); + }); + } + + #[test] + fn agent_restrictions() { + ExtBuilder::default().build_and_execute(|| { + setup_delegation_stake(200, 201, (202..203).collect(), 100, 0); + + // Registering again is noop + assert_noop!( + DelegatedStaking::register_agent(RawOrigin::Signed(200).into(), 201), + Error::::NotAllowed + ); + // a delegator cannot become delegate + assert_noop!( + DelegatedStaking::register_agent(RawOrigin::Signed(202).into(), 203), + Error::::NotAllowed + ); + // existing staker cannot become a delegate + assert_noop!( + DelegatedStaking::register_agent( + RawOrigin::Signed(GENESIS_NOMINATOR_ONE).into(), + 201 + ), + Error::::AlreadyStaking + ); + assert_noop!( + DelegatedStaking::register_agent(RawOrigin::Signed(GENESIS_VALIDATOR).into(), 201), + Error::::AlreadyStaking + ); + }); + } + + #[test] + fn migration_works() { + ExtBuilder::default().build_and_execute(|| { + // add a nominator + let staked_amount = 4000; + let agent_amount = 5000; + fund(&200, agent_amount); + + assert_ok!(Staking::bond( + RuntimeOrigin::signed(200), + staked_amount, + RewardDestination::Account(201) + )); + assert_ok!(Staking::nominate(RuntimeOrigin::signed(200), vec![GENESIS_VALIDATOR],)); + let init_stake = Staking::stake(&200).unwrap(); + + // scenario: 200 is a pool account, and the stake comes from its 4 delegators (300..304) + // in equal parts. lets try to migrate this nominator into delegate based stake. + + // all balance currently is in 200 + assert_eq!(Balances::free_balance(200), agent_amount); + + // to migrate, nominator needs to set an account as a proxy delegator where staked funds + // will be moved and delegated back to this old nominator account. This should be funded + // with at least ED. + let proxy_delegator = DelegatedStaking::sub_account(AccountType::ProxyDelegator, 200); + + assert_ok!(DelegatedStaking::migrate_to_agent(RawOrigin::Signed(200).into(), 201)); + + // verify all went well + let mut expected_proxy_delegated_amount = agent_amount; + assert_eq!( + Balances::balance_on_hold(&HoldReason::StakingDelegation.into(), &proxy_delegator), + expected_proxy_delegated_amount + ); + // stake amount is transferred from delegate to proxy delegator account. + assert_eq!(Balances::free_balance(200), 0); + assert_eq!(Staking::stake(&200).unwrap(), init_stake); + assert_eq!(get_agent(&200).ledger.effective_balance(), agent_amount); + assert_eq!(get_agent(&200).available_to_bond(), 0); + assert_eq!(get_agent(&200).ledger.unclaimed_withdrawals, agent_amount - staked_amount); + + // now lets migrate the delegators + let delegator_share = agent_amount / 4; + for delegator in 300..304 { + assert_eq!(Balances::free_balance(delegator), 0); + // fund them with ED + fund(&delegator, ExistentialDeposit::get()); + // migrate 1/4th amount into each delegator + assert_ok!(DelegatedStaking::migrate_delegation( + RawOrigin::Signed(200).into(), + delegator, + delegator_share + )); + assert_eq!( + Balances::balance_on_hold(&HoldReason::StakingDelegation.into(), &delegator), + delegator_share + ); + expected_proxy_delegated_amount -= delegator_share; + assert_eq!( + Balances::balance_on_hold( + &HoldReason::StakingDelegation.into(), + &proxy_delegator + ), + expected_proxy_delegated_amount + ); + + // delegate stake is unchanged. + assert_eq!(Staking::stake(&200).unwrap(), init_stake); + assert_eq!(get_agent(&200).ledger.effective_balance(), agent_amount); + assert_eq!(get_agent(&200).available_to_bond(), 0); + assert_eq!( + get_agent(&200).ledger.unclaimed_withdrawals, + agent_amount - staked_amount + ); + } + + // cannot use migrate delegator anymore + assert_noop!( + DelegatedStaking::migrate_delegation(RawOrigin::Signed(200).into(), 305, 1), + Error::::NotEnoughFunds + ); + }); + } +} diff --git a/substrate/frame/delegated-staking/src/types.rs b/substrate/frame/delegated-staking/src/types.rs new file mode 100644 index 0000000000000000000000000000000000000000..0bfc23281dfe6eb3648418610a1184babdd3605d --- /dev/null +++ b/substrate/frame/delegated-staking/src/types.rs @@ -0,0 +1,292 @@ +// 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 . + +//! Basic types used in delegated staking. + +use super::*; +use frame_support::traits::DefensiveSaturating; + +/// The type of pot account being created. +#[derive(Encode, Decode)] +pub(crate) enum AccountType { + /// A proxy delegator account created for a nominator who migrated to an `Agent` account. + /// + /// Funds for unmigrated `delegator` accounts of the `Agent` are kept here. + ProxyDelegator, +} + +/// Information about delegation of a `delegator`. +#[derive(Default, Encode, Clone, Decode, RuntimeDebug, TypeInfo, MaxEncodedLen)] +#[scale_info(skip_type_params(T))] +pub struct Delegation { + /// The target of delegation. + pub agent: T::AccountId, + /// The amount delegated. + pub amount: BalanceOf, +} + +impl Delegation { + /// Get delegation of a `delegator`. + pub(crate) fn get(delegator: &T::AccountId) -> Option { + >::get(delegator) + } + + /// Create and return a new delegation instance. + pub(crate) fn new(agent: &T::AccountId, amount: BalanceOf) -> Self { + Delegation { agent: agent.clone(), amount } + } + + /// Ensure the delegator is either a new delegator or they are adding more delegation to the + /// existing agent. + /// + /// Delegators are prevented from delegating to multiple agents at the same time. + pub(crate) fn can_delegate(delegator: &T::AccountId, agent: &T::AccountId) -> bool { + Delegation::::get(delegator) + .map(|delegation| delegation.agent == *agent) + .unwrap_or( + // all good if it is a new delegator except it should not be an existing agent. + !>::contains_key(delegator), + ) + } + + /// Save self to storage. If the delegation amount is zero, remove the delegation. + pub(crate) fn update_or_kill(self, key: &T::AccountId) { + // Clean up if no delegation left. + if self.amount == Zero::zero() { + >::remove(key); + return + } + + >::insert(key, self) + } +} + +/// Ledger of all delegations to an `Agent`. +/// +/// This keeps track of the active balance of the `Agent` that is made up from the funds that +/// are currently delegated to this `Agent`. It also tracks the pending slashes yet to be +/// applied among other things. +#[derive(Default, Clone, Encode, Decode, RuntimeDebug, TypeInfo, MaxEncodedLen)] +#[scale_info(skip_type_params(T))] +pub struct AgentLedger { + /// Where the reward should be paid out. + pub payee: T::AccountId, + /// Sum of all delegated funds to this `Agent`. + #[codec(compact)] + pub total_delegated: BalanceOf, + /// Funds that are withdrawn from core staking but not released to delegator/s. It is a subset + /// of `total_delegated` and can never be greater than it. + /// + /// We need this register to ensure that the `Agent` does not bond funds from delegated + /// funds that are withdrawn and should be claimed by delegators. + #[codec(compact)] + pub unclaimed_withdrawals: BalanceOf, + /// Slashes that are not yet applied. This affects the effective balance of the `Agent`. + #[codec(compact)] + pub pending_slash: BalanceOf, +} + +impl AgentLedger { + /// Create a new instance of `AgentLedger`. + pub(crate) fn new(reward_destination: &T::AccountId) -> Self { + AgentLedger { + payee: reward_destination.clone(), + total_delegated: Zero::zero(), + unclaimed_withdrawals: Zero::zero(), + pending_slash: Zero::zero(), + } + } + + /// Get `AgentLedger` from storage. + pub(crate) fn get(key: &T::AccountId) -> Option { + >::get(key) + } + + /// Save self to storage with the given key. + pub(crate) fn update(self, key: &T::AccountId) { + >::insert(key, self) + } + + /// Effective total balance of the `Agent`. + /// + /// This takes into account any slashes reported to `Agent` but unapplied. + pub(crate) fn effective_balance(&self) -> BalanceOf { + defensive_assert!( + self.total_delegated >= self.pending_slash, + "slash cannot be higher than actual balance of delegator" + ); + + // pending slash needs to be burned and cannot be used for stake. + self.total_delegated.saturating_sub(self.pending_slash) + } + + /// Agent balance that can be staked/bonded in [`T::CoreStaking`]. + pub(crate) fn stakeable_balance(&self) -> BalanceOf { + self.effective_balance().saturating_sub(self.unclaimed_withdrawals) + } +} + +/// Wrapper around `AgentLedger` to provide some helper functions to mutate the ledger. +#[derive(Clone)] +pub struct Agent { + /// storage key + pub key: T::AccountId, + /// storage value + pub ledger: AgentLedger, +} + +impl Agent { + /// Get `Agent` from storage if it exists or return an error. + pub(crate) fn get(agent: &T::AccountId) -> Result, DispatchError> { + let ledger = AgentLedger::::get(agent).ok_or(Error::::NotAgent)?; + Ok(Agent { key: agent.clone(), ledger }) + } + + /// Remove funds that are withdrawn from [Config::CoreStaking] but not claimed by a delegator. + /// + /// Checked decrease of delegation amount from `total_delegated` and `unclaimed_withdrawals` + /// registers. Consumes self and returns a new instance of self if success. + pub(crate) fn remove_unclaimed_withdraw( + self, + amount: BalanceOf, + ) -> Result { + let new_total_delegated = self + .ledger + .total_delegated + .checked_sub(&amount) + .defensive_ok_or(ArithmeticError::Overflow)?; + let new_unclaimed_withdrawals = self + .ledger + .unclaimed_withdrawals + .checked_sub(&amount) + .defensive_ok_or(ArithmeticError::Overflow)?; + + Ok(Agent { + ledger: AgentLedger { + total_delegated: new_total_delegated, + unclaimed_withdrawals: new_unclaimed_withdrawals, + ..self.ledger + }, + ..self + }) + } + + /// Add funds that are withdrawn from [Config::CoreStaking] to be claimed by delegators later. + pub(crate) fn add_unclaimed_withdraw( + self, + amount: BalanceOf, + ) -> Result { + let new_unclaimed_withdrawals = self + .ledger + .unclaimed_withdrawals + .checked_add(&amount) + .defensive_ok_or(ArithmeticError::Overflow)?; + + Ok(Agent { + ledger: AgentLedger { unclaimed_withdrawals: new_unclaimed_withdrawals, ..self.ledger }, + ..self + }) + } + + /// Amount that is delegated but not bonded yet. + /// + /// This importantly does not include `unclaimed_withdrawals` as those should not be bonded + /// again unless explicitly requested. + pub(crate) fn available_to_bond(&self) -> BalanceOf { + let bonded_stake = self.bonded_stake(); + let stakeable = self.ledger.stakeable_balance(); + + defensive_assert!( + stakeable >= bonded_stake, + "cannot be bonded with more than total amount delegated to agent" + ); + + stakeable.saturating_sub(bonded_stake) + } + + /// Remove slashes from the `AgentLedger`. + pub(crate) fn remove_slash(self, amount: BalanceOf) -> Self { + let pending_slash = self.ledger.pending_slash.defensive_saturating_sub(amount); + let total_delegated = self.ledger.total_delegated.defensive_saturating_sub(amount); + + Agent { ledger: AgentLedger { pending_slash, total_delegated, ..self.ledger }, ..self } + } + + /// Get the total stake of agent bonded in [`Config::CoreStaking`]. + pub(crate) fn bonded_stake(&self) -> BalanceOf { + T::CoreStaking::total_stake(&self.key).unwrap_or(Zero::zero()) + } + + /// Returns true if the agent is bonded in [`Config::CoreStaking`]. + pub(crate) fn is_bonded(&self) -> bool { + T::CoreStaking::stake(&self.key).is_ok() + } + + /// Returns the reward account registered by the agent. + pub(crate) fn reward_account(&self) -> &T::AccountId { + &self.ledger.payee + } + + /// Save self to storage. + pub(crate) fn save(self) { + let key = self.key; + self.ledger.update(&key) + } + + /// Save self and remove if no delegation left. + /// + /// Returns: + /// - true if agent killed. + /// - error if the delegate is in an unexpected state. + pub(crate) fn update_or_kill(self) -> Result { + let key = self.key; + // see if delegate can be killed + if self.ledger.total_delegated == Zero::zero() { + ensure!( + self.ledger.unclaimed_withdrawals == Zero::zero() && + self.ledger.pending_slash == Zero::zero(), + Error::::BadState + ); + >::remove(key); + return Ok(true) + } + self.ledger.update(&key); + Ok(false) + } + + /// Reloads self from storage. + pub(crate) fn refresh(self) -> Result, DispatchError> { + Self::get(&self.key) + } + + /// Balance of `Agent` that is not bonded. + /// + /// This is similar to [Self::available_to_bond] except it also includes `unclaimed_withdrawals` + /// of `Agent`. + #[cfg(test)] + #[allow(unused)] + pub(crate) fn total_unbonded(&self) -> BalanceOf { + let bonded_stake = self.bonded_stake(); + + let net_balance = self.ledger.effective_balance(); + + assert!(net_balance >= bonded_stake, "cannot be bonded with more than the agent balance"); + + net_balance.saturating_sub(bonded_stake) + } +} diff --git a/substrate/frame/democracy/Cargo.toml b/substrate/frame/democracy/Cargo.toml index edd2d742b5069a73212a291aaf440de40e96fd24..7f182447ead61a0b694b7dc21a888fd4480e1197 100644 --- a/substrate/frame/democracy/Cargo.toml +++ b/substrate/frame/democracy/Cargo.toml @@ -16,7 +16,7 @@ workspace = true targets = ["x86_64-unknown-linux-gnu"] [dependencies] -codec = { package = "parity-scale-codec", version = "3.6.1", default-features = false, features = [ +codec = { package = "parity-scale-codec", version = "3.6.12", default-features = false, features = [ "derive", ] } scale-info = { version = "2.11.1", default-features = false, features = ["derive"] } diff --git a/substrate/frame/democracy/src/benchmarking.rs b/substrate/frame/democracy/src/benchmarking.rs index aa66137ad880403a3a3934e121e358bc193d0826..799d614c37f4a87a147c1d1e0c21febc1ad68cd3 100644 --- a/substrate/frame/democracy/src/benchmarking.rs +++ b/substrate/frame/democracy/src/benchmarking.rs @@ -108,7 +108,7 @@ benchmarks! { whitelist_account!(caller); }: _(RawOrigin::Signed(caller), proposal, value) verify { - assert_eq!(Democracy::::public_props().len(), p as usize, "Proposals not created."); + assert_eq!(PublicProps::::get().len(), p as usize, "Proposals not created."); } second { @@ -122,12 +122,12 @@ benchmarks! { Democracy::::second(RawOrigin::Signed(seconder).into(), 0)?; } - let deposits = Democracy::::deposit_of(0).ok_or("Proposal not created")?; + let deposits = DepositOf::::get(0).ok_or("Proposal not created")?; assert_eq!(deposits.0.len(), (T::MaxDeposits::get() - 1) as usize, "Seconds not recorded"); whitelist_account!(caller); }: _(RawOrigin::Signed(caller), 0) verify { - let deposits = Democracy::::deposit_of(0).ok_or("Proposal not created")?; + let deposits = DepositOf::::get(0).ok_or("Proposal not created")?; assert_eq!(deposits.0.len(), (T::MaxDeposits::get()) as usize, "`second` benchmark did not work"); } @@ -175,7 +175,7 @@ benchmarks! { // Change vote from aye to nay let nay = Vote { aye: false, conviction: Conviction::Locked1x }; let new_vote = AccountVote::Standard { vote: nay, balance: 1000u32.into() }; - let ref_index = Democracy::::referendum_count() - 1; + let ref_index = ReferendumCount::::get() - 1; // This tests when a user changes a vote whitelist_account!(caller); @@ -186,7 +186,7 @@ benchmarks! { _ => return Err("Votes are not direct".into()), }; assert_eq!(votes.len(), T::MaxVotes::get() as usize, "Vote was incorrectly added"); - let referendum_info = Democracy::::referendum_info(ref_index) + let referendum_info = ReferendumInfoOf::::get(ref_index) .ok_or("referendum doesn't exist")?; let tally = match referendum_info { ReferendumInfo::Ongoing(r) => r.tally, @@ -261,7 +261,7 @@ benchmarks! { }: _(origin, proposal) verify { // External proposal created - ensure!(>::exists(), "External proposal didn't work"); + ensure!(NextExternal::::exists(), "External proposal didn't work"); } external_propose_majority { @@ -271,7 +271,7 @@ benchmarks! { }: _(origin, proposal) verify { // External proposal created - ensure!(>::exists(), "External proposal didn't work"); + ensure!(NextExternal::::exists(), "External proposal didn't work"); } external_propose_default { @@ -281,7 +281,7 @@ benchmarks! { }: _(origin, proposal) verify { // External proposal created - ensure!(>::exists(), "External proposal didn't work"); + ensure!(NextExternal::::exists(), "External proposal didn't work"); } fast_track { @@ -303,7 +303,7 @@ benchmarks! { let delay = 0u32; }: _(origin_fast_track, proposal_hash, voting_period, delay.into()) verify { - assert_eq!(Democracy::::referendum_count(), 1, "referendum not created"); + assert_eq!(ReferendumCount::::get(), 1, "referendum not created"); assert_last_event::(crate::Event::MetadataTransferred { prev_owner: MetadataOwner::External, owner: MetadataOwner::Referendum(0), @@ -338,7 +338,7 @@ benchmarks! { }: _(origin, proposal_hash) verify { assert!(NextExternal::::get().is_none()); - let (_, new_vetoers) = >::get(&proposal_hash).ok_or("no blacklist")?; + let (_, new_vetoers) = Blacklist::::get(&proposal_hash).ok_or("no blacklist")?; assert_eq!(new_vetoers.len(), T::MaxBlacklisted::get() as usize, "vetoers not added"); } @@ -382,7 +382,7 @@ benchmarks! { add_referendum::(i); } - assert_eq!(Democracy::::referendum_count(), r, "referenda not created"); + assert_eq!(ReferendumCount::::get(), r, "referenda not created"); // Launch external LastTabledWasExternal::::put(false); @@ -393,15 +393,15 @@ benchmarks! { let call = Call::::external_propose_majority { proposal }; call.dispatch_bypass_filter(origin)?; // External proposal created - ensure!(>::exists(), "External proposal didn't work"); + ensure!(NextExternal::::exists(), "External proposal didn't work"); let block_number = T::LaunchPeriod::get(); }: { Democracy::::on_initialize(block_number) } verify { // One extra because of next external - assert_eq!(Democracy::::referendum_count(), r + 1, "referenda not created"); - ensure!(!>::exists(), "External wasn't taken"); + assert_eq!(ReferendumCount::::get(), r + 1, "referenda not created"); + ensure!(!NextExternal::::exists(), "External wasn't taken"); // All but the new next external should be finished for i in 0 .. r { @@ -422,7 +422,7 @@ benchmarks! { add_referendum::(i); } - assert_eq!(Democracy::::referendum_count(), r, "referenda not created"); + assert_eq!(ReferendumCount::::get(), r, "referenda not created"); // Launch public assert!(add_proposal::(r).is_ok(), "proposal not created"); @@ -433,7 +433,7 @@ benchmarks! { }: { Democracy::::on_initialize(block_number) } verify { // One extra because of next public - assert_eq!(Democracy::::referendum_count(), r + 1, "proposal not accepted"); + assert_eq!(ReferendumCount::::get(), r + 1, "proposal not accepted"); // All should be finished for i in 0 .. r { @@ -461,8 +461,8 @@ benchmarks! { ReferendumInfoOf::::insert(key, info); } - assert_eq!(Democracy::::referendum_count(), r, "referenda not created"); - assert_eq!(Democracy::::lowest_unbaked(), 0, "invalid referenda init"); + assert_eq!(ReferendumCount::::get(), r, "referenda not created"); + assert_eq!(LowestUnbaked::::get(), 0, "invalid referenda init"); }: { Democracy::::on_initialize(1u32.into()) } verify { @@ -491,8 +491,8 @@ benchmarks! { ReferendumInfoOf::::insert(key, info); } - assert_eq!(Democracy::::referendum_count(), r, "referenda not created"); - assert_eq!(Democracy::::lowest_unbaked(), 0, "invalid referenda init"); + assert_eq!(ReferendumCount::::get(), r, "referenda not created"); + assert_eq!(LowestUnbaked::::get(), 0, "invalid referenda init"); let block_number = T::LaunchPeriod::get(); diff --git a/substrate/frame/democracy/src/lib.rs b/substrate/frame/democracy/src/lib.rs index f3d33a72f3ad1a088d4dc050d1e637acd162db7d..19cdc754659d34b08b3c149e5766ea7bb6c01219 100644 --- a/substrate/frame/democracy/src/lib.rs +++ b/substrate/frame/democracy/src/lib.rs @@ -346,12 +346,10 @@ pub mod pallet { /// The number of (public) proposals that have been made so far. #[pallet::storage] - #[pallet::getter(fn public_prop_count)] pub type PublicPropCount = StorageValue<_, PropIndex, ValueQuery>; /// The public proposals. Unsorted. The second item is the proposal. #[pallet::storage] - #[pallet::getter(fn public_props)] pub type PublicProps = StorageValue< _, BoundedVec<(PropIndex, BoundedCallOf, T::AccountId), T::MaxProposals>, @@ -362,7 +360,6 @@ pub mod pallet { /// /// TWOX-NOTE: Safe, as increasing integer keys are safe. #[pallet::storage] - #[pallet::getter(fn deposit_of)] pub type DepositOf = StorageMap< _, Twox64Concat, @@ -372,20 +369,17 @@ pub mod pallet { /// The next free referendum index, aka the number of referenda started so far. #[pallet::storage] - #[pallet::getter(fn referendum_count)] pub type ReferendumCount = StorageValue<_, ReferendumIndex, ValueQuery>; /// The lowest referendum index representing an unbaked referendum. Equal to /// `ReferendumCount` if there isn't a unbaked referendum. #[pallet::storage] - #[pallet::getter(fn lowest_unbaked)] pub type LowestUnbaked = StorageValue<_, ReferendumIndex, ValueQuery>; /// Information concerning any given referendum. /// /// TWOX-NOTE: SAFE as indexes are not under an attacker’s control. #[pallet::storage] - #[pallet::getter(fn referendum_info)] pub type ReferendumInfoOf = StorageMap< _, Twox64Concat, @@ -595,15 +589,15 @@ pub mod pallet { let who = T::SubmitOrigin::ensure_origin(origin)?; ensure!(value >= T::MinimumDeposit::get(), Error::::ValueLow); - let index = Self::public_prop_count(); + let index = PublicPropCount::::get(); let real_prop_count = PublicProps::::decode_len().unwrap_or(0) as u32; let max_proposals = T::MaxProposals::get(); ensure!(real_prop_count < max_proposals, Error::::TooMany); let proposal_hash = proposal.hash(); - if let Some((until, _)) = >::get(proposal_hash) { + if let Some((until, _)) = Blacklist::::get(proposal_hash) { ensure!( - >::block_number() >= until, + frame_system::Pallet::::block_number() >= until, Error::::ProposalBlacklisted, ); } @@ -638,11 +632,11 @@ pub mod pallet { let seconds = Self::len_of_deposit_of(proposal).ok_or(Error::::ProposalMissing)?; ensure!(seconds < T::MaxDeposits::get(), Error::::TooMany); - let mut deposit = Self::deposit_of(proposal).ok_or(Error::::ProposalMissing)?; + let mut deposit = DepositOf::::get(proposal).ok_or(Error::::ProposalMissing)?; T::Currency::reserve(&who, deposit.1)?; let ok = deposit.0.try_push(who.clone()).is_ok(); debug_assert!(ok, "`seconds` is below static limit; `try_insert` should succeed; qed"); - >::insert(proposal, deposit); + DepositOf::::insert(proposal, deposit); Self::deposit_event(Event::::Seconded { seconder: who, prop_index: proposal }); Ok(()) } @@ -683,9 +677,9 @@ pub mod pallet { let status = Self::referendum_status(ref_index)?; let h = status.proposal.hash(); - ensure!(!>::contains_key(h), Error::::AlreadyCanceled); + ensure!(!Cancellations::::contains_key(h), Error::::AlreadyCanceled); - >::insert(h, true); + Cancellations::::insert(h, true); Self::internal_cancel_referendum(ref_index); Ok(()) } @@ -703,14 +697,14 @@ pub mod pallet { proposal: BoundedCallOf, ) -> DispatchResult { T::ExternalOrigin::ensure_origin(origin)?; - ensure!(!>::exists(), Error::::DuplicateProposal); - if let Some((until, _)) = >::get(proposal.hash()) { + ensure!(!NextExternal::::exists(), Error::::DuplicateProposal); + if let Some((until, _)) = Blacklist::::get(proposal.hash()) { ensure!( - >::block_number() >= until, + frame_system::Pallet::::block_number() >= until, Error::::ProposalBlacklisted, ); } - >::put((proposal, VoteThreshold::SuperMajorityApprove)); + NextExternal::::put((proposal, VoteThreshold::SuperMajorityApprove)); Ok(()) } @@ -732,7 +726,7 @@ pub mod pallet { proposal: BoundedCallOf, ) -> DispatchResult { T::ExternalMajorityOrigin::ensure_origin(origin)?; - >::put((proposal, VoteThreshold::SimpleMajority)); + NextExternal::::put((proposal, VoteThreshold::SimpleMajority)); Ok(()) } @@ -754,7 +748,7 @@ pub mod pallet { proposal: BoundedCallOf, ) -> DispatchResult { T::ExternalDefaultOrigin::ensure_origin(origin)?; - >::put((proposal, VoteThreshold::SuperMajorityAgainst)); + NextExternal::::put((proposal, VoteThreshold::SuperMajorityAgainst)); Ok(()) } @@ -800,15 +794,15 @@ pub mod pallet { ensure!(voting_period > Zero::zero(), Error::::VotingPeriodLow); let (ext_proposal, threshold) = - >::get().ok_or(Error::::ProposalMissing)?; + NextExternal::::get().ok_or(Error::::ProposalMissing)?; ensure!( threshold != VoteThreshold::SuperMajorityApprove, Error::::NotSimpleMajority, ); ensure!(proposal_hash == ext_proposal.hash(), Error::::InvalidHash); - >::kill(); - let now = >::block_number(); + NextExternal::::kill(); + let now = frame_system::Pallet::::block_number(); let ref_index = Self::inject_referendum( now.saturating_add(voting_period), ext_proposal, @@ -840,7 +834,7 @@ pub mod pallet { } let mut existing_vetoers = - >::get(&proposal_hash).map(|pair| pair.1).unwrap_or_default(); + Blacklist::::get(&proposal_hash).map(|pair| pair.1).unwrap_or_default(); let insert_position = existing_vetoers.binary_search(&who).err().ok_or(Error::::AlreadyVetoed)?; existing_vetoers @@ -848,11 +842,11 @@ pub mod pallet { .map_err(|_| Error::::TooMany)?; let until = - >::block_number().saturating_add(T::CooloffPeriod::get()); - >::insert(&proposal_hash, (until, existing_vetoers)); + frame_system::Pallet::::block_number().saturating_add(T::CooloffPeriod::get()); + Blacklist::::insert(&proposal_hash, (until, existing_vetoers)); Self::deposit_event(Event::::Vetoed { who, proposal_hash, until }); - >::kill(); + NextExternal::::kill(); Self::clear_metadata(MetadataOwner::External); Ok(()) } @@ -943,7 +937,7 @@ pub mod pallet { #[pallet::weight(T::WeightInfo::clear_public_proposals())] pub fn clear_public_proposals(origin: OriginFor) -> DispatchResult { ensure_root(origin)?; - >::kill(); + PublicProps::::kill(); Ok(()) } @@ -1146,7 +1140,7 @@ pub mod pallet { ) -> DispatchResult { match owner { MetadataOwner::External => { - let (_, threshold) = >::get().ok_or(Error::::NoProposal)?; + let (_, threshold) = NextExternal::::get().ok_or(Error::::NoProposal)?; Self::ensure_external_origin(threshold, origin)?; }, MetadataOwner::Proposal(index) => { @@ -1201,7 +1195,7 @@ impl Pallet { /// Get the amount locked in support of `proposal`; `None` if proposal isn't a valid proposal /// index. pub fn backing_for(proposal: PropIndex) -> Option> { - Self::deposit_of(proposal).map(|(l, d)| d.saturating_mul((l.len() as u32).into())) + DepositOf::::get(proposal).map(|(l, d)| d.saturating_mul((l.len() as u32).into())) } /// Get all referenda ready for tally at block `n`. @@ -1209,8 +1203,8 @@ impl Pallet { n: BlockNumberFor, ) -> Vec<(ReferendumIndex, ReferendumStatus, BoundedCallOf, BalanceOf>)> { - let next = Self::lowest_unbaked(); - let last = Self::referendum_count(); + let next = LowestUnbaked::::get(); + let last = ReferendumCount::::get(); Self::maturing_referenda_at_inner(n, next..last) } @@ -1221,7 +1215,7 @@ impl Pallet { { range .into_iter() - .map(|i| (i, Self::referendum_info(i))) + .map(|i| (i, ReferendumInfoOf::::get(i))) .filter_map(|(i, maybe_info)| match maybe_info { Some(ReferendumInfo::Ongoing(status)) => Some((i, status)), _ => None, @@ -1238,8 +1232,8 @@ impl Pallet { threshold: VoteThreshold, delay: BlockNumberFor, ) -> ReferendumIndex { - >::inject_referendum( - >::block_number().saturating_add(T::VotingPeriod::get()), + Pallet::::inject_referendum( + frame_system::Pallet::::block_number().saturating_add(T::VotingPeriod::get()), proposal, threshold, delay, @@ -1529,12 +1523,12 @@ impl Pallet { threshold: VoteThreshold, delay: BlockNumberFor, ) -> ReferendumIndex { - let ref_index = Self::referendum_count(); + let ref_index = ReferendumCount::::get(); ReferendumCount::::put(ref_index + 1); let status = ReferendumStatus { end, proposal, threshold, delay, tally: Default::default() }; let item = ReferendumInfo::Ongoing(status); - >::insert(ref_index, item); + ReferendumInfoOf::::insert(ref_index, item); Self::deposit_event(Event::::Started { ref_index, threshold }); ref_index } @@ -1551,7 +1545,7 @@ impl Pallet { /// Table the waiting external proposal for a vote, if there is one. fn launch_external(now: BlockNumberFor) -> DispatchResult { - if let Some((proposal, threshold)) = >::take() { + if let Some((proposal, threshold)) = NextExternal::::take() { LastTabledWasExternal::::put(true); Self::deposit_event(Event::::ExternalTabled); let ref_index = Self::inject_referendum( @@ -1569,15 +1563,15 @@ impl Pallet { /// Table the waiting public proposal with the highest backing for a vote. fn launch_public(now: BlockNumberFor) -> DispatchResult { - let mut public_props = Self::public_props(); + let mut public_props = PublicProps::::get(); if let Some((winner_index, _)) = public_props.iter().enumerate().max_by_key( // defensive only: All current public proposals have an amount locked |x| Self::backing_for((x.1).0).defensive_unwrap_or_else(Zero::zero), ) { let (prop_index, proposal, _) = public_props.swap_remove(winner_index); - >::put(public_props); + PublicProps::::put(public_props); - if let Some((depositors, deposit)) = >::take(prop_index) { + if let Some((depositors, deposit)) = DepositOf::::take(prop_index) { // refund depositors for d in depositors.iter() { T::Currency::unreserve(d, deposit); @@ -1642,8 +1636,8 @@ impl Pallet { let max_block_weight = T::BlockWeights::get().max_block; let mut weight = Weight::zero(); - let next = Self::lowest_unbaked(); - let last = Self::referendum_count(); + let next = LowestUnbaked::::get(); + let last = ReferendumCount::::get(); let r = last.saturating_sub(next); // pick out another public referendum if it's time. @@ -1674,9 +1668,9 @@ impl Pallet { // * We shouldn't iterate more than `LaunchPeriod/VotingPeriod + 1` times because the number // of unbaked referendum is bounded by this number. In case those number have changed in a // runtime upgrade the formula should be adjusted but the bound should still be sensible. - >::mutate(|ref_index| { + LowestUnbaked::::mutate(|ref_index| { while *ref_index < last && - Self::referendum_info(*ref_index) + ReferendumInfoOf::::get(*ref_index) .map_or(true, |info| matches!(info, ReferendumInfo::Finished { .. })) { *ref_index += 1 @@ -1692,7 +1686,7 @@ impl Pallet { fn len_of_deposit_of(proposal: PropIndex) -> Option { // DepositOf first tuple element is a vec, decoding its len is equivalent to decode a // `Compact`. - decode_compact_u32_at(&>::hashed_key_for(proposal)) + decode_compact_u32_at(&DepositOf::::hashed_key_for(proposal)) } /// Return a proposal of an index. diff --git a/substrate/frame/democracy/src/migrations/v1.rs b/substrate/frame/democracy/src/migrations/v1.rs index 5e423b9ab6eff7d2a96f94416bdd425827869fba..47f8df017f1e18d19289477936dc2a3c380f8e2c 100644 --- a/substrate/frame/democracy/src/migrations/v1.rs +++ b/substrate/frame/democracy/src/migrations/v1.rs @@ -108,7 +108,7 @@ pub mod v1 { .collect::>(); let bounded = BoundedVec::<_, T::MaxProposals>::truncate_from(props.clone()); PublicProps::::put(bounded); - weight.saturating_accrue(T::DbWeight::get().reads_writes(1, 1)); + weight.saturating_accrue(T::DbWeight::get().reads_writes(1, 2)); if props.len() as u32 > T::MaxProposals::get() { log::error!( @@ -126,7 +126,7 @@ pub mod v1 { StorageVersion::new(1).put::>(); - weight.saturating_add(T::DbWeight::get().reads_writes(1, 2)) + weight.saturating_add(T::DbWeight::get().reads_writes(1, 3)) } #[cfg(feature = "try-runtime")] diff --git a/substrate/frame/democracy/src/tests.rs b/substrate/frame/democracy/src/tests.rs index e2946ba98156ad3480f85ae4e86ba4a2036ff59c..9303c0da504f366288f6f06cb33c54abbd125321 100644 --- a/substrate/frame/democracy/src/tests.rs +++ b/substrate/frame/democracy/src/tests.rs @@ -194,7 +194,7 @@ pub fn new_test_ext() -> sp_io::TestExternalities { #[test] fn params_should_work() { new_test_ext().execute_with(|| { - assert_eq!(Democracy::referendum_count(), 0); + assert_eq!(ReferendumCount::::get(), 0); assert_eq!(Balances::free_balance(42), 0); assert_eq!(Balances::total_issuance(), 210); }); diff --git a/substrate/frame/democracy/src/tests/cancellation.rs b/substrate/frame/democracy/src/tests/cancellation.rs index b4c42f9c79053ad6db1641e7e431dc4be7661e9f..eeb1df301db8ffda60e349bb7dd2fa7c673b4be4 100644 --- a/substrate/frame/democracy/src/tests/cancellation.rs +++ b/substrate/frame/democracy/src/tests/cancellation.rs @@ -30,14 +30,14 @@ fn cancel_referendum_should_work() { ); assert_ok!(Democracy::vote(RuntimeOrigin::signed(1), r, aye(1))); assert_ok!(Democracy::cancel_referendum(RuntimeOrigin::root(), r.into())); - assert_eq!(Democracy::lowest_unbaked(), 0); + assert_eq!(LowestUnbaked::::get(), 0); next_block(); next_block(); - assert_eq!(Democracy::lowest_unbaked(), 1); - assert_eq!(Democracy::lowest_unbaked(), Democracy::referendum_count()); + assert_eq!(LowestUnbaked::::get(), 1); + assert_eq!(LowestUnbaked::::get(), ReferendumCount::::get()); assert_eq!(Balances::free_balance(42), 0); }); } @@ -56,7 +56,7 @@ fn emergency_cancel_should_work() { assert_noop!(Democracy::emergency_cancel(RuntimeOrigin::signed(3), r), BadOrigin); assert_ok!(Democracy::emergency_cancel(RuntimeOrigin::signed(4), r)); - assert!(Democracy::referendum_info(r).is_none()); + assert!(ReferendumInfoOf::::get(r).is_none()); // some time later... diff --git a/substrate/frame/democracy/src/tests/external_proposing.rs b/substrate/frame/democracy/src/tests/external_proposing.rs index 08b497ab4b90e6ce458b7462c521b0d9d6d78640..78ef2904e5b6c29bf78f594ac3ffaff5c00c1c2a 100644 --- a/substrate/frame/democracy/src/tests/external_proposing.rs +++ b/substrate/frame/democracy/src/tests/external_proposing.rs @@ -24,12 +24,12 @@ fn veto_external_works() { new_test_ext().execute_with(|| { System::set_block_number(0); assert_ok!(Democracy::external_propose(RuntimeOrigin::signed(2), set_balance_proposal(2),)); - assert!(>::exists()); + assert!(NextExternal::::exists()); let h = set_balance_proposal(2).hash(); assert_ok!(Democracy::veto_external(RuntimeOrigin::signed(3), h)); // cancelled. - assert!(!>::exists()); + assert!(!NextExternal::::exists()); // fails - same proposal can't be resubmitted. assert_noop!( Democracy::external_propose(RuntimeOrigin::signed(2), set_balance_proposal(2),), @@ -46,7 +46,7 @@ fn veto_external_works() { fast_forward_to(2); // works; as we're out of the cooloff period. assert_ok!(Democracy::external_propose(RuntimeOrigin::signed(2), set_balance_proposal(2),)); - assert!(>::exists()); + assert!(NextExternal::::exists()); // 3 can't veto the same thing twice. assert_noop!( @@ -57,7 +57,7 @@ fn veto_external_works() { // 4 vetoes. assert_ok!(Democracy::veto_external(RuntimeOrigin::signed(4), h)); // cancelled again. - assert!(!>::exists()); + assert!(!NextExternal::::exists()); fast_forward_to(3); // same proposal fails as we're still in cooloff diff --git a/substrate/frame/democracy/src/tests/fast_tracking.rs b/substrate/frame/democracy/src/tests/fast_tracking.rs index 85e7792a4c2edf3728f2b0215fe94fc0dc3efdbb..89dce1dffe13eb5f950ee874d0366af3983f24a9 100644 --- a/substrate/frame/democracy/src/tests/fast_tracking.rs +++ b/substrate/frame/democracy/src/tests/fast_tracking.rs @@ -33,13 +33,13 @@ fn fast_track_referendum_works() { set_balance_proposal(2) )); let hash = note_preimage(1); - assert!(>::get(MetadataOwner::External).is_none()); + assert!(MetadataOf::::get(MetadataOwner::External).is_none()); assert_ok!(Democracy::set_metadata( RuntimeOrigin::signed(3), MetadataOwner::External, Some(hash), ),); - assert!(>::get(MetadataOwner::External).is_some()); + assert!(MetadataOf::::get(MetadataOwner::External).is_some()); assert_noop!(Democracy::fast_track(RuntimeOrigin::signed(1), h, 3, 2), BadOrigin); assert_ok!(Democracy::fast_track(RuntimeOrigin::signed(5), h, 2, 0)); assert_eq!( @@ -53,8 +53,8 @@ fn fast_track_referendum_works() { }) ); // metadata reset from the external proposal to the referendum. - assert!(>::get(MetadataOwner::External).is_none()); - assert!(>::get(MetadataOwner::Referendum(0)).is_some()); + assert!(MetadataOf::::get(MetadataOwner::External).is_none()); + assert!(MetadataOf::::get(MetadataOwner::Referendum(0)).is_some()); }); } diff --git a/substrate/frame/democracy/src/tests/metadata.rs b/substrate/frame/democracy/src/tests/metadata.rs index 1b6d66a8bc4486c555a5f0e1241f76280b33eeb7..341f14e5586bf9e0e3191eb8dbf87f1515739636 100644 --- a/substrate/frame/democracy/src/tests/metadata.rs +++ b/substrate/frame/democracy/src/tests/metadata.rs @@ -33,7 +33,7 @@ fn set_external_metadata_works() { ); // create an external proposal. assert_ok!(Democracy::external_propose(RuntimeOrigin::signed(2), set_balance_proposal(2))); - assert!(>::exists()); + assert!(NextExternal::::exists()); // fails to set metadata with non external origin. assert_noop!( Democracy::set_metadata(RuntimeOrigin::signed(1), owner.clone(), Some(invalid_hash)), @@ -61,7 +61,7 @@ fn clear_metadata_works() { let owner = MetadataOwner::External; // create an external proposal. assert_ok!(Democracy::external_propose(RuntimeOrigin::signed(2), set_balance_proposal(2))); - assert!(>::exists()); + assert!(NextExternal::::exists()); // set metadata. let hash = note_preimage(1); assert_ok!(Democracy::set_metadata(RuntimeOrigin::signed(2), owner.clone(), Some(hash))); @@ -87,7 +87,7 @@ fn set_proposal_metadata_works() { // create an external proposal. assert_ok!(propose_set_balance(1, 2, 5)); // metadata owner is a public proposal. - let owner = MetadataOwner::Proposal(Democracy::public_prop_count() - 1); + let owner = MetadataOwner::Proposal(PublicPropCount::::get() - 1); // fails to set non-existing preimage. assert_noop!( Democracy::set_metadata(RuntimeOrigin::signed(1), owner.clone(), Some(invalid_hash)), @@ -115,7 +115,7 @@ fn clear_proposal_metadata_works() { // create an external proposal. assert_ok!(propose_set_balance(1, 2, 5)); // metadata owner is a public proposal. - let owner = MetadataOwner::Proposal(Democracy::public_prop_count() - 1); + let owner = MetadataOwner::Proposal(PublicPropCount::::get() - 1); // set metadata. let hash = note_preimage(1); assert_ok!(Democracy::set_metadata(RuntimeOrigin::signed(1), owner.clone(), Some(hash))); diff --git a/substrate/frame/democracy/src/tests/public_proposals.rs b/substrate/frame/democracy/src/tests/public_proposals.rs index 69a2d3e25686f6a17337ff78c81d3c69a13ac345..01f47947f8e50e9be8fbcb9072b861fdf84f923e 100644 --- a/substrate/frame/democracy/src/tests/public_proposals.rs +++ b/substrate/frame/democracy/src/tests/public_proposals.rs @@ -97,10 +97,10 @@ fn cancel_proposal_should_work() { MetadataOwner::Proposal(0), Some(hash) )); - assert!(>::get(MetadataOwner::Proposal(0)).is_some()); + assert!(MetadataOf::::get(MetadataOwner::Proposal(0)).is_some()); assert_ok!(Democracy::cancel_proposal(RuntimeOrigin::root(), 0)); // metadata cleared, preimage unrequested. - assert!(>::get(MetadataOwner::Proposal(0)).is_none()); + assert!(MetadataOf::::get(MetadataOwner::Proposal(0)).is_none()); System::assert_has_event(crate::Event::ProposalCanceled { prop_index: 0 }.into()); System::assert_last_event( crate::Event::MetadataCleared { owner: MetadataOwner::Proposal(0), hash }.into(), diff --git a/substrate/frame/democracy/src/tests/scheduling.rs b/substrate/frame/democracy/src/tests/scheduling.rs index fdbc8fdb34947ae1454355ebd4afd6493e7de992..43f51628aaf5e6929434185787ad481851628bd7 100644 --- a/substrate/frame/democracy/src/tests/scheduling.rs +++ b/substrate/frame/democracy/src/tests/scheduling.rs @@ -30,10 +30,10 @@ fn simple_passing_should_work() { ); assert_ok!(Democracy::vote(RuntimeOrigin::signed(1), r, aye(1))); assert_eq!(tally(r), Tally { ayes: 1, nays: 0, turnout: 10 }); - assert_eq!(Democracy::lowest_unbaked(), 0); + assert_eq!(LowestUnbaked::::get(), 0); next_block(); next_block(); - assert_eq!(Democracy::lowest_unbaked(), 1); + assert_eq!(LowestUnbaked::::get(), 1); assert_eq!(Balances::free_balance(42), 2); }); } @@ -140,16 +140,16 @@ fn lowest_unbaked_should_be_sensible() { assert_ok!(Democracy::vote(RuntimeOrigin::signed(1), r2, aye(1))); // r3 is canceled assert_ok!(Democracy::cancel_referendum(RuntimeOrigin::root(), r3.into())); - assert_eq!(Democracy::lowest_unbaked(), 0); + assert_eq!(LowestUnbaked::::get(), 0); next_block(); // r2 ends with approval - assert_eq!(Democracy::lowest_unbaked(), 0); + assert_eq!(LowestUnbaked::::get(), 0); next_block(); // r1 ends with approval - assert_eq!(Democracy::lowest_unbaked(), 3); - assert_eq!(Democracy::lowest_unbaked(), Democracy::referendum_count()); + assert_eq!(LowestUnbaked::::get(), 3); + assert_eq!(LowestUnbaked::::get(), ReferendumCount::::get()); // r2 is executed assert_eq!(Balances::free_balance(42), 2); diff --git a/substrate/frame/democracy/src/tests/voting.rs b/substrate/frame/democracy/src/tests/voting.rs index f096b633ee6d4a2b226dc5be0421523edb453de5..61b80cc97fed6ad458a1fcda01efe5bd89799ad4 100644 --- a/substrate/frame/democracy/src/tests/voting.rs +++ b/substrate/frame/democracy/src/tests/voting.rs @@ -65,13 +65,13 @@ fn single_proposal_should_work() { System::set_block_number(0); assert_ok!(propose_set_balance(1, 2, 1)); let r = 0; - assert!(Democracy::referendum_info(r).is_none()); + assert!(ReferendumInfoOf::::get(r).is_none()); // start of 2 => next referendum scheduled. fast_forward_to(2); assert_ok!(Democracy::vote(RuntimeOrigin::signed(1), r, aye(1))); - assert_eq!(Democracy::referendum_count(), 1); + assert_eq!(ReferendumCount::::get(), 1); assert_eq!( Democracy::referendum_status(0), Ok(ReferendumStatus { diff --git a/substrate/frame/election-provider-multi-phase/Cargo.toml b/substrate/frame/election-provider-multi-phase/Cargo.toml index 2074b51f50f475f077f814593da74b31b5dba6e0..43e3e7079d2fa78aa1e3515b41df87446ac5b370 100644 --- a/substrate/frame/election-provider-multi-phase/Cargo.toml +++ b/substrate/frame/election-provider-multi-phase/Cargo.toml @@ -15,7 +15,7 @@ workspace = true targets = ["x86_64-unknown-linux-gnu"] [dependencies] -codec = { package = "parity-scale-codec", version = "3.6.1", default-features = false, features = [ +codec = { package = "parity-scale-codec", version = "3.6.12", default-features = false, features = [ "derive", ] } scale-info = { version = "2.11.1", default-features = false, features = [ 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 25c280921f8c7c8d3660c52555ae5e67093c1a9b..fc696e04d689f706a4afa4459ea2b8f885ca22d4 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 @@ -17,7 +17,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dev-dependencies] parking_lot = "0.12.1" -codec = { package = "parity-scale-codec", version = "3.6.1", features = ["derive"] } +codec = { package = "parity-scale-codec", version = "3.6.12", features = ["derive"] } scale-info = { version = "2.11.1", features = ["derive"] } log = { workspace = true } 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 83083c912094bc4b39287f5105021fe2e44a4bb0..c00bb66ea13044f8b11aa781e30896e03225aea8 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 @@ -23,7 +23,6 @@ pub(crate) const LOG_TARGET: &str = "tests::e2e-epm"; use frame_support::{assert_err, assert_noop, assert_ok}; use mock::*; use sp_core::Get; -use sp_npos_elections::{to_supports, StakedAssignment}; use sp_runtime::Perbill; use crate::mock::RuntimeOrigin; @@ -127,75 +126,48 @@ fn offchainify_works() { } #[test] -/// Replicates the Kusama incident of 8th Dec 2022 and its resolution through the governance +/// Inspired by the Kusama incident of 8th Dec 2022 and its resolution through the governance /// fallback. /// -/// After enough slashes exceeded the `Staking::OffendingValidatorsThreshold`, the staking pallet -/// set `Forcing::ForceNew`. When a new session starts, staking will start to force a new era and -/// calls ::elect(). If at this point EPM and the staking miners did not -/// have enough time to queue a new solution (snapshot + solution submission), the election request -/// fails. If there is no election fallback mechanism in place, EPM enters in emergency mode. -/// Recovery: Once EPM is in emergency mode, subsequent calls to `elect()` will fail until a new -/// solution is added to EPM's `QueuedSolution` queue. This can be achieved through -/// `Call::set_emergency_election_result` or `Call::governance_fallback` dispatchables. Once a new -/// solution is added to the queue, EPM phase transitions to `Phase::Off` and the election flow -/// restarts. Note that in this test case, the emergency throttling is disabled. -fn enters_emergency_phase_after_forcing_before_elect() { +/// Mass slash of validators shouldn't disable more than 1/3 of them (the byzantine threshold). Also +/// no new era should be forced which could lead to EPM entering emergency mode. +fn mass_slash_doesnt_enter_emergency_phase() { let epm_builder = EpmExtBuilder::default().disable_emergency_throttling(); - let (ext, pool_state, _) = ExtBuilder::default().epm(epm_builder).build_offchainify(); - - execute_with(ext, || { - log!( - trace, - "current validators (staking): {:?}", - >::validators() - ); - let session_validators_before = Session::validators(); - - roll_to_epm_off(); - assert!(ElectionProviderMultiPhase::current_phase().is_off()); + let staking_builder = StakingExtBuilder::default().validator_count(7); + let (mut ext, _, _) = ExtBuilder::default() + .epm(epm_builder) + .staking(staking_builder) + .build_offchainify(); + ext.execute_with(|| { assert_eq!(pallet_staking::ForceEra::::get(), pallet_staking::Forcing::NotForcing); - // slashes so that staking goes into `Forcing::ForceNew`. - slash_through_offending_threshold(); - assert_eq!(pallet_staking::ForceEra::::get(), pallet_staking::Forcing::ForceNew); + let active_set_size_before_slash = Session::validators().len(); - advance_session_delayed_solution(pool_state.clone()); - assert!(ElectionProviderMultiPhase::current_phase().is_emergency()); - log_current_time(); + // Slash more than 1/3 of the active validators + let mut slashed = slash_half_the_active_set(); - let era_before_delayed_next = Staking::current_era(); - // try to advance 2 eras. - assert!(start_next_active_era_delayed_solution(pool_state.clone()).is_ok()); - assert_eq!(Staking::current_era(), era_before_delayed_next); - assert!(start_next_active_era(pool_state).is_err()); - assert_eq!(Staking::current_era(), era_before_delayed_next); + let active_set_size_after_slash = Session::validators().len(); - // EPM is still in emergency phase. - assert!(ElectionProviderMultiPhase::current_phase().is_emergency()); + // active set should stay the same before and after the slash + assert_eq!(active_set_size_before_slash, active_set_size_after_slash); - // session validator set remains the same. - assert_eq!(Session::validators(), session_validators_before); - - // performs recovery through the set emergency result. - let supports = to_supports(&vec![ - StakedAssignment { who: 21, distribution: vec![(21, 10)] }, - StakedAssignment { who: 31, distribution: vec![(21, 10), (31, 10)] }, - StakedAssignment { who: 41, distribution: vec![(41, 10)] }, - ]); - assert!(ElectionProviderMultiPhase::set_emergency_election_result( - RuntimeOrigin::root(), - supports - ) - .is_ok()); + // Slashed validators are disabled up to a limit + slashed.truncate( + pallet_staking::UpToLimitDisablingStrategy::::disable_limit( + active_set_size_after_slash, + ), + ); - // EPM can now roll to signed phase to proceed with elections. The validator set is the - // expected (ie. set through `set_emergency_election_result`). - roll_to_epm_signed(); - //assert!(ElectionProviderMultiPhase::current_phase().is_signed()); - assert_eq!(Session::validators(), vec![21, 31, 41]); - assert_eq!(Staking::current_era(), era_before_delayed_next.map(|e| e + 1)); + // Find the indices of the disabled validators + let active_set = Session::validators(); + let expected_disabled = slashed + .into_iter() + .map(|d| active_set.iter().position(|a| *a == d).unwrap() as u32) + .collect::>(); + + assert_eq!(pallet_staking::ForceEra::::get(), pallet_staking::Forcing::NotForcing); + assert_eq!(Session::disabled_validators(), expected_disabled); }); } @@ -253,77 +225,7 @@ fn continuous_slashes_below_offending_threshold() { } #[test] -/// Slashed validator sets intentions in the same era of slashing. -/// -/// When validators are slashed, they are chilled and removed from the current `VoterList`. Thus, -/// the slashed validator should not be considered in the next validator set. However, if the -/// slashed validator sets its intention to validate again in the same era when it was slashed and -/// chilled, the validator may not be removed from the active validator set across eras, provided -/// it would selected in the subsequent era if there was no slash. Nominators of the slashed -/// validator will also be slashed and chilled, as expected, but the nomination intentions will -/// remain after the validator re-set the intention to be validating again. -/// -/// This behaviour is due to removing implicit chill upon slash -/// . -/// -/// Related to . -fn set_validation_intention_after_chilled() { - use frame_election_provider_support::SortedListProvider; - use pallet_staking::{Event, Forcing, Nominators}; - - let (ext, pool_state, _) = ExtBuilder::default() - .epm(EpmExtBuilder::default()) - .staking(StakingExtBuilder::default()) - .build_offchainify(); - - execute_with(ext, || { - assert_eq!(active_era(), 0); - // validator is part of the validator set. - assert!(Session::validators().contains(&41)); - assert!(::VoterList::contains(&41)); - - // nominate validator 81. - assert_ok!(Staking::nominate(RuntimeOrigin::signed(21), vec![41])); - assert_eq!(Nominators::::get(21).unwrap().targets, vec![41]); - - // validator is slashed. it is removed from the `VoterList` through chilling but in the - // current era, the validator is still part of the active validator set. - add_slash(&41); - assert!(Session::validators().contains(&41)); - assert!(!::VoterList::contains(&41)); - assert_eq!( - staking_events(), - [ - Event::Chilled { stash: 41 }, - Event::ForceEra { mode: Forcing::ForceNew }, - Event::SlashReported { - validator: 41, - slash_era: 0, - fraction: Perbill::from_percent(10) - } - ], - ); - - // after the nominator is slashed and chilled, the nominations remain. - assert_eq!(Nominators::::get(21).unwrap().targets, vec![41]); - - // validator sets intention to stake again in the same era it was chilled. - assert_ok!(Staking::validate(RuntimeOrigin::signed(41), Default::default())); - - // progress era and check that the slashed validator is still part of the validator - // set. - assert!(start_next_active_era(pool_state).is_ok()); - assert_eq!(active_era(), 1); - assert!(Session::validators().contains(&41)); - assert!(::VoterList::contains(&41)); - - // nominations are still active as before the slash. - assert_eq!(Nominators::::get(21).unwrap().targets, vec![41]); - }) -} - -#[test] -/// Active ledger balance may fall below ED if account chills before unbonding. +/// Active ledger balance may fall below ED if account chills before unbounding. /// /// Unbonding call fails if the remaining ledger's stash balance falls below the existential /// deposit. However, if the stash is chilled before unbonding, the ledger's active balance may 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 a727e3bf816251495c2b5e9e32eb688e51c4e339..8f1775a7e5951ad1c9271f486a782b18fe5da900 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 @@ -35,7 +35,7 @@ use sp_runtime::{ transaction_validity, BuildStorage, PerU16, Perbill, Percent, }; use sp_staking::{ - offence::{DisableStrategy, OffenceDetails, OnOffenceHandler}, + offence::{OffenceDetails, OnOffenceHandler}, EraIndex, SessionIndex, }; use sp_std::prelude::*; @@ -236,7 +236,6 @@ parameter_types! { pub const SessionsPerEra: sp_staking::SessionIndex = 2; 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; } @@ -290,6 +289,8 @@ parameter_types! { /// Upper limit on the number of NPOS nominations. const MAX_QUOTA_NOMINATIONS: u32 = 16; +/// Disabling factor set explicitly to byzantine threshold +pub(crate) const SLASHING_DISABLING_FACTOR: usize = 3; impl pallet_staking::Config for Runtime { type Currency = Balances; @@ -308,7 +309,6 @@ impl pallet_staking::Config for Runtime { type EraPayout = (); type NextNewSession = Session; type MaxExposurePageSize = ConstU32<256>; - type OffendingValidatorsThreshold = OffendingValidatorsThreshold; type ElectionProvider = ElectionProviderMultiPhase; type GenesisElectionProvider = onchain::OnChainExecution; type VoterList = BagsList; @@ -320,6 +320,7 @@ impl pallet_staking::Config for Runtime { type EventListeners = Pools; type WeightInfo = pallet_staking::weights::SubstrateWeight; type BenchmarkingConfig = pallet_staking::TestBenchmarkingConfig; + type DisablingStrategy = pallet_staking::UpToLimitDisablingStrategy; } impl frame_system::offchain::SendTransactionTypes for Runtime @@ -871,7 +872,6 @@ pub(crate) fn on_offence_now( offenders, slash_fraction, Staking::eras_start_session_index(now).unwrap(), - DisableStrategy::WhenSlashed, ); } @@ -886,19 +886,16 @@ pub(crate) fn add_slash(who: &AccountId) { ); } -// Slashes enough validators to cross the `Staking::OffendingValidatorsThreshold`. -pub(crate) fn slash_through_offending_threshold() { - let validators = Session::validators(); - let mut remaining_slashes = - ::OffendingValidatorsThreshold::get() * - validators.len() as u32; +// Slashes 1/2 of the active set. Returns the `AccountId`s of the slashed validators. +pub(crate) fn slash_half_the_active_set() -> Vec { + let mut slashed = Session::validators(); + slashed.truncate(slashed.len() / 2); - for v in validators.into_iter() { - if remaining_slashes != 0 { - add_slash(&v); - remaining_slashes -= 1; - } + for v in slashed.iter() { + add_slash(v); } + + slashed } // Slashes a percentage of the active nominators that haven't been slashed yet, with diff --git a/substrate/frame/election-provider-support/Cargo.toml b/substrate/frame/election-provider-support/Cargo.toml index 0d9748ee34e56fa5d43f0e238d2d69eda548eaec..1c63f90720f7b010fb584dc44f2e84ad78c61021 100644 --- a/substrate/frame/election-provider-support/Cargo.toml +++ b/substrate/frame/election-provider-support/Cargo.toml @@ -15,7 +15,7 @@ workspace = true targets = ["x86_64-unknown-linux-gnu"] [dependencies] -codec = { package = "parity-scale-codec", version = "3.6.1", default-features = false, features = ["derive"] } +codec = { package = "parity-scale-codec", version = "3.6.12", default-features = false, features = ["derive"] } scale-info = { version = "2.11.1", default-features = false, features = ["derive"] } frame-election-provider-solution-type = { path = "solution-type" } frame-support = { path = "../support", default-features = false } diff --git a/substrate/frame/election-provider-support/benchmarking/Cargo.toml b/substrate/frame/election-provider-support/benchmarking/Cargo.toml index 6e13f17bec1bbf237914df6baffdc2ede46c05f9..c2e644cfefab99145b839bf1c57917369a5f5cb2 100644 --- a/substrate/frame/election-provider-support/benchmarking/Cargo.toml +++ b/substrate/frame/election-provider-support/benchmarking/Cargo.toml @@ -15,7 +15,7 @@ workspace = true targets = ["x86_64-unknown-linux-gnu"] [dependencies] -codec = { package = "parity-scale-codec", version = "3.6.1", default-features = false, features = [ +codec = { package = "parity-scale-codec", version = "3.6.12", default-features = false, features = [ "derive", ] } frame-benchmarking = { path = "../../benchmarking", default-features = false, optional = true } diff --git a/substrate/frame/election-provider-support/benchmarking/src/inner.rs b/substrate/frame/election-provider-support/benchmarking/src/inner.rs new file mode 100644 index 0000000000000000000000000000000000000000..4722680cfcc1cb9131f55d6002b666b28fb3d2ae --- /dev/null +++ b/substrate/frame/election-provider-support/benchmarking/src/inner.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. + +//! Election provider support pallet benchmarking. +//! This is separated into its own crate to avoid bloating the size of the runtime. + +use codec::Decode; +use frame_benchmarking::v1::benchmarks; +use frame_election_provider_support::{NposSolver, PhragMMS, SequentialPhragmen}; +use sp_std::vec::Vec; + +pub struct Pallet(frame_system::Pallet); +pub trait Config: frame_system::Config {} + +const VOTERS: [u32; 2] = [1_000, 2_000]; +const TARGETS: [u32; 2] = [500, 1_000]; +const VOTES_PER_VOTER: [u32; 2] = [5, 16]; + +const SEED: u32 = 999; +fn set_up_voters_targets( + voters_len: u32, + targets_len: u32, + degree: usize, +) -> (Vec<(AccountId, u64, impl IntoIterator)>, Vec) { + // fill targets. + let mut targets = (0..targets_len) + .map(|i| frame_benchmarking::account::("Target", i, SEED)) + .collect::>(); + assert!(targets.len() > degree, "we should always have enough voters to fill"); + targets.truncate(degree); + + // fill voters. + let voters = (0..voters_len) + .map(|i| { + let voter = frame_benchmarking::account::("Voter", i, SEED); + (voter, 1_000, targets.clone()) + }) + .collect::>(); + + (voters, targets) +} + +benchmarks! { + phragmen { + // number of votes in snapshot. + let v in (VOTERS[0]) .. VOTERS[1]; + // number of targets in snapshot. + let t in (TARGETS[0]) .. TARGETS[1]; + // number of votes per voter (ie the degree). + let d in (VOTES_PER_VOTER[0]) .. VOTES_PER_VOTER[1]; + + let (voters, targets) = set_up_voters_targets::(v, t, d as usize); + }: { + assert!( + SequentialPhragmen:: + ::solve(d as usize, targets, voters).is_ok() + ); + } + + phragmms { + // number of votes in snapshot. + let v in (VOTERS[0]) .. VOTERS[1]; + // number of targets in snapshot. + let t in (TARGETS[0]) .. TARGETS[1]; + // number of votes per voter (ie the degree). + let d in (VOTES_PER_VOTER[0]) .. VOTES_PER_VOTER[1]; + + let (voters, targets) = set_up_voters_targets::(v, t, d as usize); + }: { + assert!( + PhragMMS:: + ::solve(d as usize, targets, voters).is_ok() + ); + } +} diff --git a/substrate/frame/election-provider-support/benchmarking/src/lib.rs b/substrate/frame/election-provider-support/benchmarking/src/lib.rs index 6c75aed0a911d3c66802951f0387ba675f8cfdba..78b226e52af6c2cec67706acb67dee280b818af3 100644 --- a/substrate/frame/election-provider-support/benchmarking/src/lib.rs +++ b/substrate/frame/election-provider-support/benchmarking/src/lib.rs @@ -16,77 +16,11 @@ // limitations under the License. //! Election provider support pallet benchmarking. -//! This is separated into its own crate to avoid bloating the size of the runtime. -#![cfg(feature = "runtime-benchmarks")] #![cfg_attr(not(feature = "std"), no_std)] -use codec::Decode; -use frame_benchmarking::v1::benchmarks; -use frame_election_provider_support::{NposSolver, PhragMMS, SequentialPhragmen}; -use sp_std::vec::Vec; +#[cfg(feature = "runtime-benchmarks")] +pub mod inner; -pub struct Pallet(frame_system::Pallet); -pub trait Config: frame_system::Config {} - -const VOTERS: [u32; 2] = [1_000, 2_000]; -const TARGETS: [u32; 2] = [500, 1_000]; -const VOTES_PER_VOTER: [u32; 2] = [5, 16]; - -const SEED: u32 = 999; -fn set_up_voters_targets( - voters_len: u32, - targets_len: u32, - degree: usize, -) -> (Vec<(AccountId, u64, impl IntoIterator)>, Vec) { - // fill targets. - let mut targets = (0..targets_len) - .map(|i| frame_benchmarking::account::("Target", i, SEED)) - .collect::>(); - assert!(targets.len() > degree, "we should always have enough voters to fill"); - targets.truncate(degree); - - // fill voters. - let voters = (0..voters_len) - .map(|i| { - let voter = frame_benchmarking::account::("Voter", i, SEED); - (voter, 1_000, targets.clone()) - }) - .collect::>(); - - (voters, targets) -} - -benchmarks! { - phragmen { - // number of votes in snapshot. - let v in (VOTERS[0]) .. VOTERS[1]; - // number of targets in snapshot. - let t in (TARGETS[0]) .. TARGETS[1]; - // number of votes per voter (ie the degree). - let d in (VOTES_PER_VOTER[0]) .. VOTES_PER_VOTER[1]; - - let (voters, targets) = set_up_voters_targets::(v, t, d as usize); - }: { - assert!( - SequentialPhragmen:: - ::solve(d as usize, targets, voters).is_ok() - ); - } - - phragmms { - // number of votes in snapshot. - let v in (VOTERS[0]) .. VOTERS[1]; - // number of targets in snapshot. - let t in (TARGETS[0]) .. TARGETS[1]; - // number of votes per voter (ie the degree). - let d in (VOTES_PER_VOTER[0]) .. VOTES_PER_VOTER[1]; - - let (voters, targets) = set_up_voters_targets::(v, t, d as usize); - }: { - assert!( - PhragMMS:: - ::solve(d as usize, targets, voters).is_ok() - ); - } -} +#[cfg(feature = "runtime-benchmarks")] +pub use inner::*; diff --git a/substrate/frame/election-provider-support/solution-type/Cargo.toml b/substrate/frame/election-provider-support/solution-type/Cargo.toml index 09c6a492dd0d6ba498111fc2c8926212e7b35fc2..3f8893dad6f2094ae75dec2e6e9de00d0b091495 100644 --- a/substrate/frame/election-provider-support/solution-type/Cargo.toml +++ b/substrate/frame/election-provider-support/solution-type/Cargo.toml @@ -24,7 +24,7 @@ proc-macro2 = "1.0.56" proc-macro-crate = "3.0.0" [dev-dependencies] -parity-scale-codec = "3.6.1" +parity-scale-codec = "3.6.12" scale-info = "2.11.1" sp-arithmetic = { path = "../../../primitives/arithmetic" } # used by generate_solution_type: 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 1fb9e2387ed8de1be004faf876315c21eeac9696..98da507384fd956e21a01cf075556bbe0b6b916b 100644 --- a/substrate/frame/election-provider-support/solution-type/fuzzer/Cargo.toml +++ b/substrate/frame/election-provider-support/solution-type/fuzzer/Cargo.toml @@ -20,7 +20,7 @@ clap = { version = "4.5.3", features = ["derive"] } honggfuzz = "0.5" rand = { version = "0.8", features = ["small_rng", "std"] } -codec = { package = "parity-scale-codec", version = "3.6.1", default-features = false, features = ["derive"] } +codec = { package = "parity-scale-codec", version = "3.6.12", default-features = false, features = ["derive"] } scale-info = { version = "2.11.1", default-features = false, features = ["derive"] } frame-election-provider-solution-type = { path = ".." } frame-election-provider-support = { path = "../.." } diff --git a/substrate/frame/elections-phragmen/Cargo.toml b/substrate/frame/elections-phragmen/Cargo.toml index 81dc48476a065b60e41ce6f703317b77ae75b0fe..dbcb740518b1379f54cd4265973b445f53109b7b 100644 --- a/substrate/frame/elections-phragmen/Cargo.toml +++ b/substrate/frame/elections-phragmen/Cargo.toml @@ -16,7 +16,7 @@ workspace = true targets = ["x86_64-unknown-linux-gnu"] [dependencies] -codec = { package = "parity-scale-codec", version = "3.6.1", default-features = false, features = [ +codec = { package = "parity-scale-codec", version = "3.6.12", default-features = false, features = [ "derive", ] } log = { workspace = true } diff --git a/substrate/frame/examples/basic/Cargo.toml b/substrate/frame/examples/basic/Cargo.toml index 43b37c6beba2c6c2545c4b6bc5191e40009065fa..ba9f9eca27d79c854dd67a8d81130062f3d1f70d 100644 --- a/substrate/frame/examples/basic/Cargo.toml +++ b/substrate/frame/examples/basic/Cargo.toml @@ -16,7 +16,7 @@ workspace = true targets = ["x86_64-unknown-linux-gnu"] [dependencies] -codec = { package = "parity-scale-codec", version = "3.6.1", default-features = false } +codec = { package = "parity-scale-codec", version = "3.6.12", default-features = false } log = { workspace = true } scale-info = { version = "2.11.1", default-features = false, features = ["derive"] } frame-benchmarking = { path = "../../benchmarking", default-features = false, optional = true } diff --git a/substrate/frame/examples/default-config/Cargo.toml b/substrate/frame/examples/default-config/Cargo.toml index 2aa062ee6c1a0765f9e20d955d1f312c06157966..0ad5b56cb6faa473d337f54fe7eaedaf31a70d9d 100644 --- a/substrate/frame/examples/default-config/Cargo.toml +++ b/substrate/frame/examples/default-config/Cargo.toml @@ -16,7 +16,7 @@ workspace = true targets = ["x86_64-unknown-linux-gnu"] [dependencies] -codec = { package = "parity-scale-codec", version = "3.6.1", default-features = false } +codec = { package = "parity-scale-codec", version = "3.6.12", default-features = false } log = { workspace = true } scale-info = { version = "2.11.1", default-features = false, features = ["derive"] } frame-support = { path = "../../support", default-features = false } diff --git a/substrate/frame/examples/dev-mode/Cargo.toml b/substrate/frame/examples/dev-mode/Cargo.toml index 71b97796ecddf89275c3594362d9ece122b7387f..d7570f570946f1df05665ad8804e62ad9c18030a 100644 --- a/substrate/frame/examples/dev-mode/Cargo.toml +++ b/substrate/frame/examples/dev-mode/Cargo.toml @@ -16,7 +16,7 @@ workspace = true targets = ["x86_64-unknown-linux-gnu"] [dependencies] -codec = { package = "parity-scale-codec", version = "3.6.1", default-features = false } +codec = { package = "parity-scale-codec", version = "3.6.12", default-features = false } log = { workspace = true } scale-info = { version = "2.11.1", default-features = false, features = ["derive"] } frame-support = { path = "../../support", default-features = false } diff --git a/substrate/frame/examples/dev-mode/src/lib.rs b/substrate/frame/examples/dev-mode/src/lib.rs index d57e7a5b76b82f92425596b69f2f495ab0865f1e..15f1a4b5d6199c29158e1600ad825e15d04479bf 100644 --- a/substrate/frame/examples/dev-mode/src/lib.rs +++ b/substrate/frame/examples/dev-mode/src/lib.rs @@ -30,6 +30,7 @@ use frame_support::dispatch::DispatchResult; use frame_system::ensure_signed; +use sp_std::{vec, vec::Vec}; // Re-export pallet items so that they can be accessed from the crate namespace. pub use pallet::*; diff --git a/substrate/frame/examples/frame-crate/Cargo.toml b/substrate/frame/examples/frame-crate/Cargo.toml index 3a0e4f720f95ddd16bf012274cfee24add6f3883..29984bab3e0ffc5ac881eb086d91820c01e7d504 100644 --- a/substrate/frame/examples/frame-crate/Cargo.toml +++ b/substrate/frame/examples/frame-crate/Cargo.toml @@ -2,7 +2,7 @@ name = "pallet-example-frame-crate" version = "0.0.1" authors = ["Parity Technologies "] -edition = "2021" +edition.workspace = true license = "MIT-0" homepage = "https://substrate.io" repository.workspace = true @@ -16,7 +16,7 @@ workspace = true targets = ["x86_64-unknown-linux-gnu"] [dependencies] -codec = { package = "parity-scale-codec", version = "3.6.1", default-features = false } +codec = { package = "parity-scale-codec", version = "3.6.12", default-features = false } scale-info = { version = "2.11.1", default-features = false, features = ["derive"] } frame = { package = "polkadot-sdk-frame", path = "../..", default-features = false, features = ["experimental", "runtime"] } diff --git a/substrate/frame/examples/kitchensink/Cargo.toml b/substrate/frame/examples/kitchensink/Cargo.toml index d8311897c6e1158f8a94520bfd1c6f2712aecbbc..db3e22daa01bd044cae876aabeac25543e814dcb 100644 --- a/substrate/frame/examples/kitchensink/Cargo.toml +++ b/substrate/frame/examples/kitchensink/Cargo.toml @@ -16,7 +16,7 @@ workspace = true targets = ["x86_64-unknown-linux-gnu"] [dependencies] -codec = { package = "parity-scale-codec", version = "3.6.1", default-features = false } +codec = { package = "parity-scale-codec", version = "3.6.12", default-features = false } log = { workspace = true } scale-info = { version = "2.11.1", default-features = false, features = ["derive"] } diff --git a/substrate/frame/examples/multi-block-migrations/Cargo.toml b/substrate/frame/examples/multi-block-migrations/Cargo.toml index 28eca8577154e85c7fbb0d22fca8aefb3c7d9237..61bb2bc61b4e3758fc47c413f35ac5420bbfb4ef 100644 --- a/substrate/frame/examples/multi-block-migrations/Cargo.toml +++ b/substrate/frame/examples/multi-block-migrations/Cargo.toml @@ -13,7 +13,7 @@ publish = false targets = ["x86_64-unknown-linux-gnu"] [dependencies] -codec = { package = "parity-scale-codec", version = "3.6.5", default-features = false } +codec = { package = "parity-scale-codec", version = "3.6.12", default-features = false } pallet-migrations = { path = "../../migrations", default-features = false } frame-support = { path = "../../support", default-features = false } frame-system = { path = "../../system", default-features = false } diff --git a/substrate/frame/examples/offchain-worker/Cargo.toml b/substrate/frame/examples/offchain-worker/Cargo.toml index 468af0345cae71d97afea4c9ce02f2ab2491e5db..23ce79c34402da91cea1f1e02ae7ebd90dc6e5d3 100644 --- a/substrate/frame/examples/offchain-worker/Cargo.toml +++ b/substrate/frame/examples/offchain-worker/Cargo.toml @@ -16,7 +16,7 @@ workspace = true targets = ["x86_64-unknown-linux-gnu"] [dependencies] -codec = { package = "parity-scale-codec", version = "3.6.1", default-features = false } +codec = { package = "parity-scale-codec", version = "3.6.12", default-features = false } lite-json = { version = "0.2.0", default-features = false } log = { workspace = true } scale-info = { version = "2.11.1", default-features = false, features = ["derive"] } @@ -24,7 +24,7 @@ frame-support = { path = "../../support", default-features = false } frame-system = { path = "../../system", default-features = false } sp-core = { path = "../../../primitives/core", default-features = false } sp-io = { path = "../../../primitives/io", default-features = false } -sp-keystore = { path = "../../../primitives/keystore", optional = true } +sp-keystore = { path = "../../../primitives/keystore", optional = true, default-features = false } sp-runtime = { path = "../../../primitives/runtime", default-features = false } sp-std = { path = "../../../primitives/std", default-features = false } diff --git a/substrate/frame/examples/single-block-migrations/Cargo.toml b/substrate/frame/examples/single-block-migrations/Cargo.toml index b1d560a85f3ff59de2ab6560223f7b7657f2b27a..080500f629671837316e724b6825493c3fcb4b67 100644 --- a/substrate/frame/examples/single-block-migrations/Cargo.toml +++ b/substrate/frame/examples/single-block-migrations/Cargo.toml @@ -15,7 +15,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] docify = "0.2.8" log = { version = "0.4.21", default-features = false } -codec = { package = "parity-scale-codec", version = "3.6.1", default-features = false, features = ["derive"] } +codec = { package = "parity-scale-codec", version = "3.6.12", default-features = false, features = ["derive"] } scale-info = { version = "2.11.1", default-features = false, features = ["derive"] } frame-support = { path = "../../support", default-features = false } frame-executive = { path = "../../executive", default-features = false } diff --git a/substrate/frame/examples/single-block-migrations/src/migrations/v1.rs b/substrate/frame/examples/single-block-migrations/src/migrations/v1.rs index 18ef4e72cc4f5ce938abf03d5eaea3039ec0b030..7b543d72c98404d84ba8f68b3d864176c4182fb9 100644 --- a/substrate/frame/examples/single-block-migrations/src/migrations/v1.rs +++ b/substrate/frame/examples/single-block-migrations/src/migrations/v1.rs @@ -67,10 +67,10 @@ impl UncheckedOnRuntimeUpgrade for InnerMigrateV0ToV1 { // 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) + // One read + write for taking the old value, and one write for setting the new value + T::DbWeight::get().reads_writes(1, 2) } else { - // One read for trying to access the old value + // No writes since there was no old value, just one read for checking T::DbWeight::get().reads(1) } } @@ -184,7 +184,7 @@ mod test { // value. assert_eq!( weight, - ::DbWeight::get().reads_writes(1, 1) + ::DbWeight::get().reads_writes(1, 2) ); // After the migration, the new value should be set as the `current` value. diff --git a/substrate/frame/examples/split/Cargo.toml b/substrate/frame/examples/split/Cargo.toml index 1ef3521e06063cf15679e248c6b46ae27a14e946..6cb4d7ddd6c06951b749d796746a7f5a63ee343f 100644 --- a/substrate/frame/examples/split/Cargo.toml +++ b/substrate/frame/examples/split/Cargo.toml @@ -16,7 +16,7 @@ workspace = true targets = ["x86_64-unknown-linux-gnu"] [dependencies] -codec = { package = "parity-scale-codec", version = "3.2.2", default-features = false } +codec = { package = "parity-scale-codec", version = "3.6.12", default-features = false } log = { workspace = true } scale-info = { version = "2.11.1", default-features = false, features = ["derive"] } diff --git a/substrate/frame/examples/tasks/Cargo.toml b/substrate/frame/examples/tasks/Cargo.toml index 3f59d57ea0f202729f11ac549daa828424343671..95246ef3f6643aafe215bb4bacf0e2e2598149ae 100644 --- a/substrate/frame/examples/tasks/Cargo.toml +++ b/substrate/frame/examples/tasks/Cargo.toml @@ -14,7 +14,7 @@ workspace = true targets = ["x86_64-unknown-linux-gnu"] [dependencies] -codec = { package = "parity-scale-codec", version = "3.6.1", default-features = false } +codec = { package = "parity-scale-codec", version = "3.6.12", default-features = false } log = { workspace = true } scale-info = { version = "2.11.1", default-features = false, features = ["derive"] } diff --git a/substrate/frame/examples/tasks/src/lib.rs b/substrate/frame/examples/tasks/src/lib.rs index c65d8095bcf6a2c2295bb87b11e4041fbab88173..1908a235ba15868c41f1fe62c3edd43532e329cf 100644 --- a/substrate/frame/examples/tasks/src/lib.rs +++ b/substrate/frame/examples/tasks/src/lib.rs @@ -19,6 +19,9 @@ #![cfg_attr(not(feature = "std"), no_std)] use frame_support::dispatch::DispatchResult; +use frame_system::offchain::SendTransactionTypes; +#[cfg(feature = "experimental")] +use frame_system::offchain::SubmitTransaction; // Re-export pallet items so that they can be accessed from the crate namespace. pub use pallet::*; @@ -31,10 +34,14 @@ mod benchmarking; pub mod weights; pub use weights::*; +#[cfg(feature = "experimental")] +const LOG_TARGET: &str = "pallet-example-tasks"; + #[frame_support::pallet(dev_mode)] pub mod pallet { use super::*; use frame_support::pallet_prelude::*; + use frame_system::pallet_prelude::*; #[pallet::error] pub enum Error { @@ -59,9 +66,36 @@ pub mod pallet { } } + #[pallet::hooks] + impl Hooks> for Pallet { + #[cfg(feature = "experimental")] + fn offchain_worker(_block_number: BlockNumberFor) { + if let Some(key) = Numbers::::iter_keys().next() { + // Create a valid task + let task = Task::::AddNumberIntoTotal { i: key }; + let runtime_task = ::RuntimeTask::from(task); + let call = frame_system::Call::::do_task { task: runtime_task.into() }; + + // Submit the task as an unsigned transaction + let res = + SubmitTransaction::>::submit_unsigned_transaction( + call.into(), + ); + match res { + Ok(_) => log::info!(target: LOG_TARGET, "Submitted the task."), + Err(e) => log::error!(target: LOG_TARGET, "Error submitting task: {:?}", e), + } + } + } + } + #[pallet::config] - pub trait Config: frame_system::Config { - type RuntimeTask: frame_support::traits::Task; + pub trait Config: + SendTransactionTypes> + frame_system::Config + { + type RuntimeTask: frame_support::traits::Task + + IsType<::RuntimeTask> + + From>; type WeightInfo: WeightInfo; } diff --git a/substrate/frame/examples/tasks/src/mock.rs b/substrate/frame/examples/tasks/src/mock.rs index 76ac9e76bff8a79dbedfd6f6a4746a452a685eba..33912bb5269c5ba58cb9f5256cceb26d681577e5 100644 --- a/substrate/frame/examples/tasks/src/mock.rs +++ b/substrate/frame/examples/tasks/src/mock.rs @@ -20,6 +20,7 @@ use crate::{self as tasks_example}; use frame_support::derive_impl; +use sp_runtime::testing::TestXt; pub type AccountId = u32; pub type Balance = u32; @@ -32,12 +33,32 @@ frame_support::construct_runtime!( } ); +pub type Extrinsic = TestXt; + #[derive_impl(frame_system::config_preludes::TestDefaultConfig)] impl frame_system::Config for Runtime { type Block = Block; } +impl frame_system::offchain::SendTransactionTypes for Runtime +where + RuntimeCall: From, +{ + type OverarchingCall = RuntimeCall; + type Extrinsic = Extrinsic; +} + impl tasks_example::Config for Runtime { type RuntimeTask = RuntimeTask; type WeightInfo = (); } + +pub fn advance_to(b: u64) { + #[cfg(feature = "experimental")] + use frame_support::traits::Hooks; + while System::block_number() < b { + System::set_block_number(System::block_number() + 1); + #[cfg(feature = "experimental")] + TasksExample::offchain_worker(System::block_number()); + } +} diff --git a/substrate/frame/examples/tasks/src/tests.rs b/substrate/frame/examples/tasks/src/tests.rs index fc3c69f4aef95601c2a96faf1c939c27ee419fd4..6c8acb0194bde6cba27e4e2706f78676468c0057 100644 --- a/substrate/frame/examples/tasks/src/tests.rs +++ b/substrate/frame/examples/tasks/src/tests.rs @@ -19,7 +19,11 @@ #![cfg(test)] use crate::{mock::*, Numbers}; +#[cfg(feature = "experimental")] +use codec::Decode; use frame_support::traits::Task; +#[cfg(feature = "experimental")] +use sp_core::offchain::{testing, OffchainWorkerExt, TransactionPoolExt}; use sp_runtime::BuildStorage; #[cfg(feature = "experimental")] @@ -130,3 +134,29 @@ fn task_execution_fails_for_invalid_task() { ); }); } + +#[cfg(feature = "experimental")] +#[test] +fn task_with_offchain_worker() { + let (offchain, _offchain_state) = testing::TestOffchainExt::new(); + let (pool, pool_state) = testing::TestTransactionPoolExt::new(); + + let mut t = sp_io::TestExternalities::default(); + t.register_extension(OffchainWorkerExt::new(offchain)); + t.register_extension(TransactionPoolExt::new(pool)); + + t.execute_with(|| { + advance_to(1); + assert!(pool_state.read().transactions.is_empty()); + + Numbers::::insert(0, 10); + assert_eq!(crate::Total::::get(), (0, 0)); + + advance_to(2); + + 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); + }); +} diff --git a/substrate/frame/executive/Cargo.toml b/substrate/frame/executive/Cargo.toml index 95de7c3f3d1f086a39a8f12af6c8a851eff3fa4d..4cce0fa9f9504ae48ca1929f87311896b81ca5cf 100644 --- a/substrate/frame/executive/Cargo.toml +++ b/substrate/frame/executive/Cargo.toml @@ -16,8 +16,8 @@ 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 = [ +aquamarine = "0.5.0" +codec = { package = "parity-scale-codec", version = "3.6.12", default-features = false, features = [ "derive", ] } log = { workspace = true } @@ -32,7 +32,7 @@ sp-std = { path = "../../primitives/std", default-features = false } sp-tracing = { path = "../../primitives/tracing", default-features = false } [dev-dependencies] -array-bytes = "6.1" +array-bytes = "6.2.2" pallet-balances = { path = "../balances" } pallet-transaction-payment = { path = "../transaction-payment" } sp-core = { path = "../../primitives/core" } diff --git a/substrate/frame/fast-unstake/Cargo.toml b/substrate/frame/fast-unstake/Cargo.toml index f05f22f764164ce15704a9200c78e65b2867c908..5b7121e2eae3788fdf37c0467871f0233dd62393 100644 --- a/substrate/frame/fast-unstake/Cargo.toml +++ b/substrate/frame/fast-unstake/Cargo.toml @@ -15,7 +15,7 @@ workspace = true targets = ["x86_64-unknown-linux-gnu"] [dependencies] -codec = { package = "parity-scale-codec", version = "3.6.1", default-features = false } +codec = { package = "parity-scale-codec", version = "3.6.12", default-features = false } log = { workspace = true } scale-info = { version = "2.11.1", default-features = false, features = ["derive"] } diff --git a/substrate/frame/fast-unstake/src/mock.rs b/substrate/frame/fast-unstake/src/mock.rs index b731cb822f336d6dd2da8e0d5ca501090909a31a..d876f9f6171e5ed55d9cbe95fd678fa071b5bd9b 100644 --- a/substrate/frame/fast-unstake/src/mock.rs +++ b/substrate/frame/fast-unstake/src/mock.rs @@ -134,7 +134,6 @@ impl pallet_staking::Config for Runtime { type NextNewSession = (); type HistoryDepth = ConstU32<84>; type MaxExposurePageSize = ConstU32<64>; - type OffendingValidatorsThreshold = (); type ElectionProvider = MockElection; type GenesisElectionProvider = Self::ElectionProvider; type VoterList = pallet_staking::UseNominatorsAndValidatorsMap; @@ -145,6 +144,7 @@ impl pallet_staking::Config for Runtime { type EventListeners = (); type BenchmarkingConfig = pallet_staking::TestBenchmarkingConfig; type WeightInfo = (); + type DisablingStrategy = pallet_staking::UpToLimitDisablingStrategy; } pub struct BalanceToU256; diff --git a/substrate/frame/glutton/Cargo.toml b/substrate/frame/glutton/Cargo.toml index 5ce010f1c2622fbbefa053bf1bb45383e853af4c..730c4e70935c0be3cb840087011a37ca9668b317 100644 --- a/substrate/frame/glutton/Cargo.toml +++ b/substrate/frame/glutton/Cargo.toml @@ -17,7 +17,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] blake2 = { version = "0.10.4", default-features = false } -codec = { package = "parity-scale-codec", version = "3.6.1", default-features = false, features = ["derive"] } +codec = { package = "parity-scale-codec", version = "3.6.12", default-features = false, features = ["derive"] } scale-info = { version = "2.11.1", default-features = false, features = ["derive"] } log = { workspace = true } frame-benchmarking = { path = "../benchmarking", default-features = false, optional = true } diff --git a/substrate/frame/grandpa/Cargo.toml b/substrate/frame/grandpa/Cargo.toml index f4dd92129f38aeb76a1df8afd21494102eb68bd9..302ce327aed4b037432b660cf65b0c9aba5123f6 100644 --- a/substrate/frame/grandpa/Cargo.toml +++ b/substrate/frame/grandpa/Cargo.toml @@ -16,7 +16,7 @@ workspace = true targets = ["x86_64-unknown-linux-gnu"] [dependencies] -codec = { package = "parity-scale-codec", version = "3.6.1", default-features = false, features = ["derive"] } +codec = { package = "parity-scale-codec", version = "3.6.12", default-features = false, features = ["derive"] } log = { workspace = true } scale-info = { version = "2.11.1", default-features = false, features = ["derive", "serde"] } frame-benchmarking = { path = "../benchmarking", default-features = false, optional = true } diff --git a/substrate/frame/grandpa/src/mock.rs b/substrate/frame/grandpa/src/mock.rs index 4a21da655e5b3d4b219caed097619fa3268eca57..2d54f525b1f0c6b6a78f8df848c5770391f4fa2d 100644 --- a/substrate/frame/grandpa/src/mock.rs +++ b/substrate/frame/grandpa/src/mock.rs @@ -146,7 +146,6 @@ parameter_types! { pub const SessionsPerEra: SessionIndex = 3; pub const BondingDuration: EraIndex = 3; pub const RewardCurve: &'static PiecewiseLinear<'static> = &REWARD_CURVE; - pub const OffendingValidatorsThreshold: Perbill = Perbill::from_percent(17); pub static ElectionsBoundsOnChain: ElectionBounds = ElectionBoundsBuilder::default().build(); } @@ -176,7 +175,6 @@ impl pallet_staking::Config for Test { type UnixTime = pallet_timestamp::Pallet; type EraPayout = pallet_staking::ConvertCurve; type MaxExposurePageSize = ConstU32<64>; - type OffendingValidatorsThreshold = OffendingValidatorsThreshold; type NextNewSession = Session; type ElectionProvider = onchain::OnChainExecution; type GenesisElectionProvider = Self::ElectionProvider; @@ -189,6 +187,7 @@ impl pallet_staking::Config for Test { type EventListeners = (); type BenchmarkingConfig = pallet_staking::TestBenchmarkingConfig; type WeightInfo = (); + type DisablingStrategy = pallet_staking::UpToLimitDisablingStrategy; } impl pallet_offences::Config for Test { diff --git a/substrate/frame/identity/Cargo.toml b/substrate/frame/identity/Cargo.toml index 8c0052004ae3d595f3d1f0bef75d92584d3c3ff5..e0bce8a77bdc68c26a9de9b95438b8b06ff4228b 100644 --- a/substrate/frame/identity/Cargo.toml +++ b/substrate/frame/identity/Cargo.toml @@ -16,7 +16,7 @@ workspace = true targets = ["x86_64-unknown-linux-gnu"] [dependencies] -codec = { package = "parity-scale-codec", version = "3.6.1", default-features = false, features = ["derive", "max-encoded-len"] } +codec = { package = "parity-scale-codec", version = "3.6.12", default-features = false, features = ["derive", "max-encoded-len"] } enumflags2 = { version = "0.7.7" } log = { workspace = true } scale-info = { version = "2.11.1", default-features = false, features = ["derive"] } diff --git a/substrate/frame/im-online/Cargo.toml b/substrate/frame/im-online/Cargo.toml index 46b416f0f9a8d72a12aa12f9d8eeb99aaf4c1c2a..78192a81d7b461d0c834662b8bd0e4c50ea31333 100644 --- a/substrate/frame/im-online/Cargo.toml +++ b/substrate/frame/im-online/Cargo.toml @@ -16,7 +16,7 @@ workspace = true targets = ["x86_64-unknown-linux-gnu"] [dependencies] -codec = { package = "parity-scale-codec", version = "3.6.1", default-features = false, features = ["derive"] } +codec = { package = "parity-scale-codec", version = "3.6.12", default-features = false, features = ["derive"] } log = { workspace = true } scale-info = { version = "2.11.1", default-features = false, features = ["derive", "serde"] } frame-benchmarking = { path = "../benchmarking", default-features = false, optional = true } diff --git a/substrate/frame/im-online/src/lib.rs b/substrate/frame/im-online/src/lib.rs index 239b47834d1f8b1625a186e4a8f90e9861bfa303..f91a473e53d5389275974ed0e62c1d75d0daff54 100644 --- a/substrate/frame/im-online/src/lib.rs +++ b/substrate/frame/im-online/src/lib.rs @@ -104,7 +104,7 @@ use sp_runtime::{ PerThing, Perbill, Permill, RuntimeDebug, SaturatedConversion, }; use sp_staking::{ - offence::{DisableStrategy, Kind, Offence, ReportOffence}, + offence::{Kind, Offence, ReportOffence}, SessionIndex, }; use sp_std::prelude::*; @@ -847,10 +847,6 @@ impl Offence for UnresponsivenessOffence { self.session_index } - fn disable_strategy(&self) -> DisableStrategy { - DisableStrategy::Never - } - fn slash_fraction(&self, offenders: u32) -> Perbill { // the formula is min((3 * (k - (n / 10 + 1))) / n, 1) * 0.07 // basically, 10% can be offline with no slash, but after that, it linearly climbs up to 7% diff --git a/substrate/frame/im-online/src/tests.rs b/substrate/frame/im-online/src/tests.rs index f9959593494a0b94c4093f4c06f0e45c1e3e4f59..12333d59ef8959d26836330bb4a3a1be93ac49ab 100644 --- a/substrate/frame/im-online/src/tests.rs +++ b/substrate/frame/im-online/src/tests.rs @@ -50,9 +50,6 @@ fn test_unresponsiveness_slash_fraction() { dummy_offence.slash_fraction(17), Perbill::from_parts(46200000), // 4.62% ); - - // Offline offences should never lead to being disabled. - assert_eq!(dummy_offence.disable_strategy(), DisableStrategy::Never); } #[test] diff --git a/substrate/frame/indices/Cargo.toml b/substrate/frame/indices/Cargo.toml index 7b14bf358f1ef3e929e8e6be67f33a54b3590928..248bae003ed856a828ce82863ad2fadfb7f0a927 100644 --- a/substrate/frame/indices/Cargo.toml +++ b/substrate/frame/indices/Cargo.toml @@ -16,14 +16,14 @@ workspace = true targets = ["x86_64-unknown-linux-gnu"] [dependencies] -codec = { package = "parity-scale-codec", version = "3.6.1", default-features = false, features = ["derive"] } +codec = { package = "parity-scale-codec", version = "3.6.12", default-features = false, features = ["derive"] } scale-info = { version = "2.11.1", 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 } sp-core = { path = "../../primitives/core", default-features = false } sp-io = { path = "../../primitives/io", default-features = false } -sp-keyring = { path = "../../primitives/keyring", optional = true } +sp-keyring = { path = "../../primitives/keyring", optional = true, default-features = false } sp-runtime = { path = "../../primitives/runtime", default-features = false } sp-std = { path = "../../primitives/std", default-features = false } @@ -42,6 +42,7 @@ std = [ "sp-core/std", "sp-io/std", "sp-keyring", + "sp-keyring?/std", "sp-runtime/std", "sp-std/std", ] diff --git a/substrate/frame/insecure-randomness-collective-flip/Cargo.toml b/substrate/frame/insecure-randomness-collective-flip/Cargo.toml index f4d65d9e560a51afe6211ca2889a95eb864a42f3..c2ec14cb4bc77c5668750684ae983b41ac46e780 100644 --- a/substrate/frame/insecure-randomness-collective-flip/Cargo.toml +++ b/substrate/frame/insecure-randomness-collective-flip/Cargo.toml @@ -16,7 +16,7 @@ workspace = true targets = ["x86_64-unknown-linux-gnu"] [dependencies] -codec = { package = "parity-scale-codec", version = "3.6.1", default-features = false, features = ["derive"] } +codec = { package = "parity-scale-codec", version = "3.6.12", default-features = false, features = ["derive"] } safe-mix = { version = "1.0", default-features = false } scale-info = { version = "2.11.1", default-features = false, features = ["derive"] } frame-support = { path = "../support", default-features = false } diff --git a/substrate/frame/lottery/Cargo.toml b/substrate/frame/lottery/Cargo.toml index 5f79704445f964eae544f0c8678f08f86ab85213..be59e5ec8935102bd03782f7c745775c46bacc18 100644 --- a/substrate/frame/lottery/Cargo.toml +++ b/substrate/frame/lottery/Cargo.toml @@ -15,7 +15,7 @@ workspace = true targets = ["x86_64-unknown-linux-gnu"] [dependencies] -codec = { package = "parity-scale-codec", version = "3.6.1", default-features = false, features = [ +codec = { package = "parity-scale-codec", version = "3.6.12", default-features = false, features = [ "derive", ] } scale-info = { version = "2.11.1", default-features = false, features = ["derive"] } diff --git a/substrate/frame/membership/Cargo.toml b/substrate/frame/membership/Cargo.toml index 6f67db0ae709901f30c2339c40fd6d3399b06606..9f19c40973687a41936372f6e116eb2dc8417306 100644 --- a/substrate/frame/membership/Cargo.toml +++ b/substrate/frame/membership/Cargo.toml @@ -16,7 +16,7 @@ workspace = true targets = ["x86_64-unknown-linux-gnu"] [dependencies] -codec = { package = "parity-scale-codec", version = "3.6.1", default-features = false } +codec = { package = "parity-scale-codec", version = "3.6.12", default-features = false } log = { workspace = true } scale-info = { version = "2.11.1", default-features = false, features = ["derive", "serde"] } frame-benchmarking = { path = "../benchmarking", default-features = false, optional = true } diff --git a/substrate/frame/merkle-mountain-range/Cargo.toml b/substrate/frame/merkle-mountain-range/Cargo.toml index 6dc919e16505a164e84c0e5e5b6c4f299b2da955..0d73c567cf4e16babb1488d0ad6e5d43c11639d8 100644 --- a/substrate/frame/merkle-mountain-range/Cargo.toml +++ b/substrate/frame/merkle-mountain-range/Cargo.toml @@ -15,7 +15,7 @@ workspace = true targets = ["x86_64-unknown-linux-gnu"] [dependencies] -codec = { package = "parity-scale-codec", version = "3.6.1", default-features = false } +codec = { package = "parity-scale-codec", version = "3.6.12", default-features = false } log = { workspace = true } scale-info = { version = "2.11.1", default-features = false, features = ["derive"] } frame-benchmarking = { path = "../benchmarking", default-features = false, optional = true } @@ -28,9 +28,9 @@ sp-runtime = { path = "../../primitives/runtime", default-features = false } sp-std = { path = "../../primitives/std", default-features = false } [dev-dependencies] -array-bytes = "6.1" +array-bytes = "6.2.2" env_logger = "0.11" -itertools = "0.10.3" +itertools = "0.11" [features] default = ["std"] diff --git a/substrate/frame/merkle-mountain-range/src/lib.rs b/substrate/frame/merkle-mountain-range/src/lib.rs index e2b40974579e8376723f466198d74755603285d0..a86443f2e0114120cac8b14e85de08ee183eda93 100644 --- a/substrate/frame/merkle-mountain-range/src/lib.rs +++ b/substrate/frame/merkle-mountain-range/src/lib.rs @@ -260,15 +260,15 @@ pub mod pallet { /// Stateless MMR proof verification for batch of leaves. /// -/// This function can be used to verify received MMR [primitives::Proof] (`proof`) +/// This function can be used to verify received MMR [primitives::LeafProof] (`proof`) /// for given leaves set (`leaves`) against a known MMR root hash (`root`). /// Note, the leaves should be sorted such that corresponding leaves and leaf indices have the /// same position in both the `leaves` vector and the `leaf_indices` vector contained in the -/// [primitives::Proof]. +/// [primitives::LeafProof]. pub fn verify_leaves_proof( root: H::Output, leaves: Vec>, - proof: primitives::Proof, + proof: primitives::LeafProof, ) -> Result<(), primitives::Error> where H: traits::Hash, @@ -342,7 +342,7 @@ impl, I: 'static> Pallet { pub fn generate_proof( block_numbers: Vec>, best_known_block_number: Option>, - ) -> Result<(Vec>, primitives::Proof>), primitives::Error> { + ) -> Result<(Vec>, primitives::LeafProof>), primitives::Error> { // check whether best_known_block_number provided, else use current best block let best_known_block_number = best_known_block_number.unwrap_or_else(|| >::block_number()); @@ -362,11 +362,6 @@ impl, I: 'static> Pallet { mmr.generate_proof(leaf_indices) } - /// Return the on-chain MMR root hash. - pub fn mmr_root() -> HashOf { - RootHash::::get() - } - /// Verify MMR proof for given `leaves`. /// /// This method is safe to use within the runtime code. @@ -375,7 +370,7 @@ impl, I: 'static> Pallet { /// or the proof is invalid. pub fn verify_leaves( leaves: Vec>, - proof: primitives::Proof>, + proof: primitives::LeafProof>, ) -> Result<(), primitives::Error> { if proof.leaf_count > NumberOfLeaves::::get() || proof.leaf_count == 0 || @@ -393,4 +388,37 @@ impl, I: 'static> Pallet { Err(primitives::Error::Verify.log_debug("The proof is incorrect.")) } } + + pub fn generate_ancestry_proof( + prev_block_number: BlockNumberFor, + best_known_block_number: Option>, + ) -> Result>, Error> { + // check whether best_known_block_number provided, else use current best block + let best_known_block_number = + best_known_block_number.unwrap_or_else(|| >::block_number()); + + let leaf_count = Self::block_num_to_leaf_index(best_known_block_number)?.saturating_add(1); + let prev_leaf_count = Self::block_num_to_leaf_index(prev_block_number)?.saturating_add(1); + + let mmr: ModuleMmr = mmr::Mmr::new(leaf_count); + mmr.generate_ancestry_proof(prev_leaf_count) + } + + pub fn verify_ancestry_proof( + ancestry_proof: primitives::AncestryProof>, + ) -> Result<(), Error> { + let mmr: ModuleMmr = + mmr::Mmr::new(ancestry_proof.leaf_count); + let is_valid = mmr.verify_ancestry_proof(ancestry_proof)?; + if is_valid { + Ok(()) + } else { + Err(Error::Verify.log_debug("The ancestry proof is incorrect.")) + } + } + + /// Return the on-chain MMR root hash. + pub fn mmr_root() -> HashOf { + RootHash::::get() + } } diff --git a/substrate/frame/merkle-mountain-range/src/mmr/mmr.rs b/substrate/frame/merkle-mountain-range/src/mmr/mmr.rs index aeb3e7ea66414a062a238da3f84795b53da4f68b..5efc172d1e93f1d7a56e3b36da20f93c6e1df1f9 100644 --- a/substrate/frame/merkle-mountain-range/src/mmr/mmr.rs +++ b/substrate/frame/merkle-mountain-range/src/mmr/mmr.rs @@ -23,17 +23,17 @@ use crate::{ primitives::{self, Error, NodeIndex}, Config, HashOf, HashingOf, }; -use sp_mmr_primitives::{mmr_lib, utils::NodesUtils}; +use sp_mmr_primitives::{mmr_lib, mmr_lib::MMRStoreReadOps, utils::NodesUtils, LeafIndex}; use sp_std::prelude::*; /// Stateless verification of the proof for a batch of leaves. /// Note, the leaves should be sorted such that corresponding leaves and leaf indices have the /// same position in both the `leaves` vector and the `leaf_indices` vector contained in the -/// [primitives::Proof] +/// [primitives::LeafProof] pub fn verify_leaves_proof( root: H::Output, leaves: Vec>, - proof: primitives::Proof, + proof: primitives::LeafProof, ) -> Result where H: sp_runtime::traits::Hash, @@ -69,7 +69,8 @@ where T: Config, I: 'static, L: primitives::FullLeaf, - Storage: mmr_lib::MMRStore>, + Storage: + MMRStoreReadOps> + mmr_lib::MMRStoreWriteOps>, { mmr: mmr_lib::MMR, Hasher, L>, Storage>, leaves: NodeIndex, @@ -80,7 +81,8 @@ where T: Config, I: 'static, L: primitives::FullLeaf, - Storage: mmr_lib::MMRStore>, + Storage: + MMRStoreReadOps> + mmr_lib::MMRStoreWriteOps>, { /// Create a pointer to an existing MMR with given number of leaves. pub fn new(leaves: NodeIndex) -> Self { @@ -91,11 +93,11 @@ where /// Verify proof for a set of leaves. /// Note, the leaves should be sorted such that corresponding leaves and leaf indices have /// the same position in both the `leaves` vector and the `leaf_indices` vector contained in the - /// [primitives::Proof] + /// [primitives::LeafProof] pub fn verify_leaves_proof( &self, leaves: Vec, - proof: primitives::Proof>, + proof: primitives::LeafProof>, ) -> Result { let p = mmr_lib::MerkleProof::, Hasher, L>>::new( self.mmr.mmr_size(), @@ -117,6 +119,44 @@ where .map_err(|e| Error::Verify.log_debug(e)) } + pub fn verify_ancestry_proof( + &self, + ancestry_proof: primitives::AncestryProof>, + ) -> Result { + let prev_peaks_proof = + mmr_lib::NodeMerkleProof::, Hasher, L>>::new( + self.mmr.mmr_size(), + ancestry_proof + .items + .into_iter() + .map(|(index, hash)| (index, Node::Hash(hash))) + .collect(), + ); + + let raw_ancestry_proof = mmr_lib::AncestryProof::< + NodeOf, + Hasher, L>, + > { + prev_peaks: ancestry_proof + .prev_peaks + .into_iter() + .map(|hash| Node::Hash(hash)) + .collect(), + prev_size: mmr_lib::helper::leaf_index_to_mmr_size(ancestry_proof.prev_leaf_count - 1), + proof: prev_peaks_proof, + }; + + let prev_root = mmr_lib::ancestry_proof::bagging_peaks_hashes::< + NodeOf, + Hasher, L>, + >(raw_ancestry_proof.prev_peaks.clone()) + .map_err(|e| Error::Verify.log_debug(e))?; + let root = self.mmr.get_root().map_err(|e| Error::GetRoot.log_error(e))?; + raw_ancestry_proof + .verify_ancestor(root, prev_root) + .map_err(|e| Error::Verify.log_debug(e)) + } + /// Return the internal size of the MMR (number of nodes). #[cfg(test)] pub fn size(&self) -> NodeIndex { @@ -145,7 +185,7 @@ where /// Commit the changes to underlying storage, return current number of leaves and /// calculate the new MMR's root hash. - pub fn finalize(self) -> Result<(NodeIndex, HashOf), Error> { + pub fn finalize(mut self) -> Result<(NodeIndex, HashOf), Error> { let root = self.mmr.get_root().map_err(|e| Error::GetRoot.log_error(e))?; self.mmr.commit().map_err(|e| Error::Commit.log_error(e))?; Ok((self.leaves, root.hash())) @@ -166,7 +206,7 @@ where pub fn generate_proof( &self, leaf_indices: Vec, - ) -> Result<(Vec, primitives::Proof>), Error> { + ) -> Result<(Vec, primitives::LeafProof>), Error> { let positions = leaf_indices .iter() .map(|index| mmr_lib::leaf_index_to_pos(*index)) @@ -174,7 +214,7 @@ where let store = >::default(); let leaves = positions .iter() - .map(|pos| match mmr_lib::MMRStore::get_elem(&store, *pos) { + .map(|pos| match store.get_elem(*pos) { Ok(Some(Node::Data(leaf))) => Ok(leaf), e => Err(Error::LeafNotFound.log_debug(e)), }) @@ -184,11 +224,34 @@ where self.mmr .gen_proof(positions) .map_err(|e| Error::GenerateProof.log_error(e)) - .map(|p| primitives::Proof { + .map(|p| primitives::LeafProof { leaf_indices, leaf_count, items: p.proof_items().iter().map(|x| x.hash()).collect(), }) .map(|p| (leaves, p)) } + + pub fn generate_ancestry_proof( + &self, + prev_leaf_count: LeafIndex, + ) -> Result>, Error> { + let prev_mmr_size = NodesUtils::new(prev_leaf_count).size(); + let raw_ancestry_proof = self + .mmr + .gen_ancestry_proof(prev_mmr_size) + .map_err(|e| Error::GenerateProof.log_error(e))?; + + Ok(primitives::AncestryProof { + prev_peaks: raw_ancestry_proof.prev_peaks.into_iter().map(|p| p.hash()).collect(), + prev_leaf_count, + leaf_count: self.leaves, + items: raw_ancestry_proof + .proof + .proof_items() + .iter() + .map(|(index, item)| (*index, item.hash())) + .collect(), + }) + } } diff --git a/substrate/frame/merkle-mountain-range/src/mmr/storage.rs b/substrate/frame/merkle-mountain-range/src/mmr/storage.rs index f2acc35a137ffb46a39396762eafe30d7296e017..6848b8f1b9906b85bfc7c3b9ca9d5a52b4ddaed8 100644 --- a/substrate/frame/merkle-mountain-range/src/mmr/storage.rs +++ b/substrate/frame/merkle-mountain-range/src/mmr/storage.rs @@ -60,7 +60,7 @@ impl Default for Storage { } } -impl mmr_lib::MMRStore> for Storage +impl mmr_lib::MMRStoreReadOps> for Storage where T: Config, I: 'static, @@ -98,13 +98,20 @@ where Ok(sp_io::offchain::local_storage_get(StorageKind::PERSISTENT, &temp_key) .and_then(|v| codec::Decode::decode(&mut &*v).ok())) } +} +impl mmr_lib::MMRStoreWriteOps> for Storage +where + T: Config, + I: 'static, + L: primitives::FullLeaf + codec::Decode, +{ fn append(&mut self, _: NodeIndex, _: Vec>) -> mmr_lib::Result<()> { panic!("MMR must not be altered in the off-chain context.") } } -impl mmr_lib::MMRStore> for Storage +impl mmr_lib::MMRStoreReadOps> for Storage where T: Config, I: 'static, @@ -113,7 +120,14 @@ where fn get_elem(&self, pos: NodeIndex) -> mmr_lib::Result>> { Ok(Nodes::::get(pos).map(Node::Hash)) } +} +impl mmr_lib::MMRStoreWriteOps> for Storage +where + T: Config, + I: 'static, + L: primitives::FullLeaf, +{ fn append(&mut self, pos: NodeIndex, elems: Vec>) -> mmr_lib::Result<()> { if elems.is_empty() { return Ok(()) diff --git a/substrate/frame/merkle-mountain-range/src/tests.rs b/substrate/frame/merkle-mountain-range/src/tests.rs index 88de7511c9f280b6996419f07ac1f5c458d8a395..f8cfcb4e2c286f949207826990ba715485247ca2 100644 --- a/substrate/frame/merkle-mountain-range/src/tests.rs +++ b/substrate/frame/merkle-mountain-range/src/tests.rs @@ -22,7 +22,7 @@ use sp_core::{ offchain::{testing::TestOffchainExt, OffchainDbExt, OffchainWorkerExt}, H256, }; -use sp_mmr_primitives::{mmr_lib::helper, utils, Compact, Proof}; +use sp_mmr_primitives::{mmr_lib::helper, utils, Compact, LeafProof}; use sp_runtime::BuildStorage; pub(crate) fn new_test_ext() -> sp_io::TestExternalities { @@ -283,7 +283,7 @@ fn should_generate_proofs_correctly() { proofs[0], ( vec![Compact::new(((0, H256::repeat_byte(1)).into(), LeafData::new(1).into(),))], - Proof { + LeafProof { leaf_indices: vec![0], leaf_count: 7, items: vec![ @@ -298,7 +298,7 @@ fn should_generate_proofs_correctly() { historical_proofs[0][0], ( vec![Compact::new(((0, H256::repeat_byte(1)).into(), LeafData::new(1).into(),))], - Proof { leaf_indices: vec![0], leaf_count: 1, items: vec![] } + LeafProof { leaf_indices: vec![0], leaf_count: 1, items: vec![] } ) ); @@ -314,7 +314,7 @@ fn should_generate_proofs_correctly() { proofs[2], ( vec![Compact::new(((2, H256::repeat_byte(3)).into(), LeafData::new(3).into(),))], - Proof { + LeafProof { leaf_indices: vec![2], leaf_count: 7, items: vec![ @@ -334,7 +334,7 @@ fn should_generate_proofs_correctly() { historical_proofs[2][0], ( vec![Compact::new(((2, H256::repeat_byte(3)).into(), LeafData::new(3).into(),))], - Proof { + LeafProof { leaf_indices: vec![2], leaf_count: 3, items: vec![hex( @@ -354,7 +354,7 @@ fn should_generate_proofs_correctly() { historical_proofs[2][2], ( vec![Compact::new(((2, H256::repeat_byte(3)).into(), LeafData::new(3).into(),))], - Proof { + LeafProof { leaf_indices: vec![2], leaf_count: 5, items: vec![ @@ -372,7 +372,7 @@ fn should_generate_proofs_correctly() { ( // NOTE: the leaf index is equivalent to the block number(in this case 5) - 1 vec![Compact::new(((4, H256::repeat_byte(5)).into(), LeafData::new(5).into(),))], - Proof { + LeafProof { leaf_indices: vec![4], leaf_count: 7, items: vec![ @@ -387,7 +387,7 @@ fn should_generate_proofs_correctly() { historical_proofs[4][0], ( vec![Compact::new(((4, H256::repeat_byte(5)).into(), LeafData::new(5).into(),))], - Proof { + LeafProof { leaf_indices: vec![4], leaf_count: 5, items: vec![hex( @@ -402,7 +402,7 @@ fn should_generate_proofs_correctly() { proofs[6], ( vec![Compact::new(((6, H256::repeat_byte(7)).into(), LeafData::new(7).into(),))], - Proof { + LeafProof { leaf_indices: vec![6], leaf_count: 7, items: vec![ @@ -433,7 +433,7 @@ fn should_generate_batch_proof_correctly() { // then assert_eq!( proof, - Proof { + LeafProof { // the leaf indices are equivalent to the above specified block numbers - 1. leaf_indices: vec![0, 4, 5], leaf_count: 7, @@ -451,7 +451,7 @@ fn should_generate_batch_proof_correctly() { // then assert_eq!( historical_proof, - Proof { + LeafProof { leaf_indices: vec![0, 4, 5], leaf_count: 6, items: vec![ @@ -516,43 +516,40 @@ fn should_verify() { }); } -#[test] -fn should_verify_batch_proofs() { - fn generate_and_verify_batch_proof( - ext: &mut sp_io::TestExternalities, - block_numbers: &Vec, - blocks_to_add: usize, - ) { - let (leaves, proof) = ext.execute_with(|| { - crate::Pallet::::generate_proof(block_numbers.to_vec(), None).unwrap() - }); +fn generate_and_verify_batch_proof( + ext: &mut sp_io::TestExternalities, + block_numbers: &Vec, + blocks_to_add: usize, +) { + let (leaves, proof) = ext.execute_with(|| { + crate::Pallet::::generate_proof(block_numbers.to_vec(), None).unwrap() + }); - let max_block_number = ext.execute_with(|| frame_system::Pallet::::block_number()); - let min_block_number = block_numbers.iter().max().unwrap(); + let max_block_number = ext.execute_with(|| frame_system::Pallet::::block_number()); + let min_block_number = block_numbers.iter().max().unwrap(); - // generate all possible historical proofs for the given blocks - let historical_proofs = (*min_block_number..=max_block_number) - .map(|best_block| { - ext.execute_with(|| { - crate::Pallet::::generate_proof(block_numbers.to_vec(), Some(best_block)) - .unwrap() - }) + // generate all possible historical proofs for the given blocks + let historical_proofs = (*min_block_number..=max_block_number) + .map(|best_block| { + ext.execute_with(|| { + crate::Pallet::::generate_proof(block_numbers.to_vec(), Some(best_block)) + .unwrap() }) - .collect::>(); - - ext.execute_with(|| { - add_blocks(blocks_to_add); - // then - assert_eq!(crate::Pallet::::verify_leaves(leaves, proof), Ok(())); - historical_proofs.iter().for_each(|(leaves, proof)| { - assert_eq!( - crate::Pallet::::verify_leaves(leaves.clone(), proof.clone()), - Ok(()) - ); - }); }) - } + .collect::>(); + + ext.execute_with(|| { + add_blocks(blocks_to_add); + // then + assert_eq!(crate::Pallet::::verify_leaves(leaves, proof), Ok(())); + historical_proofs.iter().for_each(|(leaves, proof)| { + assert_eq!(crate::Pallet::::verify_leaves(leaves.clone(), proof.clone()), Ok(())); + }); + }) +} +#[test] +fn should_verify_batch_proofs() { let _ = env_logger::try_init(); use itertools::Itertools; @@ -790,3 +787,24 @@ fn does_not_panic_when_generating_historical_proofs() { ); }); } + +#[test] +fn generating_and_verifying_ancestry_proofs_works_correctly() { + let _ = env_logger::try_init(); + let mut ext = new_test_ext(); + ext.execute_with(|| add_blocks(500)); + ext.persist_offchain_overlay(); + register_offchain_ext(&mut ext); + + ext.execute_with(|| { + // Check that generating and verifying ancestry proofs works correctly + // for each previous block + for prev_block_number in 1..501 { + let proof = Pallet::::generate_ancestry_proof(prev_block_number, None).unwrap(); + Pallet::::verify_ancestry_proof(proof).unwrap(); + } + + // Check that we can't generate ancestry proofs for a future block. + assert_eq!(Pallet::::generate_ancestry_proof(501, None), Err(Error::GenerateProof)); + }); +} diff --git a/substrate/frame/message-queue/Cargo.toml b/substrate/frame/message-queue/Cargo.toml index f263c41831beab8f77aa04522e6cec40d75af703..e44cbeb1550ccfdb0daf8e871e924df261a59227 100644 --- a/substrate/frame/message-queue/Cargo.toml +++ b/substrate/frame/message-queue/Cargo.toml @@ -12,7 +12,7 @@ description = "FRAME pallet to queue and process messages" workspace = true [dependencies] -codec = { package = "parity-scale-codec", version = "3.6.1", default-features = false, features = ["derive"] } +codec = { package = "parity-scale-codec", version = "3.6.12", default-features = false, features = ["derive"] } scale-info = { version = "2.11.1", default-features = false, features = ["derive"] } serde = { optional = true, features = ["derive"], workspace = true, default-features = true } log = { workspace = true } diff --git a/substrate/frame/message-queue/src/lib.rs b/substrate/frame/message-queue/src/lib.rs index ec85c785f79eb6eea628d9a8df6db0667d2bf70e..ef3420d21be520f8056b1c1299e8369754186560 100644 --- a/substrate/frame/message-queue/src/lib.rs +++ b/substrate/frame/message-queue/src/lib.rs @@ -765,6 +765,13 @@ enum MessageExecutionStatus { Processed, /// The message was processed and resulted in a, possibly permanent, error. Unprocessable { permanent: bool }, + /// The stack depth limit was reached. + /// + /// We cannot just return `Unprocessable` in this case, because the processability of the + /// message depends on how the function was called. This may be a permanent error if it was + /// called by a top-level function, or a transient error if it was already called in a nested + /// function. + StackLimitReached, } impl Pallet { @@ -984,7 +991,8 @@ impl Pallet { // additional overweight event being deposited. ) { Overweight | InsufficientWeight => Err(Error::::InsufficientWeight), - Unprocessable { permanent: false } => Err(Error::::TemporarilyUnprocessable), + StackLimitReached | Unprocessable { permanent: false } => + Err(Error::::TemporarilyUnprocessable), Unprocessable { permanent: true } | Processed => { page.note_processed_at_pos(pos); book_state.message_count.saturating_dec(); @@ -1250,7 +1258,7 @@ impl Pallet { let is_processed = match res { InsufficientWeight => return ItemExecutionStatus::Bailed, Unprocessable { permanent: false } => return ItemExecutionStatus::NoProgress, - Processed | Unprocessable { permanent: true } => true, + Processed | Unprocessable { permanent: true } | StackLimitReached => true, Overweight => false, }; @@ -1461,6 +1469,10 @@ impl Pallet { Self::deposit_event(Event::::ProcessingFailed { id: id.into(), origin, error }); MessageExecutionStatus::Unprocessable { permanent: true } }, + Err(error @ StackLimitReached) => { + Self::deposit_event(Event::::ProcessingFailed { id: id.into(), origin, error }); + MessageExecutionStatus::StackLimitReached + }, Ok(success) => { // Success let weight_used = meter.consumed().saturating_sub(prev_consumed); diff --git a/substrate/frame/message-queue/src/mock.rs b/substrate/frame/message-queue/src/mock.rs index 1281de6b0a66f37e265071b390981138b30dad2e..66a242d5a18ff7f72dd08a4c0a0519c82f1cfbbc 100644 --- a/substrate/frame/message-queue/src/mock.rs +++ b/substrate/frame/message-queue/src/mock.rs @@ -198,6 +198,7 @@ impl ProcessMessage for RecordingMessageProcessor { parameter_types! { pub static Callback: Box = Box::new(|_, _| {}); + pub static IgnoreStackOvError: bool = false; } /// Processed a mocked message. Messages that end with `badformat`, `corrupt`, `unsupported` or @@ -216,6 +217,8 @@ fn processing_message(msg: &[u8], origin: &MessageOrigin) -> Result<(), ProcessM Err(ProcessMessageError::Unsupported) } else if msg.ends_with("yield") { Err(ProcessMessageError::Yield) + } else if msg.ends_with("stacklimitreached") && !IgnoreStackOvError::get() { + Err(ProcessMessageError::StackLimitReached) } else { Ok(()) } diff --git a/substrate/frame/message-queue/src/tests.rs b/substrate/frame/message-queue/src/tests.rs index d6788847d57173da6a7a06740daf55946f15b15f..e89fdb8b3208e2e218f2f8ba8dd797f3d08e12bb 100644 --- a/substrate/frame/message-queue/src/tests.rs +++ b/substrate/frame/message-queue/src/tests.rs @@ -174,9 +174,10 @@ fn service_queues_failing_messages_works() { MessageQueue::enqueue_message(msg("badformat"), Here); MessageQueue::enqueue_message(msg("corrupt"), Here); MessageQueue::enqueue_message(msg("unsupported"), Here); + MessageQueue::enqueue_message(msg("stacklimitreached"), Here); MessageQueue::enqueue_message(msg("yield"), Here); // Starts with four pages. - assert_pages(&[0, 1, 2, 3]); + assert_pages(&[0, 1, 2, 3, 4]); assert_eq!(MessageQueue::service_queues(1.into_weight()), 1.into_weight()); assert_last_event::( @@ -206,9 +207,9 @@ fn service_queues_failing_messages_works() { .into(), ); assert_eq!(MessageQueue::service_queues(1.into_weight()), 1.into_weight()); - assert_eq!(System::events().len(), 3); + assert_eq!(System::events().len(), 4); // Last page with the `yield` stays in. - assert_pages(&[3]); + assert_pages(&[4]); }); } @@ -1880,3 +1881,97 @@ fn process_enqueued_on_idle_requires_enough_weight() { assert_eq!(MessagesProcessed::take(), vec![]); }) } + +/// A message that reports `StackLimitReached` will not be put into the overweight queue when +/// executed from the top level. +#[test] +fn process_discards_stack_ov_message() { + use MessageOrigin::*; + build_and_execute::(|| { + MessageQueue::enqueue_message(msg("stacklimitreached"), Here); + + MessageQueue::service_queues(10.into_weight()); + + assert_last_event::( + Event::ProcessingFailed { + id: blake2_256(b"stacklimitreached").into(), + origin: MessageOrigin::Here, + error: ProcessMessageError::StackLimitReached, + } + .into(), + ); + + assert!(MessagesProcessed::take().is_empty()); + // Message is gone and not overweight: + assert_pages(&[]); + }); +} + +/// A message that reports `StackLimitReached` will stay in the overweight queue when it is executed +/// by `execute_overweight`. +#[test] +fn execute_overweight_keeps_stack_ov_message() { + use MessageOrigin::*; + build_and_execute::(|| { + // We need to create a mocked message that first reports insufficient weight, and then + // `StackLimitReached`: + IgnoreStackOvError::set(true); + MessageQueue::enqueue_message(msg("stacklimitreached"), Here); + MessageQueue::service_queues(0.into_weight()); + + assert_last_event::( + Event::OverweightEnqueued { + id: blake2_256(b"stacklimitreached"), + origin: MessageOrigin::Here, + message_index: 0, + page_index: 0, + } + .into(), + ); + // Does not count as 'processed': + assert!(MessagesProcessed::take().is_empty()); + assert_pages(&[0]); + + // Now let it return `StackLimitReached`. Note that this case would normally not happen, + // since we assume that the top-level execution is the one with the most remaining stack + // depth. + IgnoreStackOvError::set(false); + // Ensure that trying to execute the message does not change any state (besides events). + System::reset_events(); + let storage_noop = StorageNoopGuard::new(); + assert_eq!( + ::execute_overweight(3.into_weight(), (Here, 0, 0)), + Err(ExecuteOverweightError::Other) + ); + assert_last_event::( + Event::ProcessingFailed { + id: blake2_256(b"stacklimitreached").into(), + origin: MessageOrigin::Here, + error: ProcessMessageError::StackLimitReached, + } + .into(), + ); + System::reset_events(); + drop(storage_noop); + + // Now let's process it normally: + IgnoreStackOvError::set(true); + assert_eq!( + ::execute_overweight(1.into_weight(), (Here, 0, 0)) + .unwrap(), + 1.into_weight() + ); + + assert_last_event::( + Event::Processed { + id: blake2_256(b"stacklimitreached").into(), + origin: MessageOrigin::Here, + weight_used: 1.into_weight(), + success: true, + } + .into(), + ); + assert_pages(&[]); + System::reset_events(); + }); +} diff --git a/substrate/frame/migrations/Cargo.toml b/substrate/frame/migrations/Cargo.toml index 4726ac5c521e7395a29d374ab195a4a5a2147ff5..69e910a4e4f6e56b2b848f9b0f402da40d73f77d 100644 --- a/substrate/frame/migrations/Cargo.toml +++ b/substrate/frame/migrations/Cargo.toml @@ -11,7 +11,7 @@ repository.workspace = true targets = ["x86_64-unknown-linux-gnu"] [dependencies] -codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = ["derive"] } +codec = { package = "parity-scale-codec", version = "3.6.12", default-features = false, features = ["derive"] } docify = "0.2.8" impl-trait-for-tuples = "0.2.2" log = "0.4.21" diff --git a/substrate/frame/mixnet/Cargo.toml b/substrate/frame/mixnet/Cargo.toml index 6a4ef5c29ac8b0afe770e51e802f39ca0409eb72..44a567d668fb3c3452b4492831b0be66595a7c05 100644 --- a/substrate/frame/mixnet/Cargo.toml +++ b/substrate/frame/mixnet/Cargo.toml @@ -4,7 +4,7 @@ name = "pallet-mixnet" version = "0.4.0" license = "Apache-2.0" authors = ["Parity Technologies "] -edition = "2021" +edition.workspace = true homepage = "https://substrate.io" repository = "https://github.com/paritytech/substrate/" readme = "README.md" @@ -16,7 +16,7 @@ workspace = true targets = ["x86_64-unknown-linux-gnu"] [dependencies] -codec = { package = "parity-scale-codec", version = "3.6.1", default-features = false, features = ["derive", "max-encoded-len"] } +codec = { package = "parity-scale-codec", version = "3.6.12", default-features = false, features = ["derive", "max-encoded-len"] } frame-benchmarking = { default-features = false, optional = true, path = "../benchmarking" } frame-support = { default-features = false, path = "../support" } frame-system = { default-features = false, path = "../system" } diff --git a/substrate/frame/multisig/Cargo.toml b/substrate/frame/multisig/Cargo.toml index 2437acbc2e231b8d9c12fef4e2089e0110193be4..649a7100325f931e940760688710f88a1fbb6154 100644 --- a/substrate/frame/multisig/Cargo.toml +++ b/substrate/frame/multisig/Cargo.toml @@ -16,7 +16,7 @@ workspace = true targets = ["x86_64-unknown-linux-gnu"] [dependencies] -codec = { package = "parity-scale-codec", version = "3.6.1", default-features = false } +codec = { package = "parity-scale-codec", version = "3.6.12", default-features = false } scale-info = { version = "2.11.1", 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/Cargo.toml b/substrate/frame/nft-fractionalization/Cargo.toml index b5a929468f7dc734ac3efb394b8a99475bb00a41..e2a7e34c637b430dbda56f1690938c1cde2b100e 100644 --- a/substrate/frame/nft-fractionalization/Cargo.toml +++ b/substrate/frame/nft-fractionalization/Cargo.toml @@ -16,7 +16,7 @@ workspace = true targets = ["x86_64-unknown-linux-gnu"] [dependencies] -codec = { package = "parity-scale-codec", version = "3.6.1", default-features = false } +codec = { package = "parity-scale-codec", version = "3.6.12", default-features = false } log = { workspace = true } scale-info = { version = "2.11.1", default-features = false, features = ["derive"] } frame-benchmarking = { path = "../benchmarking", default-features = false, optional = true } diff --git a/substrate/frame/nft-fractionalization/src/lib.rs b/substrate/frame/nft-fractionalization/src/lib.rs index e97d3802fd206ca52ee008da007b46776ea76de8..cb269f464c48aea9555498c1bdf3f4d261c01895 100644 --- a/substrate/frame/nft-fractionalization/src/lib.rs +++ b/substrate/frame/nft-fractionalization/src/lib.rs @@ -75,7 +75,7 @@ pub mod pallet { AssetId, Balance as AssetBalance, Fortitude::Polite, Precision::{BestEffort, Exact}, - Preservation::Preserve, + Preservation::{Expendable, Preserve}, }, }, BoundedVec, PalletId, @@ -374,7 +374,7 @@ pub mod pallet { account: &T::AccountId, amount: AssetBalanceOf, ) -> DispatchResult { - T::Assets::burn_from(asset_id.clone(), account, amount, Exact, Polite)?; + T::Assets::burn_from(asset_id.clone(), account, amount, Expendable, Exact, Polite)?; T::Assets::start_destroy(asset_id, None) } diff --git a/substrate/frame/nfts/Cargo.toml b/substrate/frame/nfts/Cargo.toml index 4f818ea3e08c52e741124f42463f3b9ecc3ae9c9..5c5c011c94ea27467e5b8bbd18fda890a181acf2 100644 --- a/substrate/frame/nfts/Cargo.toml +++ b/substrate/frame/nfts/Cargo.toml @@ -16,7 +16,7 @@ workspace = true targets = ["x86_64-unknown-linux-gnu"] [dependencies] -codec = { package = "parity-scale-codec", version = "3.6.1", default-features = false } +codec = { package = "parity-scale-codec", version = "3.6.12", default-features = false } enumflags2 = { version = "0.7.7" } log = { workspace = true } scale-info = { version = "2.11.1", default-features = false, features = ["derive"] } diff --git a/substrate/frame/nfts/runtime-api/Cargo.toml b/substrate/frame/nfts/runtime-api/Cargo.toml index 84cbd1f51c98c673df2f9084d34fad77ec69dd54..6bee98fb51e0c908dfb70d28891e91cb55a7c6ea 100644 --- a/substrate/frame/nfts/runtime-api/Cargo.toml +++ b/substrate/frame/nfts/runtime-api/Cargo.toml @@ -16,7 +16,7 @@ workspace = true targets = ["x86_64-unknown-linux-gnu"] [dependencies] -codec = { package = "parity-scale-codec", version = "3.6.1", default-features = false, features = ["derive"] } +codec = { package = "parity-scale-codec", version = "3.6.12", default-features = false, features = ["derive"] } pallet-nfts = { path = "..", default-features = false } sp-api = { path = "../../../primitives/api", default-features = false } sp-std = { path = "../../../primitives/std", default-features = false } diff --git a/substrate/frame/nis/Cargo.toml b/substrate/frame/nis/Cargo.toml index d0ba74a9273152dcac8e541ee8be8a41d1a5b584..1e3a0609c46bbfc40b044eae839f9bd0303e0178 100644 --- a/substrate/frame/nis/Cargo.toml +++ b/substrate/frame/nis/Cargo.toml @@ -16,7 +16,7 @@ workspace = true targets = ["x86_64-unknown-linux-gnu"] [dependencies] -codec = { package = "parity-scale-codec", version = "3.6.1", default-features = false, features = ["derive"] } +codec = { package = "parity-scale-codec", version = "3.6.12", default-features = false, features = ["derive"] } scale-info = { version = "2.11.1", 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/nis/src/lib.rs b/substrate/frame/nis/src/lib.rs index 63287f6a1802104df4f03982f92b82010a65924b..f38755836fb9f15dd6db8eaab38f206dea43b562 100644 --- a/substrate/frame/nis/src/lib.rs +++ b/substrate/frame/nis/src/lib.rs @@ -808,7 +808,7 @@ pub mod pallet { ensure!(summary.thawed <= throttle, Error::::Throttled); let cp_amount = T::CounterpartAmount::convert(receipt.proportion); - T::Counterpart::burn_from(&who, cp_amount, Exact, Polite)?; + T::Counterpart::burn_from(&who, cp_amount, Expendable, Exact, Polite)?; // Multiply the proportion it is by the total issued. let our_account = Self::account_id(); @@ -897,6 +897,7 @@ pub mod pallet { T::Counterpart::burn_from( &who, T::CounterpartAmount::convert(receipt.proportion), + Expendable, Exact, Polite, )?; diff --git a/substrate/frame/nis/src/tests.rs b/substrate/frame/nis/src/tests.rs index 01724999ae7e9fb346f940be776e8b1273ea98f4..a17aaf421827f3aba79fa36065178922b0af6d93 100644 --- a/substrate/frame/nis/src/tests.rs +++ b/substrate/frame/nis/src/tests.rs @@ -24,7 +24,7 @@ use frame_support::{ traits::{ fungible::{hold::Inspect as InspectHold, Inspect as FunInspect, Mutate as FunMutate}, nonfungible::{Inspect, Transfer}, - tokens::{Fortitude::Force, Precision::Exact}, + tokens::{Fortitude::Force, Precision::Exact, Preservation::Expendable}, }, }; use sp_arithmetic::Perquintill; @@ -646,9 +646,9 @@ fn thaw_when_issuance_lower_works() { enlarge(100, 1); // Everybody else's balances goes down by 25% - assert_ok!(Balances::burn_from(&2, 25, Exact, Force)); - assert_ok!(Balances::burn_from(&3, 25, Exact, Force)); - assert_ok!(Balances::burn_from(&4, 25, Exact, Force)); + assert_ok!(Balances::burn_from(&2, 25, Expendable, Exact, Force)); + assert_ok!(Balances::burn_from(&3, 25, Expendable, Exact, Force)); + assert_ok!(Balances::burn_from(&4, 25, Expendable, Exact, Force)); run_to_block(4); assert_ok!(Nis::thaw_private(signed(1), 0, None)); diff --git a/substrate/frame/node-authorization/Cargo.toml b/substrate/frame/node-authorization/Cargo.toml index 63376163cdcb78baa03a266189d3e52ee13466a7..17ed16d2623368826f1ad93c6b4f5032775319cf 100644 --- a/substrate/frame/node-authorization/Cargo.toml +++ b/substrate/frame/node-authorization/Cargo.toml @@ -15,7 +15,7 @@ workspace = true targets = ["x86_64-unknown-linux-gnu"] [dependencies] -codec = { package = "parity-scale-codec", version = "3.6.1", default-features = false, features = ["derive"] } +codec = { package = "parity-scale-codec", version = "3.6.12", default-features = false, features = ["derive"] } log = { workspace = true } scale-info = { version = "2.11.1", default-features = false, features = ["derive"] } frame-support = { path = "../support", default-features = false } diff --git a/substrate/frame/node-authorization/src/lib.rs b/substrate/frame/node-authorization/src/lib.rs index 9019a863ad8124fdb8aacac6a8e532d860861730..a7967536079f9cf1c72940ff1cdc8847052e9318 100644 --- a/substrate/frame/node-authorization/src/lib.rs +++ b/substrate/frame/node-authorization/src/lib.rs @@ -47,7 +47,7 @@ pub mod weights; pub use pallet::*; use sp_core::OpaquePeerId as PeerId; use sp_runtime::traits::StaticLookup; -use sp_std::{collections::btree_set::BTreeSet, iter::FromIterator, prelude::*}; +use sp_std::{collections::btree_set::BTreeSet, prelude::*}; pub use weights::WeightInfo; type AccountIdLookupOf = <::Lookup as StaticLookup>::Source; diff --git a/substrate/frame/nomination-pools/Cargo.toml b/substrate/frame/nomination-pools/Cargo.toml index 55e9ef6fbd3382f65f2d4be3cfdb5eed1b318345..bf4e01a3184793d638b1c87f5984a517a18e2ceb 100644 --- a/substrate/frame/nomination-pools/Cargo.toml +++ b/substrate/frame/nomination-pools/Cargo.toml @@ -16,7 +16,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] # parity -codec = { package = "parity-scale-codec", version = "3.6.1", default-features = false, features = [ +codec = { package = "parity-scale-codec", version = "3.6.12", default-features = false, features = [ "derive", ] } scale-info = { version = "2.11.1", default-features = false, features = [ @@ -34,8 +34,8 @@ sp-io = { path = "../../primitives/io", default-features = false } log = { workspace = true } # Optional: use for testing and/or fuzzing -pallet-balances = { path = "../balances", optional = true } -sp-tracing = { path = "../../primitives/tracing", optional = true } +pallet-balances = { path = "../balances", optional = true, default-features = false } +sp-tracing = { path = "../../primitives/tracing", optional = true, default-features = false } [dev-dependencies] pallet-balances = { path = "../balances" } diff --git a/substrate/frame/nomination-pools/benchmarking/Cargo.toml b/substrate/frame/nomination-pools/benchmarking/Cargo.toml index 4985d7acbec92f8258f32338bc348981922c53a9..3186bce5164cc9fa57c2601a1219b5aadfca4e50 100644 --- a/substrate/frame/nomination-pools/benchmarking/Cargo.toml +++ b/substrate/frame/nomination-pools/benchmarking/Cargo.toml @@ -17,7 +17,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] # parity -codec = { package = "parity-scale-codec", version = "3.6.1", default-features = false, features = ["derive"] } +codec = { package = "parity-scale-codec", version = "3.6.12", default-features = false, features = ["derive"] } scale-info = { version = "2.11.1", default-features = false, features = ["derive"] } # FRAME diff --git a/substrate/frame/nomination-pools/benchmarking/src/inner.rs b/substrate/frame/nomination-pools/benchmarking/src/inner.rs new file mode 100644 index 0000000000000000000000000000000000000000..277060e7f640f962bd112a6f337339ec1cf2559e --- /dev/null +++ b/substrate/frame/nomination-pools/benchmarking/src/inner.rs @@ -0,0 +1,846 @@ +// 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 the nomination pools coupled with the staking and bags list pallets. + +use frame_benchmarking::v1::{account, whitelist_account}; +use frame_election_provider_support::SortedListProvider; +use frame_support::{ + assert_ok, ensure, + traits::{ + fungible::{Inspect, Mutate, Unbalanced}, + Get, + }, +}; +use frame_system::RawOrigin as RuntimeOrigin; +use pallet_nomination_pools::{ + BalanceOf, BondExtra, BondedPoolInner, BondedPools, ClaimPermission, ClaimPermissions, + Commission, CommissionChangeRate, CommissionClaimPermission, ConfigOp, GlobalMaxCommission, + MaxPoolMembers, MaxPoolMembersPerPool, MaxPools, Metadata, MinCreateBond, MinJoinBond, + Pallet as Pools, PoolMembers, PoolRoles, PoolState, RewardPools, SubPoolsStorage, +}; +use pallet_staking::MaxNominationsOf; +use sp_runtime::{ + traits::{Bounded, StaticLookup, Zero}, + Perbill, +}; +use sp_staking::{EraIndex, StakingInterface}; +use sp_std::{vec, vec::Vec}; +// `frame_benchmarking::benchmarks!` macro needs this +use pallet_nomination_pools::Call; + +type CurrencyOf = ::Currency; + +const USER_SEED: u32 = 0; +const MAX_SPANS: u32 = 100; + +pub(crate) type VoterBagsListInstance = pallet_bags_list::Instance1; +pub trait Config: + pallet_nomination_pools::Config + + pallet_staking::Config + + pallet_bags_list::Config +{ +} + +pub struct Pallet(Pools); + +fn create_funded_user_with_balance( + string: &'static str, + n: u32, + balance: BalanceOf, +) -> T::AccountId { + let user = account(string, n, USER_SEED); + T::Currency::set_balance(&user, balance); + user +} + +// Create a bonded pool account, bonding `balance` and giving the account `balance * 2` free +// balance. +fn create_pool_account( + n: u32, + balance: BalanceOf, + commission: Option, +) -> (T::AccountId, T::AccountId) { + let ed = CurrencyOf::::minimum_balance(); + let pool_creator: T::AccountId = + create_funded_user_with_balance::("pool_creator", n, ed + balance * 2u32.into()); + let pool_creator_lookup = T::Lookup::unlookup(pool_creator.clone()); + + Pools::::create( + RuntimeOrigin::Signed(pool_creator.clone()).into(), + balance, + pool_creator_lookup.clone(), + pool_creator_lookup.clone(), + pool_creator_lookup, + ) + .unwrap(); + + if let Some(c) = commission { + let pool_id = pallet_nomination_pools::LastPoolId::::get(); + Pools::::set_commission( + RuntimeOrigin::Signed(pool_creator.clone()).into(), + pool_id, + Some((c, pool_creator.clone())), + ) + .expect("pool just created, commission can be set by root; qed"); + } + + let pool_account = pallet_nomination_pools::BondedPools::::iter() + .find(|(_, bonded_pool)| bonded_pool.roles.depositor == pool_creator) + .map(|(pool_id, _)| Pools::::create_bonded_account(pool_id)) + .expect("pool_creator created a pool above"); + + (pool_creator, pool_account) +} + +fn vote_to_balance( + vote: u64, +) -> Result, &'static str> { + vote.try_into().map_err(|_| "could not convert u64 to Balance") +} + +#[allow(unused)] +struct ListScenario { + /// Stash/Controller that is expected to be moved. + origin1: T::AccountId, + creator1: T::AccountId, + dest_weight: BalanceOf, + origin1_member: Option, +} + +impl ListScenario { + /// An expensive scenario for bags-list implementation: + /// + /// - the node to be updated (r) is the head of a bag that has at least one other node. The bag + /// itself will need to be read and written to update its head. The node pointed to by r.next + /// will need to be read and written as it will need to have its prev pointer updated. Note + /// that there are two other worst case scenarios for bag removal: 1) the node is a tail and + /// 2) the node is a middle node with prev and next; all scenarios end up with the same number + /// of storage reads and writes. + /// + /// - the destination bag has at least one node, which will need its next pointer updated. + pub(crate) fn new( + origin_weight: BalanceOf, + is_increase: bool, + ) -> Result { + ensure!(!origin_weight.is_zero(), "origin weight must be greater than 0"); + + ensure!( + pallet_nomination_pools::MaxPools::::get().unwrap_or(0) >= 3, + "must allow at least three pools for benchmarks" + ); + + // Burn the entire issuance. + CurrencyOf::::set_total_issuance(Zero::zero()); + + // Create accounts with the origin weight + let (pool_creator1, pool_origin1) = + create_pool_account::(USER_SEED + 1, origin_weight, Some(Perbill::from_percent(50))); + + T::Staking::nominate( + &pool_origin1, + // NOTE: these don't really need to be validators. + vec![account("random_validator", 0, USER_SEED)], + )?; + + let (_, pool_origin2) = + create_pool_account::(USER_SEED + 2, origin_weight, Some(Perbill::from_percent(50))); + + T::Staking::nominate( + &pool_origin2, + vec![account("random_validator", 0, USER_SEED)].clone(), + )?; + + // Find a destination weight that will trigger the worst case scenario + let dest_weight_as_vote = ::VoterList::score_update_worst_case( + &pool_origin1, + is_increase, + ); + + let dest_weight: BalanceOf = + dest_weight_as_vote.try_into().map_err(|_| "could not convert u64 to Balance")?; + + // Create an account with the worst case destination weight + let (_, pool_dest1) = + create_pool_account::(USER_SEED + 3, dest_weight, Some(Perbill::from_percent(50))); + + T::Staking::nominate(&pool_dest1, vec![account("random_validator", 0, USER_SEED)])?; + + let weight_of = pallet_staking::Pallet::::weight_of_fn(); + assert_eq!(vote_to_balance::(weight_of(&pool_origin1)).unwrap(), origin_weight); + assert_eq!(vote_to_balance::(weight_of(&pool_origin2)).unwrap(), origin_weight); + assert_eq!(vote_to_balance::(weight_of(&pool_dest1)).unwrap(), dest_weight); + + Ok(ListScenario { + origin1: pool_origin1, + creator1: pool_creator1, + dest_weight, + origin1_member: None, + }) + } + + fn add_joiner(mut self, amount: BalanceOf) -> Self { + let amount = MinJoinBond::::get() + .max(CurrencyOf::::minimum_balance()) + // Max `amount` with minimum thresholds for account balance and joining a pool + // to ensure 1) the user can be created and 2) can join the pool + .max(amount); + + let joiner: T::AccountId = account("joiner", USER_SEED, 0); + self.origin1_member = Some(joiner.clone()); + CurrencyOf::::set_balance(&joiner, amount * 2u32.into()); + + let original_bonded = T::Staking::active_stake(&self.origin1).unwrap(); + + // Unbond `amount` from the underlying pool account so when the member joins + // we will maintain `current_bonded`. + T::Staking::unbond(&self.origin1, amount).expect("the pool was created in `Self::new`."); + + // Account pool points for the unbonded balance. + BondedPools::::mutate(&1, |maybe_pool| { + maybe_pool.as_mut().map(|pool| pool.points -= amount) + }); + + Pools::::join(RuntimeOrigin::Signed(joiner.clone()).into(), amount, 1).unwrap(); + + // check that the vote weight is still the same as the original bonded + let weight_of = pallet_staking::Pallet::::weight_of_fn(); + assert_eq!(vote_to_balance::(weight_of(&self.origin1)).unwrap(), original_bonded); + + // check the member was added correctly + let member = PoolMembers::::get(&joiner).unwrap(); + assert_eq!(member.points, amount); + assert_eq!(member.pool_id, 1); + + self + } +} + +frame_benchmarking::benchmarks! { + join { + let origin_weight = Pools::::depositor_min_bond() * 2u32.into(); + + // setup the worst case list scenario. + let scenario = ListScenario::::new(origin_weight, true)?; + assert_eq!( + T::Staking::active_stake(&scenario.origin1).unwrap(), + origin_weight + ); + + let max_additional = scenario.dest_weight - origin_weight; + let joiner_free = CurrencyOf::::minimum_balance() + max_additional; + + let joiner: T::AccountId + = create_funded_user_with_balance::("joiner", 0, joiner_free); + + whitelist_account!(joiner); + }: _(RuntimeOrigin::Signed(joiner.clone()), max_additional, 1) + verify { + assert_eq!(CurrencyOf::::balance(&joiner), joiner_free - max_additional); + assert_eq!( + T::Staking::active_stake(&scenario.origin1).unwrap(), + scenario.dest_weight + ); + } + + bond_extra_transfer { + let origin_weight = Pools::::depositor_min_bond() * 2u32.into(); + let scenario = ListScenario::::new(origin_weight, true)?; + let extra = scenario.dest_weight - origin_weight; + + // creator of the src pool will bond-extra, bumping itself to dest bag. + + }: bond_extra(RuntimeOrigin::Signed(scenario.creator1.clone()), BondExtra::FreeBalance(extra)) + verify { + assert!( + T::Staking::active_stake(&scenario.origin1).unwrap() >= + scenario.dest_weight + ); + } + + bond_extra_other { + let claimer: T::AccountId = account("claimer", USER_SEED + 4, 0); + + let origin_weight = Pools::::depositor_min_bond() * 2u32.into(); + let scenario = ListScenario::::new(origin_weight, true)?; + let extra = (scenario.dest_weight - origin_weight).max(CurrencyOf::::minimum_balance()); + + // set claim preferences to `PermissionlessAll` to any account to bond extra on member's behalf. + let _ = Pools::::set_claim_permission(RuntimeOrigin::Signed(scenario.creator1.clone()).into(), ClaimPermission::PermissionlessAll); + + // transfer exactly `extra` to the depositor of the src pool (1), + let reward_account1 = Pools::::create_reward_account(1); + assert!(extra >= CurrencyOf::::minimum_balance()); + let _ = CurrencyOf::::mint_into(&reward_account1, extra); + + }: _(RuntimeOrigin::Signed(claimer), T::Lookup::unlookup(scenario.creator1.clone()), BondExtra::Rewards) + verify { + // commission of 50% deducted here. + assert!( + T::Staking::active_stake(&scenario.origin1).unwrap() >= + scenario.dest_weight / 2u32.into() + ); + } + + claim_payout { + let claimer: T::AccountId = account("claimer", USER_SEED + 4, 0); + let commission = Perbill::from_percent(50); + let origin_weight = Pools::::depositor_min_bond() * 2u32.into(); + let ed = CurrencyOf::::minimum_balance(); + let (depositor, pool_account) = create_pool_account::(0, origin_weight, Some(commission)); + let reward_account = Pools::::create_reward_account(1); + + // Send funds to the reward account of the pool + CurrencyOf::::set_balance(&reward_account, ed + origin_weight); + + // set claim preferences to `PermissionlessAll` so any account can claim rewards on member's + // behalf. + let _ = Pools::::set_claim_permission(RuntimeOrigin::Signed(depositor.clone()).into(), ClaimPermission::PermissionlessAll); + + // Sanity check + assert_eq!( + CurrencyOf::::balance(&depositor), + origin_weight + ); + + whitelist_account!(depositor); + }:claim_payout_other(RuntimeOrigin::Signed(claimer), depositor.clone()) + verify { + assert_eq!( + CurrencyOf::::balance(&depositor), + origin_weight + commission * origin_weight + ); + assert_eq!( + CurrencyOf::::balance(&reward_account), + ed + commission * origin_weight + ); + } + + + unbond { + // The weight the nominator will start at. The value used here is expected to be + // significantly higher than the first position in a list (e.g. the first bag threshold). + let origin_weight = Pools::::depositor_min_bond() * 200u32.into(); + let scenario = ListScenario::::new(origin_weight, false)?; + let amount = origin_weight - scenario.dest_weight; + + let scenario = scenario.add_joiner(amount); + let member_id = scenario.origin1_member.unwrap().clone(); + let member_id_lookup = T::Lookup::unlookup(member_id.clone()); + let all_points = PoolMembers::::get(&member_id).unwrap().points; + whitelist_account!(member_id); + }: _(RuntimeOrigin::Signed(member_id.clone()), member_id_lookup, all_points) + verify { + let bonded_after = T::Staking::active_stake(&scenario.origin1).unwrap(); + // We at least went down to the destination bag + assert!(bonded_after <= scenario.dest_weight); + let member = PoolMembers::::get( + &member_id + ) + .unwrap(); + assert_eq!( + member.unbonding_eras.keys().cloned().collect::>(), + vec![0 + T::Staking::bonding_duration()] + ); + assert_eq!( + member.unbonding_eras.values().cloned().collect::>(), + vec![all_points] + ); + } + + pool_withdraw_unbonded { + let s in 0 .. MAX_SPANS; + + let min_create_bond = Pools::::depositor_min_bond(); + let (depositor, pool_account) = create_pool_account::(0, min_create_bond, None); + + // Add a new member + let min_join_bond = MinJoinBond::::get().max(CurrencyOf::::minimum_balance()); + let joiner = create_funded_user_with_balance::("joiner", 0, min_join_bond * 2u32.into()); + Pools::::join(RuntimeOrigin::Signed(joiner.clone()).into(), min_join_bond, 1) + .unwrap(); + + // Sanity check join worked + assert_eq!( + T::Staking::active_stake(&pool_account).unwrap(), + min_create_bond + min_join_bond + ); + assert_eq!(CurrencyOf::::balance(&joiner), min_join_bond); + + // Unbond the new member + Pools::::fully_unbond(RuntimeOrigin::Signed(joiner.clone()).into(), joiner.clone()).unwrap(); + + // Sanity check that unbond worked + assert_eq!( + T::Staking::active_stake(&pool_account).unwrap(), + min_create_bond + ); + assert_eq!(pallet_staking::Ledger::::get(&pool_account).unwrap().unlocking.len(), 1); + // Set the current era + pallet_staking::CurrentEra::::put(EraIndex::max_value()); + + // Add `s` count of slashing spans to storage. + pallet_staking::benchmarking::add_slashing_spans::(&pool_account, s); + whitelist_account!(pool_account); + }: _(RuntimeOrigin::Signed(pool_account.clone()), 1, s) + verify { + // The joiners funds didn't change + assert_eq!(CurrencyOf::::balance(&joiner), min_join_bond); + // The unlocking chunk was removed + assert_eq!(pallet_staking::Ledger::::get(pool_account).unwrap().unlocking.len(), 0); + } + + withdraw_unbonded_update { + let s in 0 .. MAX_SPANS; + + let min_create_bond = Pools::::depositor_min_bond(); + let (depositor, pool_account) = create_pool_account::(0, min_create_bond, None); + + // Add a new member + let min_join_bond = MinJoinBond::::get().max(CurrencyOf::::minimum_balance()); + let joiner = create_funded_user_with_balance::("joiner", 0, min_join_bond * 2u32.into()); + let joiner_lookup = T::Lookup::unlookup(joiner.clone()); + Pools::::join(RuntimeOrigin::Signed(joiner.clone()).into(), min_join_bond, 1) + .unwrap(); + + // Sanity check join worked + assert_eq!( + T::Staking::active_stake(&pool_account).unwrap(), + min_create_bond + min_join_bond + ); + assert_eq!(CurrencyOf::::balance(&joiner), min_join_bond); + + // Unbond the new member + pallet_staking::CurrentEra::::put(0); + Pools::::fully_unbond(RuntimeOrigin::Signed(joiner.clone()).into(), joiner.clone()).unwrap(); + + // Sanity check that unbond worked + assert_eq!( + T::Staking::active_stake(&pool_account).unwrap(), + min_create_bond + ); + assert_eq!(pallet_staking::Ledger::::get(&pool_account).unwrap().unlocking.len(), 1); + + // Set the current era to ensure we can withdraw unbonded funds + pallet_staking::CurrentEra::::put(EraIndex::max_value()); + + pallet_staking::benchmarking::add_slashing_spans::(&pool_account, s); + whitelist_account!(joiner); + }: withdraw_unbonded(RuntimeOrigin::Signed(joiner.clone()), joiner_lookup, s) + verify { + assert_eq!( + CurrencyOf::::balance(&joiner), min_join_bond * 2u32.into() + ); + // The unlocking chunk was removed + assert_eq!(pallet_staking::Ledger::::get(&pool_account).unwrap().unlocking.len(), 0); + } + + withdraw_unbonded_kill { + let s in 0 .. MAX_SPANS; + + let min_create_bond = Pools::::depositor_min_bond(); + let (depositor, pool_account) = create_pool_account::(0, min_create_bond, None); + let depositor_lookup = T::Lookup::unlookup(depositor.clone()); + + // We set the pool to the destroying state so the depositor can leave + BondedPools::::try_mutate(&1, |maybe_bonded_pool| { + maybe_bonded_pool.as_mut().ok_or(()).map(|bonded_pool| { + bonded_pool.state = PoolState::Destroying; + }) + }) + .unwrap(); + + // Unbond the creator + pallet_staking::CurrentEra::::put(0); + // Simulate some rewards so we can check if the rewards storage is cleaned up. We check this + // here to ensure the complete flow for destroying a pool works - the reward pool account + // should never exist by time the depositor withdraws so we test that it gets cleaned + // up when unbonding. + let reward_account = Pools::::create_reward_account(1); + assert!(frame_system::Account::::contains_key(&reward_account)); + Pools::::fully_unbond(RuntimeOrigin::Signed(depositor.clone()).into(), depositor.clone()).unwrap(); + + // Sanity check that unbond worked + assert_eq!( + T::Staking::active_stake(&pool_account).unwrap(), + Zero::zero() + ); + assert_eq!( + CurrencyOf::::balance(&pool_account), + min_create_bond + ); + assert_eq!(pallet_staking::Ledger::::get(&pool_account).unwrap().unlocking.len(), 1); + + // Set the current era to ensure we can withdraw unbonded funds + pallet_staking::CurrentEra::::put(EraIndex::max_value()); + + // Some last checks that storage items we expect to get cleaned up are present + assert!(pallet_staking::Ledger::::contains_key(&pool_account)); + assert!(BondedPools::::contains_key(&1)); + assert!(SubPoolsStorage::::contains_key(&1)); + assert!(RewardPools::::contains_key(&1)); + assert!(PoolMembers::::contains_key(&depositor)); + assert!(frame_system::Account::::contains_key(&reward_account)); + + whitelist_account!(depositor); + }: withdraw_unbonded(RuntimeOrigin::Signed(depositor.clone()), depositor_lookup, s) + verify { + // Pool removal worked + assert!(!pallet_staking::Ledger::::contains_key(&pool_account)); + assert!(!BondedPools::::contains_key(&1)); + assert!(!SubPoolsStorage::::contains_key(&1)); + assert!(!RewardPools::::contains_key(&1)); + assert!(!PoolMembers::::contains_key(&depositor)); + assert!(!frame_system::Account::::contains_key(&pool_account)); + assert!(!frame_system::Account::::contains_key(&reward_account)); + + // Funds where transferred back correctly + assert_eq!( + CurrencyOf::::balance(&depositor), + // gets bond back + rewards collecting when unbonding + min_create_bond * 2u32.into() + CurrencyOf::::minimum_balance() + ); + } + + create { + let min_create_bond = Pools::::depositor_min_bond(); + let depositor: T::AccountId = account("depositor", USER_SEED, 0); + let depositor_lookup = T::Lookup::unlookup(depositor.clone()); + + // Give the depositor some balance to bond + CurrencyOf::::set_balance(&depositor, min_create_bond * 2u32.into()); + + // Make sure no Pools exist at a pre-condition for our verify checks + assert_eq!(RewardPools::::count(), 0); + assert_eq!(BondedPools::::count(), 0); + + whitelist_account!(depositor); + }: _( + RuntimeOrigin::Signed(depositor.clone()), + min_create_bond, + depositor_lookup.clone(), + depositor_lookup.clone(), + depositor_lookup + ) + verify { + assert_eq!(RewardPools::::count(), 1); + assert_eq!(BondedPools::::count(), 1); + let (_, new_pool) = BondedPools::::iter().next().unwrap(); + assert_eq!( + new_pool, + BondedPoolInner { + commission: Commission::default(), + member_counter: 1, + points: min_create_bond, + roles: PoolRoles { + depositor: depositor.clone(), + root: Some(depositor.clone()), + nominator: Some(depositor.clone()), + bouncer: Some(depositor.clone()), + }, + state: PoolState::Open, + } + ); + assert_eq!( + T::Staking::active_stake(&Pools::::create_bonded_account(1)), + Ok(min_create_bond) + ); + } + + nominate { + let n in 1 .. MaxNominationsOf::::get(); + + // Create a pool + let min_create_bond = Pools::::depositor_min_bond() * 2u32.into(); + let (depositor, pool_account) = create_pool_account::(0, min_create_bond, None); + + // Create some accounts to nominate. For the sake of benchmarking they don't need to be + // actual validators + let validators: Vec<_> = (0..n) + .map(|i| account("stash", USER_SEED, i)) + .collect(); + + whitelist_account!(depositor); + }:_(RuntimeOrigin::Signed(depositor.clone()), 1, validators) + verify { + assert_eq!(RewardPools::::count(), 1); + assert_eq!(BondedPools::::count(), 1); + let (_, new_pool) = BondedPools::::iter().next().unwrap(); + assert_eq!( + new_pool, + BondedPoolInner { + commission: Commission::default(), + member_counter: 1, + points: min_create_bond, + roles: PoolRoles { + depositor: depositor.clone(), + root: Some(depositor.clone()), + nominator: Some(depositor.clone()), + bouncer: Some(depositor.clone()), + }, + state: PoolState::Open, + } + ); + assert_eq!( + T::Staking::active_stake(&Pools::::create_bonded_account(1)), + Ok(min_create_bond) + ); + } + + set_state { + // Create a pool + let min_create_bond = Pools::::depositor_min_bond(); + let (depositor, pool_account) = create_pool_account::(0, min_create_bond, None); + BondedPools::::mutate(&1, |maybe_pool| { + // Force the pool into an invalid state + maybe_pool.as_mut().map(|pool| pool.points = min_create_bond * 10u32.into()); + }); + + let caller = account("caller", 0, USER_SEED); + whitelist_account!(caller); + }:_(RuntimeOrigin::Signed(caller), 1, PoolState::Destroying) + verify { + assert_eq!(BondedPools::::get(1).unwrap().state, PoolState::Destroying); + } + + set_metadata { + let n in 1 .. ::MaxMetadataLen::get(); + + // Create a pool + let (depositor, pool_account) = create_pool_account::(0, Pools::::depositor_min_bond() * 2u32.into(), None); + + // Create metadata of the max possible size + let metadata: Vec = (0..n).map(|_| 42).collect(); + + whitelist_account!(depositor); + }:_(RuntimeOrigin::Signed(depositor), 1, metadata.clone()) + verify { + assert_eq!(Metadata::::get(&1), metadata); + } + + set_configs { + }:_( + RuntimeOrigin::Root, + ConfigOp::Set(BalanceOf::::max_value()), + ConfigOp::Set(BalanceOf::::max_value()), + ConfigOp::Set(u32::MAX), + ConfigOp::Set(u32::MAX), + ConfigOp::Set(u32::MAX), + ConfigOp::Set(Perbill::max_value()) + ) verify { + assert_eq!(MinJoinBond::::get(), BalanceOf::::max_value()); + assert_eq!(MinCreateBond::::get(), BalanceOf::::max_value()); + assert_eq!(MaxPools::::get(), Some(u32::MAX)); + assert_eq!(MaxPoolMembers::::get(), Some(u32::MAX)); + assert_eq!(MaxPoolMembersPerPool::::get(), Some(u32::MAX)); + assert_eq!(GlobalMaxCommission::::get(), Some(Perbill::max_value())); + } + + update_roles { + let first_id = pallet_nomination_pools::LastPoolId::::get() + 1; + let (root, _) = create_pool_account::(0, Pools::::depositor_min_bond() * 2u32.into(), None); + let random: T::AccountId = account("but is anything really random in computers..?", 0, USER_SEED); + }:_( + RuntimeOrigin::Signed(root.clone()), + first_id, + ConfigOp::Set(random.clone()), + ConfigOp::Set(random.clone()), + ConfigOp::Set(random.clone()) + ) verify { + assert_eq!( + pallet_nomination_pools::BondedPools::::get(first_id).unwrap().roles, + pallet_nomination_pools::PoolRoles { + depositor: root, + nominator: Some(random.clone()), + bouncer: Some(random.clone()), + root: Some(random), + }, + ) + } + + chill { + // Create a pool + let (depositor, pool_account) = create_pool_account::(0, Pools::::depositor_min_bond() * 2u32.into(), None); + + // Nominate with the pool. + let validators: Vec<_> = (0..MaxNominationsOf::::get()) + .map(|i| account("stash", USER_SEED, i)) + .collect(); + + assert_ok!(T::Staking::nominate(&pool_account, validators)); + assert!(T::Staking::nominations(&Pools::::create_bonded_account(1)).is_some()); + + whitelist_account!(depositor); + }:_(RuntimeOrigin::Signed(depositor.clone()), 1) + verify { + assert!(T::Staking::nominations(&Pools::::create_bonded_account(1)).is_none()); + } + + set_commission { + // Create a pool - do not set a commission yet. + let (depositor, pool_account) = create_pool_account::(0, Pools::::depositor_min_bond() * 2u32.into(), None); + // set a max commission + Pools::::set_commission_max(RuntimeOrigin::Signed(depositor.clone()).into(), 1u32.into(), Perbill::from_percent(50)).unwrap(); + // set a change rate + Pools::::set_commission_change_rate(RuntimeOrigin::Signed(depositor.clone()).into(), 1u32.into(), CommissionChangeRate { + max_increase: Perbill::from_percent(20), + min_delay: 0u32.into(), + }).unwrap(); + // set a claim permission to an account. + Pools::::set_commission_claim_permission( + RuntimeOrigin::Signed(depositor.clone()).into(), + 1u32.into(), + Some(CommissionClaimPermission::Account(depositor.clone())) + ).unwrap(); + + }:_(RuntimeOrigin::Signed(depositor.clone()), 1u32.into(), Some((Perbill::from_percent(20), depositor.clone()))) + verify { + assert_eq!(BondedPools::::get(1).unwrap().commission, Commission { + current: Some((Perbill::from_percent(20), depositor.clone())), + max: Some(Perbill::from_percent(50)), + change_rate: Some(CommissionChangeRate { + max_increase: Perbill::from_percent(20), + min_delay: 0u32.into() + }), + throttle_from: Some(1u32.into()), + claim_permission: Some(CommissionClaimPermission::Account(depositor)), + }); + } + + set_commission_max { + // Create a pool, setting a commission that will update when max commission is set. + let (depositor, pool_account) = create_pool_account::(0, Pools::::depositor_min_bond() * 2u32.into(), Some(Perbill::from_percent(50))); + }:_(RuntimeOrigin::Signed(depositor.clone()), 1u32.into(), Perbill::from_percent(50)) + verify { + assert_eq!( + BondedPools::::get(1).unwrap().commission, Commission { + current: Some((Perbill::from_percent(50), depositor)), + max: Some(Perbill::from_percent(50)), + change_rate: None, + throttle_from: Some(0u32.into()), + claim_permission: None, + }); + } + + set_commission_change_rate { + // Create a pool + let (depositor, pool_account) = create_pool_account::(0, Pools::::depositor_min_bond() * 2u32.into(), None); + }:_(RuntimeOrigin::Signed(depositor.clone()), 1u32.into(), CommissionChangeRate { + max_increase: Perbill::from_percent(50), + min_delay: 1000u32.into(), + }) + verify { + assert_eq!( + BondedPools::::get(1).unwrap().commission, Commission { + current: None, + max: None, + change_rate: Some(CommissionChangeRate { + max_increase: Perbill::from_percent(50), + min_delay: 1000u32.into(), + }), + throttle_from: Some(1_u32.into()), + claim_permission: None, + }); + } + + set_commission_claim_permission { + // Create a pool. + let (depositor, pool_account) = create_pool_account::(0, Pools::::depositor_min_bond() * 2u32.into(), None); + }:_(RuntimeOrigin::Signed(depositor.clone()), 1u32.into(), Some(CommissionClaimPermission::Account(depositor.clone()))) + verify { + assert_eq!( + BondedPools::::get(1).unwrap().commission, Commission { + current: None, + max: None, + change_rate: None, + throttle_from: None, + claim_permission: Some(CommissionClaimPermission::Account(depositor)), + }); + } + + set_claim_permission { + // Create a pool + let min_create_bond = Pools::::depositor_min_bond(); + let (depositor, pool_account) = create_pool_account::(0, min_create_bond, None); + + // Join pool + let min_join_bond = MinJoinBond::::get().max(CurrencyOf::::minimum_balance()); + let joiner = create_funded_user_with_balance::("joiner", 0, min_join_bond * 4u32.into()); + let joiner_lookup = T::Lookup::unlookup(joiner.clone()); + Pools::::join(RuntimeOrigin::Signed(joiner.clone()).into(), min_join_bond, 1) + .unwrap(); + + // Sanity check join worked + assert_eq!( + T::Staking::active_stake(&pool_account).unwrap(), + min_create_bond + min_join_bond + ); + }:_(RuntimeOrigin::Signed(joiner.clone()), ClaimPermission::Permissioned) + verify { + assert_eq!(ClaimPermissions::::get(joiner), ClaimPermission::Permissioned); + } + + claim_commission { + let claimer: T::AccountId = account("claimer_member", USER_SEED + 4, 0); + let commission = Perbill::from_percent(50); + let origin_weight = Pools::::depositor_min_bond() * 2u32.into(); + let ed = CurrencyOf::::minimum_balance(); + let (depositor, pool_account) = create_pool_account::(0, origin_weight, Some(commission)); + let reward_account = Pools::::create_reward_account(1); + CurrencyOf::::set_balance(&reward_account, ed + origin_weight); + + // member claims a payout to make some commission available. + let _ = Pools::::claim_payout(RuntimeOrigin::Signed(claimer.clone()).into()); + // set a claim permission to an account. + let _ = Pools::::set_commission_claim_permission( + RuntimeOrigin::Signed(depositor.clone()).into(), + 1u32.into(), + Some(CommissionClaimPermission::Account(claimer)) + ); + whitelist_account!(depositor); + }:_(RuntimeOrigin::Signed(depositor.clone()), 1u32.into()) + verify { + assert_eq!( + CurrencyOf::::balance(&depositor), + origin_weight + commission * origin_weight + ); + assert_eq!( + CurrencyOf::::balance(&reward_account), + ed + commission * origin_weight + ); + } + + adjust_pool_deposit { + // Create a pool + let (depositor, _) = create_pool_account::(0, Pools::::depositor_min_bond() * 2u32.into(), None); + + // Remove ed freeze to create a scenario where the ed deposit needs to be adjusted. + let _ = Pools::::unfreeze_pool_deposit(&Pools::::create_reward_account(1)); + assert!(&Pools::::check_ed_imbalance().is_err()); + + whitelist_account!(depositor); + }:_(RuntimeOrigin::Signed(depositor), 1) + verify { + assert!(&Pools::::check_ed_imbalance().is_ok()); + } + + impl_benchmark_test_suite!( + Pallet, + crate::mock::new_test_ext(), + crate::mock::Runtime + ); +} diff --git a/substrate/frame/nomination-pools/benchmarking/src/lib.rs b/substrate/frame/nomination-pools/benchmarking/src/lib.rs index f7df173ec04eab4c681757ec21d01654b9fff9a6..45e8f1f27e99a52b5900aa5e18c5439d9d7baa5c 100644 --- a/substrate/frame/nomination-pools/benchmarking/src/lib.rs +++ b/substrate/frame/nomination-pools/benchmarking/src/lib.rs @@ -17,836 +17,13 @@ //! Benchmarks for the nomination pools coupled with the staking and bags list pallets. -#![cfg(feature = "runtime-benchmarks")] #![cfg_attr(not(feature = "std"), no_std)] -#[cfg(test)] -mod mock; +#[cfg(feature = "runtime-benchmarks")] +pub mod inner; -use frame_benchmarking::v1::{account, whitelist_account}; -use frame_election_provider_support::SortedListProvider; -use frame_support::{ - assert_ok, ensure, - traits::{ - fungible::{Inspect, Mutate, Unbalanced}, - Get, - }, -}; -use frame_system::RawOrigin as RuntimeOrigin; -use pallet_nomination_pools::{ - BalanceOf, BondExtra, BondedPoolInner, BondedPools, ClaimPermission, ClaimPermissions, - Commission, CommissionChangeRate, CommissionClaimPermission, ConfigOp, GlobalMaxCommission, - MaxPoolMembers, MaxPoolMembersPerPool, MaxPools, Metadata, MinCreateBond, MinJoinBond, - Pallet as Pools, PoolMembers, PoolRoles, PoolState, RewardPools, SubPoolsStorage, -}; -use pallet_staking::MaxNominationsOf; -use sp_runtime::{ - traits::{Bounded, StaticLookup, Zero}, - Perbill, -}; -use sp_staking::{EraIndex, StakingInterface}; -use sp_std::{vec, vec::Vec}; -// `frame_benchmarking::benchmarks!` macro needs this -use pallet_nomination_pools::Call; +#[cfg(feature = "runtime-benchmarks")] +pub use inner::*; -type CurrencyOf = ::Currency; - -const USER_SEED: u32 = 0; -const MAX_SPANS: u32 = 100; - -type VoterBagsListInstance = pallet_bags_list::Instance1; -pub trait Config: - pallet_nomination_pools::Config - + pallet_staking::Config - + pallet_bags_list::Config -{ -} - -pub struct Pallet(Pools); - -fn create_funded_user_with_balance( - string: &'static str, - n: u32, - balance: BalanceOf, -) -> T::AccountId { - let user = account(string, n, USER_SEED); - T::Currency::set_balance(&user, balance); - user -} - -// Create a bonded pool account, bonding `balance` and giving the account `balance * 2` free -// balance. -fn create_pool_account( - n: u32, - balance: BalanceOf, - commission: Option, -) -> (T::AccountId, T::AccountId) { - let ed = CurrencyOf::::minimum_balance(); - let pool_creator: T::AccountId = - create_funded_user_with_balance::("pool_creator", n, ed + balance * 2u32.into()); - let pool_creator_lookup = T::Lookup::unlookup(pool_creator.clone()); - - Pools::::create( - RuntimeOrigin::Signed(pool_creator.clone()).into(), - balance, - pool_creator_lookup.clone(), - pool_creator_lookup.clone(), - pool_creator_lookup, - ) - .unwrap(); - - if let Some(c) = commission { - let pool_id = pallet_nomination_pools::LastPoolId::::get(); - Pools::::set_commission( - RuntimeOrigin::Signed(pool_creator.clone()).into(), - pool_id, - Some((c, pool_creator.clone())), - ) - .expect("pool just created, commission can be set by root; qed"); - } - - let pool_account = pallet_nomination_pools::BondedPools::::iter() - .find(|(_, bonded_pool)| bonded_pool.roles.depositor == pool_creator) - .map(|(pool_id, _)| Pools::::create_bonded_account(pool_id)) - .expect("pool_creator created a pool above"); - - (pool_creator, pool_account) -} - -fn vote_to_balance( - vote: u64, -) -> Result, &'static str> { - vote.try_into().map_err(|_| "could not convert u64 to Balance") -} - -#[allow(unused)] -struct ListScenario { - /// Stash/Controller that is expected to be moved. - origin1: T::AccountId, - creator1: T::AccountId, - dest_weight: BalanceOf, - origin1_member: Option, -} - -impl ListScenario { - /// An expensive scenario for bags-list implementation: - /// - /// - the node to be updated (r) is the head of a bag that has at least one other node. The bag - /// itself will need to be read and written to update its head. The node pointed to by r.next - /// will need to be read and written as it will need to have its prev pointer updated. Note - /// that there are two other worst case scenarios for bag removal: 1) the node is a tail and - /// 2) the node is a middle node with prev and next; all scenarios end up with the same number - /// of storage reads and writes. - /// - /// - the destination bag has at least one node, which will need its next pointer updated. - pub(crate) fn new( - origin_weight: BalanceOf, - is_increase: bool, - ) -> Result { - ensure!(!origin_weight.is_zero(), "origin weight must be greater than 0"); - - ensure!( - pallet_nomination_pools::MaxPools::::get().unwrap_or(0) >= 3, - "must allow at least three pools for benchmarks" - ); - - // Burn the entire issuance. - CurrencyOf::::set_total_issuance(Zero::zero()); - - // Create accounts with the origin weight - let (pool_creator1, pool_origin1) = - create_pool_account::(USER_SEED + 1, origin_weight, Some(Perbill::from_percent(50))); - - T::Staking::nominate( - &pool_origin1, - // NOTE: these don't really need to be validators. - vec![account("random_validator", 0, USER_SEED)], - )?; - - let (_, pool_origin2) = - create_pool_account::(USER_SEED + 2, origin_weight, Some(Perbill::from_percent(50))); - - T::Staking::nominate( - &pool_origin2, - vec![account("random_validator", 0, USER_SEED)].clone(), - )?; - - // Find a destination weight that will trigger the worst case scenario - let dest_weight_as_vote = ::VoterList::score_update_worst_case( - &pool_origin1, - is_increase, - ); - - let dest_weight: BalanceOf = - dest_weight_as_vote.try_into().map_err(|_| "could not convert u64 to Balance")?; - - // Create an account with the worst case destination weight - let (_, pool_dest1) = - create_pool_account::(USER_SEED + 3, dest_weight, Some(Perbill::from_percent(50))); - - T::Staking::nominate(&pool_dest1, vec![account("random_validator", 0, USER_SEED)])?; - - let weight_of = pallet_staking::Pallet::::weight_of_fn(); - assert_eq!(vote_to_balance::(weight_of(&pool_origin1)).unwrap(), origin_weight); - assert_eq!(vote_to_balance::(weight_of(&pool_origin2)).unwrap(), origin_weight); - assert_eq!(vote_to_balance::(weight_of(&pool_dest1)).unwrap(), dest_weight); - - Ok(ListScenario { - origin1: pool_origin1, - creator1: pool_creator1, - dest_weight, - origin1_member: None, - }) - } - - fn add_joiner(mut self, amount: BalanceOf) -> Self { - let amount = MinJoinBond::::get() - .max(CurrencyOf::::minimum_balance()) - // Max `amount` with minimum thresholds for account balance and joining a pool - // to ensure 1) the user can be created and 2) can join the pool - .max(amount); - - let joiner: T::AccountId = account("joiner", USER_SEED, 0); - self.origin1_member = Some(joiner.clone()); - CurrencyOf::::set_balance(&joiner, amount * 2u32.into()); - - let original_bonded = T::Staking::active_stake(&self.origin1).unwrap(); - - // Unbond `amount` from the underlying pool account so when the member joins - // we will maintain `current_bonded`. - T::Staking::unbond(&self.origin1, amount).expect("the pool was created in `Self::new`."); - - // Account pool points for the unbonded balance. - BondedPools::::mutate(&1, |maybe_pool| { - maybe_pool.as_mut().map(|pool| pool.points -= amount) - }); - - Pools::::join(RuntimeOrigin::Signed(joiner.clone()).into(), amount, 1).unwrap(); - - // check that the vote weight is still the same as the original bonded - let weight_of = pallet_staking::Pallet::::weight_of_fn(); - assert_eq!(vote_to_balance::(weight_of(&self.origin1)).unwrap(), original_bonded); - - // check the member was added correctly - let member = PoolMembers::::get(&joiner).unwrap(); - assert_eq!(member.points, amount); - assert_eq!(member.pool_id, 1); - - self - } -} - -frame_benchmarking::benchmarks! { - join { - let origin_weight = Pools::::depositor_min_bond() * 2u32.into(); - - // setup the worst case list scenario. - let scenario = ListScenario::::new(origin_weight, true)?; - assert_eq!( - T::Staking::active_stake(&scenario.origin1).unwrap(), - origin_weight - ); - - let max_additional = scenario.dest_weight - origin_weight; - let joiner_free = CurrencyOf::::minimum_balance() + max_additional; - - let joiner: T::AccountId - = create_funded_user_with_balance::("joiner", 0, joiner_free); - - whitelist_account!(joiner); - }: _(RuntimeOrigin::Signed(joiner.clone()), max_additional, 1) - verify { - assert_eq!(CurrencyOf::::balance(&joiner), joiner_free - max_additional); - assert_eq!( - T::Staking::active_stake(&scenario.origin1).unwrap(), - scenario.dest_weight - ); - } - - bond_extra_transfer { - let origin_weight = Pools::::depositor_min_bond() * 2u32.into(); - let scenario = ListScenario::::new(origin_weight, true)?; - let extra = scenario.dest_weight - origin_weight; - - // creator of the src pool will bond-extra, bumping itself to dest bag. - - }: bond_extra(RuntimeOrigin::Signed(scenario.creator1.clone()), BondExtra::FreeBalance(extra)) - verify { - assert!( - T::Staking::active_stake(&scenario.origin1).unwrap() >= - scenario.dest_weight - ); - } - - bond_extra_other { - let claimer: T::AccountId = account("claimer", USER_SEED + 4, 0); - - let origin_weight = Pools::::depositor_min_bond() * 2u32.into(); - let scenario = ListScenario::::new(origin_weight, true)?; - let extra = (scenario.dest_weight - origin_weight).max(CurrencyOf::::minimum_balance()); - - // set claim preferences to `PermissionlessAll` to any account to bond extra on member's behalf. - let _ = Pools::::set_claim_permission(RuntimeOrigin::Signed(scenario.creator1.clone()).into(), ClaimPermission::PermissionlessAll); - - // transfer exactly `extra` to the depositor of the src pool (1), - let reward_account1 = Pools::::create_reward_account(1); - assert!(extra >= CurrencyOf::::minimum_balance()); - let _ = CurrencyOf::::mint_into(&reward_account1, extra); - - }: _(RuntimeOrigin::Signed(claimer), T::Lookup::unlookup(scenario.creator1.clone()), BondExtra::Rewards) - verify { - // commission of 50% deducted here. - assert!( - T::Staking::active_stake(&scenario.origin1).unwrap() >= - scenario.dest_weight / 2u32.into() - ); - } - - claim_payout { - let claimer: T::AccountId = account("claimer", USER_SEED + 4, 0); - let commission = Perbill::from_percent(50); - let origin_weight = Pools::::depositor_min_bond() * 2u32.into(); - let ed = CurrencyOf::::minimum_balance(); - let (depositor, pool_account) = create_pool_account::(0, origin_weight, Some(commission)); - let reward_account = Pools::::create_reward_account(1); - - // Send funds to the reward account of the pool - CurrencyOf::::set_balance(&reward_account, ed + origin_weight); - - // set claim preferences to `PermissionlessAll` so any account can claim rewards on member's - // behalf. - let _ = Pools::::set_claim_permission(RuntimeOrigin::Signed(depositor.clone()).into(), ClaimPermission::PermissionlessAll); - - // Sanity check - assert_eq!( - CurrencyOf::::balance(&depositor), - origin_weight - ); - - whitelist_account!(depositor); - }:claim_payout_other(RuntimeOrigin::Signed(claimer), depositor.clone()) - verify { - assert_eq!( - CurrencyOf::::balance(&depositor), - origin_weight + commission * origin_weight - ); - assert_eq!( - CurrencyOf::::balance(&reward_account), - ed + commission * origin_weight - ); - } - - - unbond { - // The weight the nominator will start at. The value used here is expected to be - // significantly higher than the first position in a list (e.g. the first bag threshold). - let origin_weight = Pools::::depositor_min_bond() * 200u32.into(); - let scenario = ListScenario::::new(origin_weight, false)?; - let amount = origin_weight - scenario.dest_weight; - - let scenario = scenario.add_joiner(amount); - let member_id = scenario.origin1_member.unwrap().clone(); - let member_id_lookup = T::Lookup::unlookup(member_id.clone()); - let all_points = PoolMembers::::get(&member_id).unwrap().points; - whitelist_account!(member_id); - }: _(RuntimeOrigin::Signed(member_id.clone()), member_id_lookup, all_points) - verify { - let bonded_after = T::Staking::active_stake(&scenario.origin1).unwrap(); - // We at least went down to the destination bag - assert!(bonded_after <= scenario.dest_weight); - let member = PoolMembers::::get( - &member_id - ) - .unwrap(); - assert_eq!( - member.unbonding_eras.keys().cloned().collect::>(), - vec![0 + T::Staking::bonding_duration()] - ); - assert_eq!( - member.unbonding_eras.values().cloned().collect::>(), - vec![all_points] - ); - } - - pool_withdraw_unbonded { - let s in 0 .. MAX_SPANS; - - let min_create_bond = Pools::::depositor_min_bond(); - let (depositor, pool_account) = create_pool_account::(0, min_create_bond, None); - - // Add a new member - let min_join_bond = MinJoinBond::::get().max(CurrencyOf::::minimum_balance()); - let joiner = create_funded_user_with_balance::("joiner", 0, min_join_bond * 2u32.into()); - Pools::::join(RuntimeOrigin::Signed(joiner.clone()).into(), min_join_bond, 1) - .unwrap(); - - // Sanity check join worked - assert_eq!( - T::Staking::active_stake(&pool_account).unwrap(), - min_create_bond + min_join_bond - ); - assert_eq!(CurrencyOf::::balance(&joiner), min_join_bond); - - // Unbond the new member - Pools::::fully_unbond(RuntimeOrigin::Signed(joiner.clone()).into(), joiner.clone()).unwrap(); - - // Sanity check that unbond worked - assert_eq!( - T::Staking::active_stake(&pool_account).unwrap(), - min_create_bond - ); - assert_eq!(pallet_staking::Ledger::::get(&pool_account).unwrap().unlocking.len(), 1); - // Set the current era - pallet_staking::CurrentEra::::put(EraIndex::max_value()); - - // Add `s` count of slashing spans to storage. - pallet_staking::benchmarking::add_slashing_spans::(&pool_account, s); - whitelist_account!(pool_account); - }: _(RuntimeOrigin::Signed(pool_account.clone()), 1, s) - verify { - // The joiners funds didn't change - assert_eq!(CurrencyOf::::balance(&joiner), min_join_bond); - // The unlocking chunk was removed - assert_eq!(pallet_staking::Ledger::::get(pool_account).unwrap().unlocking.len(), 0); - } - - withdraw_unbonded_update { - let s in 0 .. MAX_SPANS; - - let min_create_bond = Pools::::depositor_min_bond(); - let (depositor, pool_account) = create_pool_account::(0, min_create_bond, None); - - // Add a new member - let min_join_bond = MinJoinBond::::get().max(CurrencyOf::::minimum_balance()); - let joiner = create_funded_user_with_balance::("joiner", 0, min_join_bond * 2u32.into()); - let joiner_lookup = T::Lookup::unlookup(joiner.clone()); - Pools::::join(RuntimeOrigin::Signed(joiner.clone()).into(), min_join_bond, 1) - .unwrap(); - - // Sanity check join worked - assert_eq!( - T::Staking::active_stake(&pool_account).unwrap(), - min_create_bond + min_join_bond - ); - assert_eq!(CurrencyOf::::balance(&joiner), min_join_bond); - - // Unbond the new member - pallet_staking::CurrentEra::::put(0); - Pools::::fully_unbond(RuntimeOrigin::Signed(joiner.clone()).into(), joiner.clone()).unwrap(); - - // Sanity check that unbond worked - assert_eq!( - T::Staking::active_stake(&pool_account).unwrap(), - min_create_bond - ); - assert_eq!(pallet_staking::Ledger::::get(&pool_account).unwrap().unlocking.len(), 1); - - // Set the current era to ensure we can withdraw unbonded funds - pallet_staking::CurrentEra::::put(EraIndex::max_value()); - - pallet_staking::benchmarking::add_slashing_spans::(&pool_account, s); - whitelist_account!(joiner); - }: withdraw_unbonded(RuntimeOrigin::Signed(joiner.clone()), joiner_lookup, s) - verify { - assert_eq!( - CurrencyOf::::balance(&joiner), min_join_bond * 2u32.into() - ); - // The unlocking chunk was removed - assert_eq!(pallet_staking::Ledger::::get(&pool_account).unwrap().unlocking.len(), 0); - } - - withdraw_unbonded_kill { - let s in 0 .. MAX_SPANS; - - let min_create_bond = Pools::::depositor_min_bond(); - let (depositor, pool_account) = create_pool_account::(0, min_create_bond, None); - let depositor_lookup = T::Lookup::unlookup(depositor.clone()); - - // We set the pool to the destroying state so the depositor can leave - BondedPools::::try_mutate(&1, |maybe_bonded_pool| { - maybe_bonded_pool.as_mut().ok_or(()).map(|bonded_pool| { - bonded_pool.state = PoolState::Destroying; - }) - }) - .unwrap(); - - // Unbond the creator - pallet_staking::CurrentEra::::put(0); - // Simulate some rewards so we can check if the rewards storage is cleaned up. We check this - // here to ensure the complete flow for destroying a pool works - the reward pool account - // should never exist by time the depositor withdraws so we test that it gets cleaned - // up when unbonding. - let reward_account = Pools::::create_reward_account(1); - assert!(frame_system::Account::::contains_key(&reward_account)); - Pools::::fully_unbond(RuntimeOrigin::Signed(depositor.clone()).into(), depositor.clone()).unwrap(); - - // Sanity check that unbond worked - assert_eq!( - T::Staking::active_stake(&pool_account).unwrap(), - Zero::zero() - ); - assert_eq!( - CurrencyOf::::balance(&pool_account), - min_create_bond - ); - assert_eq!(pallet_staking::Ledger::::get(&pool_account).unwrap().unlocking.len(), 1); - - // Set the current era to ensure we can withdraw unbonded funds - pallet_staking::CurrentEra::::put(EraIndex::max_value()); - - // Some last checks that storage items we expect to get cleaned up are present - assert!(pallet_staking::Ledger::::contains_key(&pool_account)); - assert!(BondedPools::::contains_key(&1)); - assert!(SubPoolsStorage::::contains_key(&1)); - assert!(RewardPools::::contains_key(&1)); - assert!(PoolMembers::::contains_key(&depositor)); - assert!(frame_system::Account::::contains_key(&reward_account)); - - whitelist_account!(depositor); - }: withdraw_unbonded(RuntimeOrigin::Signed(depositor.clone()), depositor_lookup, s) - verify { - // Pool removal worked - assert!(!pallet_staking::Ledger::::contains_key(&pool_account)); - assert!(!BondedPools::::contains_key(&1)); - assert!(!SubPoolsStorage::::contains_key(&1)); - assert!(!RewardPools::::contains_key(&1)); - assert!(!PoolMembers::::contains_key(&depositor)); - assert!(!frame_system::Account::::contains_key(&pool_account)); - assert!(!frame_system::Account::::contains_key(&reward_account)); - - // Funds where transferred back correctly - assert_eq!( - CurrencyOf::::balance(&depositor), - // gets bond back + rewards collecting when unbonding - min_create_bond * 2u32.into() + CurrencyOf::::minimum_balance() - ); - } - - create { - let min_create_bond = Pools::::depositor_min_bond(); - let depositor: T::AccountId = account("depositor", USER_SEED, 0); - let depositor_lookup = T::Lookup::unlookup(depositor.clone()); - - // Give the depositor some balance to bond - CurrencyOf::::set_balance(&depositor, min_create_bond * 2u32.into()); - - // Make sure no Pools exist at a pre-condition for our verify checks - assert_eq!(RewardPools::::count(), 0); - assert_eq!(BondedPools::::count(), 0); - - whitelist_account!(depositor); - }: _( - RuntimeOrigin::Signed(depositor.clone()), - min_create_bond, - depositor_lookup.clone(), - depositor_lookup.clone(), - depositor_lookup - ) - verify { - assert_eq!(RewardPools::::count(), 1); - assert_eq!(BondedPools::::count(), 1); - let (_, new_pool) = BondedPools::::iter().next().unwrap(); - assert_eq!( - new_pool, - BondedPoolInner { - commission: Commission::default(), - member_counter: 1, - points: min_create_bond, - roles: PoolRoles { - depositor: depositor.clone(), - root: Some(depositor.clone()), - nominator: Some(depositor.clone()), - bouncer: Some(depositor.clone()), - }, - state: PoolState::Open, - } - ); - assert_eq!( - T::Staking::active_stake(&Pools::::create_bonded_account(1)), - Ok(min_create_bond) - ); - } - - nominate { - let n in 1 .. MaxNominationsOf::::get(); - - // Create a pool - let min_create_bond = Pools::::depositor_min_bond() * 2u32.into(); - let (depositor, pool_account) = create_pool_account::(0, min_create_bond, None); - - // Create some accounts to nominate. For the sake of benchmarking they don't need to be - // actual validators - let validators: Vec<_> = (0..n) - .map(|i| account("stash", USER_SEED, i)) - .collect(); - - whitelist_account!(depositor); - }:_(RuntimeOrigin::Signed(depositor.clone()), 1, validators) - verify { - assert_eq!(RewardPools::::count(), 1); - assert_eq!(BondedPools::::count(), 1); - let (_, new_pool) = BondedPools::::iter().next().unwrap(); - assert_eq!( - new_pool, - BondedPoolInner { - commission: Commission::default(), - member_counter: 1, - points: min_create_bond, - roles: PoolRoles { - depositor: depositor.clone(), - root: Some(depositor.clone()), - nominator: Some(depositor.clone()), - bouncer: Some(depositor.clone()), - }, - state: PoolState::Open, - } - ); - assert_eq!( - T::Staking::active_stake(&Pools::::create_bonded_account(1)), - Ok(min_create_bond) - ); - } - - set_state { - // Create a pool - let min_create_bond = Pools::::depositor_min_bond(); - let (depositor, pool_account) = create_pool_account::(0, min_create_bond, None); - BondedPools::::mutate(&1, |maybe_pool| { - // Force the pool into an invalid state - maybe_pool.as_mut().map(|pool| pool.points = min_create_bond * 10u32.into()); - }); - - let caller = account("caller", 0, USER_SEED); - whitelist_account!(caller); - }:_(RuntimeOrigin::Signed(caller), 1, PoolState::Destroying) - verify { - assert_eq!(BondedPools::::get(1).unwrap().state, PoolState::Destroying); - } - - set_metadata { - let n in 1 .. ::MaxMetadataLen::get(); - - // Create a pool - let (depositor, pool_account) = create_pool_account::(0, Pools::::depositor_min_bond() * 2u32.into(), None); - - // Create metadata of the max possible size - let metadata: Vec = (0..n).map(|_| 42).collect(); - - whitelist_account!(depositor); - }:_(RuntimeOrigin::Signed(depositor), 1, metadata.clone()) - verify { - assert_eq!(Metadata::::get(&1), metadata); - } - - set_configs { - }:_( - RuntimeOrigin::Root, - ConfigOp::Set(BalanceOf::::max_value()), - ConfigOp::Set(BalanceOf::::max_value()), - ConfigOp::Set(u32::MAX), - ConfigOp::Set(u32::MAX), - ConfigOp::Set(u32::MAX), - ConfigOp::Set(Perbill::max_value()) - ) verify { - assert_eq!(MinJoinBond::::get(), BalanceOf::::max_value()); - assert_eq!(MinCreateBond::::get(), BalanceOf::::max_value()); - assert_eq!(MaxPools::::get(), Some(u32::MAX)); - assert_eq!(MaxPoolMembers::::get(), Some(u32::MAX)); - assert_eq!(MaxPoolMembersPerPool::::get(), Some(u32::MAX)); - assert_eq!(GlobalMaxCommission::::get(), Some(Perbill::max_value())); - } - - update_roles { - let first_id = pallet_nomination_pools::LastPoolId::::get() + 1; - let (root, _) = create_pool_account::(0, Pools::::depositor_min_bond() * 2u32.into(), None); - let random: T::AccountId = account("but is anything really random in computers..?", 0, USER_SEED); - }:_( - RuntimeOrigin::Signed(root.clone()), - first_id, - ConfigOp::Set(random.clone()), - ConfigOp::Set(random.clone()), - ConfigOp::Set(random.clone()) - ) verify { - assert_eq!( - pallet_nomination_pools::BondedPools::::get(first_id).unwrap().roles, - pallet_nomination_pools::PoolRoles { - depositor: root, - nominator: Some(random.clone()), - bouncer: Some(random.clone()), - root: Some(random), - }, - ) - } - - chill { - // Create a pool - let (depositor, pool_account) = create_pool_account::(0, Pools::::depositor_min_bond() * 2u32.into(), None); - - // Nominate with the pool. - let validators: Vec<_> = (0..MaxNominationsOf::::get()) - .map(|i| account("stash", USER_SEED, i)) - .collect(); - - assert_ok!(T::Staking::nominate(&pool_account, validators)); - assert!(T::Staking::nominations(&Pools::::create_bonded_account(1)).is_some()); - - whitelist_account!(depositor); - }:_(RuntimeOrigin::Signed(depositor.clone()), 1) - verify { - assert!(T::Staking::nominations(&Pools::::create_bonded_account(1)).is_none()); - } - - set_commission { - // Create a pool - do not set a commission yet. - let (depositor, pool_account) = create_pool_account::(0, Pools::::depositor_min_bond() * 2u32.into(), None); - // set a max commission - Pools::::set_commission_max(RuntimeOrigin::Signed(depositor.clone()).into(), 1u32.into(), Perbill::from_percent(50)).unwrap(); - // set a change rate - Pools::::set_commission_change_rate(RuntimeOrigin::Signed(depositor.clone()).into(), 1u32.into(), CommissionChangeRate { - max_increase: Perbill::from_percent(20), - min_delay: 0u32.into(), - }).unwrap(); - // set a claim permission to an account. - Pools::::set_commission_claim_permission( - RuntimeOrigin::Signed(depositor.clone()).into(), - 1u32.into(), - Some(CommissionClaimPermission::Account(depositor.clone())) - ).unwrap(); - - }:_(RuntimeOrigin::Signed(depositor.clone()), 1u32.into(), Some((Perbill::from_percent(20), depositor.clone()))) - verify { - assert_eq!(BondedPools::::get(1).unwrap().commission, Commission { - current: Some((Perbill::from_percent(20), depositor.clone())), - max: Some(Perbill::from_percent(50)), - change_rate: Some(CommissionChangeRate { - max_increase: Perbill::from_percent(20), - min_delay: 0u32.into() - }), - throttle_from: Some(1u32.into()), - claim_permission: Some(CommissionClaimPermission::Account(depositor)), - }); - } - - set_commission_max { - // Create a pool, setting a commission that will update when max commission is set. - let (depositor, pool_account) = create_pool_account::(0, Pools::::depositor_min_bond() * 2u32.into(), Some(Perbill::from_percent(50))); - }:_(RuntimeOrigin::Signed(depositor.clone()), 1u32.into(), Perbill::from_percent(50)) - verify { - assert_eq!( - BondedPools::::get(1).unwrap().commission, Commission { - current: Some((Perbill::from_percent(50), depositor)), - max: Some(Perbill::from_percent(50)), - change_rate: None, - throttle_from: Some(0u32.into()), - claim_permission: None, - }); - } - - set_commission_change_rate { - // Create a pool - let (depositor, pool_account) = create_pool_account::(0, Pools::::depositor_min_bond() * 2u32.into(), None); - }:_(RuntimeOrigin::Signed(depositor.clone()), 1u32.into(), CommissionChangeRate { - max_increase: Perbill::from_percent(50), - min_delay: 1000u32.into(), - }) - verify { - assert_eq!( - BondedPools::::get(1).unwrap().commission, Commission { - current: None, - max: None, - change_rate: Some(CommissionChangeRate { - max_increase: Perbill::from_percent(50), - min_delay: 1000u32.into(), - }), - throttle_from: Some(1_u32.into()), - claim_permission: None, - }); - } - - set_commission_claim_permission { - // Create a pool. - let (depositor, pool_account) = create_pool_account::(0, Pools::::depositor_min_bond() * 2u32.into(), None); - }:_(RuntimeOrigin::Signed(depositor.clone()), 1u32.into(), Some(CommissionClaimPermission::Account(depositor.clone()))) - verify { - assert_eq!( - BondedPools::::get(1).unwrap().commission, Commission { - current: None, - max: None, - change_rate: None, - throttle_from: None, - claim_permission: Some(CommissionClaimPermission::Account(depositor)), - }); - } - - set_claim_permission { - // Create a pool - let min_create_bond = Pools::::depositor_min_bond(); - let (depositor, pool_account) = create_pool_account::(0, min_create_bond, None); - - // Join pool - let min_join_bond = MinJoinBond::::get().max(CurrencyOf::::minimum_balance()); - let joiner = create_funded_user_with_balance::("joiner", 0, min_join_bond * 4u32.into()); - let joiner_lookup = T::Lookup::unlookup(joiner.clone()); - Pools::::join(RuntimeOrigin::Signed(joiner.clone()).into(), min_join_bond, 1) - .unwrap(); - - // Sanity check join worked - assert_eq!( - T::Staking::active_stake(&pool_account).unwrap(), - min_create_bond + min_join_bond - ); - }:_(RuntimeOrigin::Signed(joiner.clone()), ClaimPermission::Permissioned) - verify { - assert_eq!(ClaimPermissions::::get(joiner), ClaimPermission::Permissioned); - } - - claim_commission { - let claimer: T::AccountId = account("claimer_member", USER_SEED + 4, 0); - let commission = Perbill::from_percent(50); - let origin_weight = Pools::::depositor_min_bond() * 2u32.into(); - let ed = CurrencyOf::::minimum_balance(); - let (depositor, pool_account) = create_pool_account::(0, origin_weight, Some(commission)); - let reward_account = Pools::::create_reward_account(1); - CurrencyOf::::set_balance(&reward_account, ed + origin_weight); - - // member claims a payout to make some commission available. - let _ = Pools::::claim_payout(RuntimeOrigin::Signed(claimer.clone()).into()); - // set a claim permission to an account. - let _ = Pools::::set_commission_claim_permission( - RuntimeOrigin::Signed(depositor.clone()).into(), - 1u32.into(), - Some(CommissionClaimPermission::Account(claimer)) - ); - whitelist_account!(depositor); - }:_(RuntimeOrigin::Signed(depositor.clone()), 1u32.into()) - verify { - assert_eq!( - CurrencyOf::::balance(&depositor), - origin_weight + commission * origin_weight - ); - assert_eq!( - CurrencyOf::::balance(&reward_account), - ed + commission * origin_weight - ); - } - - adjust_pool_deposit { - // Create a pool - let (depositor, _) = create_pool_account::(0, Pools::::depositor_min_bond() * 2u32.into(), None); - - // Remove ed freeze to create a scenario where the ed deposit needs to be adjusted. - let _ = Pools::::unfreeze_pool_deposit(&Pools::::create_reward_account(1)); - assert!(&Pools::::check_ed_imbalance().is_err()); - - whitelist_account!(depositor); - }:_(RuntimeOrigin::Signed(depositor), 1) - verify { - assert!(&Pools::::check_ed_imbalance().is_ok()); - } - - impl_benchmark_test_suite!( - Pallet, - crate::mock::new_test_ext(), - crate::mock::Runtime - ); -} +#[cfg(all(feature = "runtime-benchmarks", test))] +pub(crate) mod mock; diff --git a/substrate/frame/nomination-pools/benchmarking/src/mock.rs b/substrate/frame/nomination-pools/benchmarking/src/mock.rs index a59f8f3f40e7f6e67ca3163edb56b43257fdc6ee..2752d53a6b9f3364c234d9144a6c40b10b449a5b 100644 --- a/substrate/frame/nomination-pools/benchmarking/src/mock.rs +++ b/substrate/frame/nomination-pools/benchmarking/src/mock.rs @@ -111,7 +111,6 @@ impl pallet_staking::Config for Runtime { type EraPayout = pallet_staking::ConvertCurve; type NextNewSession = (); type MaxExposurePageSize = ConstU32<64>; - type OffendingValidatorsThreshold = (); type ElectionProvider = frame_election_provider_support::NoElection<(AccountId, BlockNumber, Staking, ())>; type GenesisElectionProvider = Self::ElectionProvider; @@ -124,6 +123,7 @@ impl pallet_staking::Config for Runtime { type EventListeners = Pools; type BenchmarkingConfig = pallet_staking::TestBenchmarkingConfig; type WeightInfo = (); + type DisablingStrategy = pallet_staking::UpToLimitDisablingStrategy; } parameter_types! { diff --git a/substrate/frame/nomination-pools/runtime-api/Cargo.toml b/substrate/frame/nomination-pools/runtime-api/Cargo.toml index 7828f26fe6fe1378942479f44f40e325da265817..a0ddac9e045675aefe7b8139e0048f3399663da8 100644 --- a/substrate/frame/nomination-pools/runtime-api/Cargo.toml +++ b/substrate/frame/nomination-pools/runtime-api/Cargo.toml @@ -16,7 +16,7 @@ workspace = true targets = ["x86_64-unknown-linux-gnu"] [dependencies] -codec = { package = "parity-scale-codec", version = "3.6.1", default-features = false, features = ["derive"] } +codec = { package = "parity-scale-codec", version = "3.6.12", default-features = false, features = ["derive"] } sp-api = { path = "../../../primitives/api", default-features = false } sp-std = { path = "../../../primitives/std", default-features = false } pallet-nomination-pools = { path = "..", default-features = false } diff --git a/substrate/frame/nomination-pools/src/mock.rs b/substrate/frame/nomination-pools/src/mock.rs index b9301a400953e0c4f9c7589b3f74241d094c597f..686402b843492e8f92bb26231a7ed3becf0c0e03 100644 --- a/substrate/frame/nomination-pools/src/mock.rs +++ b/substrate/frame/nomination-pools/src/mock.rs @@ -131,6 +131,10 @@ impl sp_staking::StakingInterface for StakingMock { Ok(()) } + fn update_payee(_stash: &Self::AccountId, _reward_acc: &Self::AccountId) -> DispatchResult { + unimplemented!("method currently not used in testing") + } + fn chill(_: &Self::AccountId) -> sp_runtime::DispatchResult { Ok(()) } @@ -223,6 +227,10 @@ impl sp_staking::StakingInterface for StakingMock { fn max_exposure_page_size() -> sp_staking::Page { unimplemented!("method currently not used in testing") } + + fn slash_reward_fraction() -> Perbill { + unimplemented!("method currently not used in testing") + } } #[derive_impl(frame_system::config_preludes::TestDefaultConfig)] diff --git a/substrate/frame/nomination-pools/test-staking/Cargo.toml b/substrate/frame/nomination-pools/test-staking/Cargo.toml index 130a27752bf37768d34bcbc1012f51524c2df277..ada52db6de53180093eafc47a140a4b229ced685 100644 --- a/substrate/frame/nomination-pools/test-staking/Cargo.toml +++ b/substrate/frame/nomination-pools/test-staking/Cargo.toml @@ -16,7 +16,7 @@ workspace = true targets = ["x86_64-unknown-linux-gnu"] [dev-dependencies] -codec = { package = "parity-scale-codec", version = "3.6.1", features = ["derive"] } +codec = { package = "parity-scale-codec", version = "3.6.12", features = ["derive"] } scale-info = { version = "2.11.1", features = ["derive"] } sp-runtime = { path = "../../../primitives/runtime" } diff --git a/substrate/frame/nomination-pools/test-staking/src/mock.rs b/substrate/frame/nomination-pools/test-staking/src/mock.rs index 2ec47e0d164558defb0e70d260def626406680e7..93a05ddfae990108c7277c2448ff1470ae11d2ae 100644 --- a/substrate/frame/nomination-pools/test-staking/src/mock.rs +++ b/substrate/frame/nomination-pools/test-staking/src/mock.rs @@ -125,7 +125,6 @@ impl pallet_staking::Config for Runtime { type EraPayout = pallet_staking::ConvertCurve; type NextNewSession = (); type MaxExposurePageSize = ConstU32<64>; - type OffendingValidatorsThreshold = (); type ElectionProvider = frame_election_provider_support::NoElection<(AccountId, BlockNumber, Staking, ())>; type GenesisElectionProvider = Self::ElectionProvider; @@ -138,6 +137,7 @@ impl pallet_staking::Config for Runtime { type EventListeners = Pools; type BenchmarkingConfig = pallet_staking::TestBenchmarkingConfig; type WeightInfo = (); + type DisablingStrategy = pallet_staking::UpToLimitDisablingStrategy; } parameter_types! { diff --git a/substrate/frame/offences/Cargo.toml b/substrate/frame/offences/Cargo.toml index f8efc88bafc1aa3ec4bceb9150d62268499d62b3..a59ef9334f0bc3cba6a92943a1cbbdbe4d3c94d1 100644 --- a/substrate/frame/offences/Cargo.toml +++ b/substrate/frame/offences/Cargo.toml @@ -16,7 +16,7 @@ workspace = true targets = ["x86_64-unknown-linux-gnu"] [dependencies] -codec = { package = "parity-scale-codec", version = "3.6.1", default-features = false, features = ["derive"] } +codec = { package = "parity-scale-codec", version = "3.6.12", default-features = false, features = ["derive"] } log = { workspace = true } scale-info = { version = "2.11.1", default-features = false, features = ["derive"] } serde = { optional = true, workspace = true, default-features = true } diff --git a/substrate/frame/offences/benchmarking/Cargo.toml b/substrate/frame/offences/benchmarking/Cargo.toml index 07905a1e0aa42d2aa859046b595569e275fe778a..bbd918a2883f30afb82310424375eb3ed5b5a8e8 100644 --- a/substrate/frame/offences/benchmarking/Cargo.toml +++ b/substrate/frame/offences/benchmarking/Cargo.toml @@ -16,7 +16,7 @@ workspace = true targets = ["x86_64-unknown-linux-gnu"] [dependencies] -codec = { package = "parity-scale-codec", version = "3.6.1", default-features = false } +codec = { package = "parity-scale-codec", version = "3.6.12", default-features = false } scale-info = { version = "2.11.1", default-features = false, features = ["derive"] } frame-benchmarking = { path = "../../benchmarking", default-features = false } frame-election-provider-support = { path = "../../election-provider-support", default-features = false } diff --git a/substrate/frame/offences/benchmarking/src/inner.rs b/substrate/frame/offences/benchmarking/src/inner.rs new file mode 100644 index 0000000000000000000000000000000000000000..9aa88f7a0d6d08e41d25c6b9e425fc71ba0f78d2 --- /dev/null +++ b/substrate/frame/offences/benchmarking/src/inner.rs @@ -0,0 +1,250 @@ +// 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. + +//! Offences pallet benchmarking. + +use sp_std::{prelude::*, vec}; + +use frame_benchmarking::v1::{account, benchmarks}; +use frame_support::traits::{Currency, Get}; +use frame_system::{Config as SystemConfig, Pallet as System, RawOrigin}; + +use sp_runtime::{ + traits::{Convert, Saturating, StaticLookup}, + Perbill, +}; +use sp_staking::offence::ReportOffence; + +use pallet_babe::EquivocationOffence as BabeEquivocationOffence; +use pallet_balances::Config as BalancesConfig; +use pallet_grandpa::{ + EquivocationOffence as GrandpaEquivocationOffence, TimeSlot as GrandpaTimeSlot, +}; +use pallet_offences::{Config as OffencesConfig, Pallet as Offences}; +use pallet_session::{ + historical::{Config as HistoricalConfig, IdentificationTuple}, + Config as SessionConfig, Pallet as Session, SessionManager, +}; +use pallet_staking::{ + Config as StakingConfig, Exposure, IndividualExposure, MaxNominationsOf, Pallet as Staking, + RewardDestination, ValidatorPrefs, +}; + +const SEED: u32 = 0; + +const MAX_NOMINATORS: u32 = 100; + +pub struct Pallet(Offences); + +pub trait Config: + SessionConfig + + StakingConfig + + OffencesConfig + + HistoricalConfig + + BalancesConfig + + IdTupleConvert +{ +} + +/// A helper trait to make sure we can convert `IdentificationTuple` coming from historical +/// and the one required by offences. +pub trait IdTupleConvert { + /// Convert identification tuple from `historical` trait to the one expected by `offences`. + fn convert(id: IdentificationTuple) -> ::IdentificationTuple; +} + +impl IdTupleConvert for T +where + ::IdentificationTuple: From>, +{ + fn convert(id: IdentificationTuple) -> ::IdentificationTuple { + id.into() + } +} + +type LookupSourceOf = <::Lookup as StaticLookup>::Source; +type BalanceOf = + <::Currency as Currency<::AccountId>>::Balance; + +struct Offender { + pub controller: T::AccountId, + #[allow(dead_code)] + pub stash: T::AccountId, + #[allow(dead_code)] + pub nominator_stashes: Vec, +} + +fn bond_amount() -> BalanceOf { + T::Currency::minimum_balance().saturating_mul(10_000u32.into()) +} + +fn create_offender(n: u32, nominators: u32) -> Result, &'static str> { + let stash: T::AccountId = account("stash", n, SEED); + let stash_lookup: LookupSourceOf = T::Lookup::unlookup(stash.clone()); + let reward_destination = RewardDestination::Staked; + let amount = bond_amount::(); + // add twice as much balance to prevent the account from being killed. + let free_amount = amount.saturating_mul(2u32.into()); + T::Currency::make_free_balance_be(&stash, free_amount); + Staking::::bond( + RawOrigin::Signed(stash.clone()).into(), + amount, + reward_destination.clone(), + )?; + + let validator_prefs = + ValidatorPrefs { commission: Perbill::from_percent(50), ..Default::default() }; + Staking::::validate(RawOrigin::Signed(stash.clone()).into(), validator_prefs)?; + + let mut individual_exposures = vec![]; + let mut nominator_stashes = vec![]; + // Create n nominators + for i in 0..nominators { + let nominator_stash: T::AccountId = + account("nominator stash", n * MAX_NOMINATORS + i, SEED); + T::Currency::make_free_balance_be(&nominator_stash, free_amount); + + Staking::::bond( + RawOrigin::Signed(nominator_stash.clone()).into(), + amount, + reward_destination.clone(), + )?; + + let selected_validators: Vec> = vec![stash_lookup.clone()]; + Staking::::nominate( + RawOrigin::Signed(nominator_stash.clone()).into(), + selected_validators, + )?; + + individual_exposures + .push(IndividualExposure { who: nominator_stash.clone(), value: amount }); + nominator_stashes.push(nominator_stash.clone()); + } + + let exposure = Exposure { total: amount * n.into(), own: amount, others: individual_exposures }; + let current_era = 0u32; + Staking::::add_era_stakers(current_era, stash.clone(), exposure); + + Ok(Offender { controller: stash.clone(), stash, nominator_stashes }) +} + +fn make_offenders( + num_offenders: u32, + num_nominators: u32, +) -> Result<(Vec>, Vec>), &'static str> { + Staking::::new_session(0); + + let mut offenders = vec![]; + for i in 0..num_offenders { + let offender = create_offender::(i + 1, num_nominators)?; + offenders.push(offender); + } + + Staking::::start_session(0); + + let id_tuples = offenders + .iter() + .map(|offender| { + ::ValidatorIdOf::convert(offender.controller.clone()) + .expect("failed to get validator id from account id") + }) + .map(|validator_id| { + ::FullIdentificationOf::convert(validator_id.clone()) + .map(|full_id| (validator_id, full_id)) + .expect("failed to convert validator id to full identification") + }) + .collect::>>(); + Ok((id_tuples, offenders)) +} + +benchmarks! { + report_offence_grandpa { + let n in 0 .. MAX_NOMINATORS.min(MaxNominationsOf::::get()); + + // for grandpa equivocation reports the number of reporters + // and offenders is always 1 + let reporters = vec![account("reporter", 1, SEED)]; + + // make sure reporters actually get rewarded + Staking::::set_slash_reward_fraction(Perbill::one()); + + let (mut offenders, raw_offenders) = make_offenders::(1, n)?; + let validator_set_count = Session::::validators().len() as u32; + + let offence = GrandpaEquivocationOffence { + time_slot: GrandpaTimeSlot { set_id: 0, round: 0 }, + session_index: 0, + validator_set_count, + offender: T::convert(offenders.pop().unwrap()), + }; + assert_eq!(System::::event_count(), 0); + }: { + let _ = Offences::::report_offence(reporters, offence); + } + verify { + // make sure that all slashes have been applied + #[cfg(test)] + assert_eq!( + System::::event_count(), 0 + + 1 // offence + + 3 // reporter (reward + endowment) + + 1 // offenders reported + + 3 // offenders slashed + + 1 // offenders chilled + + 3 * n // nominators slashed + ); + } + + report_offence_babe { + let n in 0 .. MAX_NOMINATORS.min(MaxNominationsOf::::get()); + + // for babe equivocation reports the number of reporters + // and offenders is always 1 + let reporters = vec![account("reporter", 1, SEED)]; + + // make sure reporters actually get rewarded + Staking::::set_slash_reward_fraction(Perbill::one()); + + let (mut offenders, raw_offenders) = make_offenders::(1, n)?; + let validator_set_count = Session::::validators().len() as u32; + + let offence = BabeEquivocationOffence { + slot: 0u64.into(), + session_index: 0, + validator_set_count, + offender: T::convert(offenders.pop().unwrap()), + }; + assert_eq!(System::::event_count(), 0); + }: { + let _ = Offences::::report_offence(reporters, offence); + } + verify { + // make sure that all slashes have been applied + #[cfg(test)] + assert_eq!( + System::::event_count(), 0 + + 1 // offence + + 3 // reporter (reward + endowment) + + 1 // offenders reported + + 3 // offenders slashed + + 1 // offenders chilled + + 3 * n // nominators slashed + ); + } + + impl_benchmark_test_suite!(Pallet, crate::mock::new_test_ext(), crate::mock::Test); +} diff --git a/substrate/frame/offences/benchmarking/src/lib.rs b/substrate/frame/offences/benchmarking/src/lib.rs index 563aa4755cec08ece465236208495baf872e325d..b08955a133297f356a5fa884394b3a88a7e28727 100644 --- a/substrate/frame/offences/benchmarking/src/lib.rs +++ b/substrate/frame/offences/benchmarking/src/lib.rs @@ -17,239 +17,13 @@ //! Offences pallet benchmarking. -#![cfg(feature = "runtime-benchmarks")] #![cfg_attr(not(feature = "std"), no_std)] -mod mock; +#[cfg(feature = "runtime-benchmarks")] +pub mod inner; -use sp_std::{prelude::*, vec}; +#[cfg(feature = "runtime-benchmarks")] +pub use inner::*; -use frame_benchmarking::v1::{account, benchmarks}; -use frame_support::traits::{Currency, Get}; -use frame_system::{Config as SystemConfig, Pallet as System, RawOrigin}; - -use sp_runtime::{ - traits::{Convert, Saturating, StaticLookup}, - Perbill, -}; -use sp_staking::offence::ReportOffence; - -use pallet_babe::EquivocationOffence as BabeEquivocationOffence; -use pallet_balances::Config as BalancesConfig; -use pallet_grandpa::{ - EquivocationOffence as GrandpaEquivocationOffence, TimeSlot as GrandpaTimeSlot, -}; -use pallet_offences::{Config as OffencesConfig, Pallet as Offences}; -use pallet_session::{ - historical::{Config as HistoricalConfig, IdentificationTuple}, - Config as SessionConfig, Pallet as Session, SessionManager, -}; -use pallet_staking::{ - Config as StakingConfig, Exposure, IndividualExposure, MaxNominationsOf, Pallet as Staking, - RewardDestination, ValidatorPrefs, -}; - -const SEED: u32 = 0; - -const MAX_NOMINATORS: u32 = 100; - -pub struct Pallet(Offences); - -pub trait Config: - SessionConfig - + StakingConfig - + OffencesConfig - + HistoricalConfig - + BalancesConfig - + IdTupleConvert -{ -} - -/// A helper trait to make sure we can convert `IdentificationTuple` coming from historical -/// and the one required by offences. -pub trait IdTupleConvert { - /// Convert identification tuple from `historical` trait to the one expected by `offences`. - fn convert(id: IdentificationTuple) -> ::IdentificationTuple; -} - -impl IdTupleConvert for T -where - ::IdentificationTuple: From>, -{ - fn convert(id: IdentificationTuple) -> ::IdentificationTuple { - id.into() - } -} - -type LookupSourceOf = <::Lookup as StaticLookup>::Source; -type BalanceOf = - <::Currency as Currency<::AccountId>>::Balance; - -struct Offender { - pub controller: T::AccountId, - #[allow(dead_code)] - pub stash: T::AccountId, - #[allow(dead_code)] - pub nominator_stashes: Vec, -} - -fn bond_amount() -> BalanceOf { - T::Currency::minimum_balance().saturating_mul(10_000u32.into()) -} - -fn create_offender(n: u32, nominators: u32) -> Result, &'static str> { - let stash: T::AccountId = account("stash", n, SEED); - let stash_lookup: LookupSourceOf = T::Lookup::unlookup(stash.clone()); - let reward_destination = RewardDestination::Staked; - let amount = bond_amount::(); - // add twice as much balance to prevent the account from being killed. - let free_amount = amount.saturating_mul(2u32.into()); - T::Currency::make_free_balance_be(&stash, free_amount); - Staking::::bond( - RawOrigin::Signed(stash.clone()).into(), - amount, - reward_destination.clone(), - )?; - - let validator_prefs = - ValidatorPrefs { commission: Perbill::from_percent(50), ..Default::default() }; - Staking::::validate(RawOrigin::Signed(stash.clone()).into(), validator_prefs)?; - - let mut individual_exposures = vec![]; - let mut nominator_stashes = vec![]; - // Create n nominators - for i in 0..nominators { - let nominator_stash: T::AccountId = - account("nominator stash", n * MAX_NOMINATORS + i, SEED); - T::Currency::make_free_balance_be(&nominator_stash, free_amount); - - Staking::::bond( - RawOrigin::Signed(nominator_stash.clone()).into(), - amount, - reward_destination.clone(), - )?; - - let selected_validators: Vec> = vec![stash_lookup.clone()]; - Staking::::nominate( - RawOrigin::Signed(nominator_stash.clone()).into(), - selected_validators, - )?; - - individual_exposures - .push(IndividualExposure { who: nominator_stash.clone(), value: amount }); - nominator_stashes.push(nominator_stash.clone()); - } - - let exposure = Exposure { total: amount * n.into(), own: amount, others: individual_exposures }; - let current_era = 0u32; - Staking::::add_era_stakers(current_era, stash.clone(), exposure); - - Ok(Offender { controller: stash.clone(), stash, nominator_stashes }) -} - -fn make_offenders( - num_offenders: u32, - num_nominators: u32, -) -> Result<(Vec>, Vec>), &'static str> { - Staking::::new_session(0); - - let mut offenders = vec![]; - for i in 0..num_offenders { - let offender = create_offender::(i + 1, num_nominators)?; - offenders.push(offender); - } - - Staking::::start_session(0); - - let id_tuples = offenders - .iter() - .map(|offender| { - ::ValidatorIdOf::convert(offender.controller.clone()) - .expect("failed to get validator id from account id") - }) - .map(|validator_id| { - ::FullIdentificationOf::convert(validator_id.clone()) - .map(|full_id| (validator_id, full_id)) - .expect("failed to convert validator id to full identification") - }) - .collect::>>(); - Ok((id_tuples, offenders)) -} - -benchmarks! { - report_offence_grandpa { - let n in 0 .. MAX_NOMINATORS.min(MaxNominationsOf::::get()); - - // for grandpa equivocation reports the number of reporters - // and offenders is always 1 - let reporters = vec![account("reporter", 1, SEED)]; - - // make sure reporters actually get rewarded - Staking::::set_slash_reward_fraction(Perbill::one()); - - let (mut offenders, raw_offenders) = make_offenders::(1, n)?; - let validator_set_count = Session::::validators().len() as u32; - - let offence = GrandpaEquivocationOffence { - time_slot: GrandpaTimeSlot { set_id: 0, round: 0 }, - session_index: 0, - validator_set_count, - offender: T::convert(offenders.pop().unwrap()), - }; - assert_eq!(System::::event_count(), 0); - }: { - let _ = Offences::::report_offence(reporters, offence); - } - verify { - // make sure that all slashes have been applied - #[cfg(test)] - assert_eq!( - System::::event_count(), 0 - + 1 // offence - + 3 // reporter (reward + endowment) - + 1 // offenders reported - + 3 // offenders slashed - + 1 // offenders chilled - + 3 * n // nominators slashed - ); - } - - report_offence_babe { - let n in 0 .. MAX_NOMINATORS.min(MaxNominationsOf::::get()); - - // for babe equivocation reports the number of reporters - // and offenders is always 1 - let reporters = vec![account("reporter", 1, SEED)]; - - // make sure reporters actually get rewarded - Staking::::set_slash_reward_fraction(Perbill::one()); - - let (mut offenders, raw_offenders) = make_offenders::(1, n)?; - let validator_set_count = Session::::validators().len() as u32; - - let offence = BabeEquivocationOffence { - slot: 0u64.into(), - session_index: 0, - validator_set_count, - offender: T::convert(offenders.pop().unwrap()), - }; - assert_eq!(System::::event_count(), 0); - }: { - let _ = Offences::::report_offence(reporters, offence); - } - verify { - // make sure that all slashes have been applied - #[cfg(test)] - assert_eq!( - System::::event_count(), 0 - + 1 // offence - + 3 // reporter (reward + endowment) - + 1 // offenders reported - + 3 // offenders slashed - + 1 // offenders chilled - + 3 * n // nominators slashed - ); - } - - impl_benchmark_test_suite!(Pallet, crate::mock::new_test_ext(), crate::mock::Test); -} +#[cfg(all(feature = "runtime-benchmarks", test))] +pub(crate) mod mock; diff --git a/substrate/frame/offences/benchmarking/src/mock.rs b/substrate/frame/offences/benchmarking/src/mock.rs index ea2e9e93ed68aabf1b30de0a1cbe5a235acdbcad..eeaa1364504abbb3aae3c2953d99f21952198b72 100644 --- a/substrate/frame/offences/benchmarking/src/mock.rs +++ b/substrate/frame/offences/benchmarking/src/mock.rs @@ -17,9 +17,6 @@ //! Mock file for offences benchmarking. -#![cfg(test)] - -use super::*; use frame_election_provider_support::{ bounds::{ElectionBounds, ElectionBoundsBuilder}, onchain, SequentialPhragmen, @@ -33,7 +30,7 @@ use pallet_session::historical as pallet_session_historical; use sp_runtime::{ testing::{Header, UintAuthorityId}, traits::IdentityLookup, - BuildStorage, + BuildStorage, Perbill, }; type AccountId = u64; @@ -177,7 +174,6 @@ impl pallet_staking::Config for Test { type EraPayout = pallet_staking::ConvertCurve; type NextNewSession = Session; type MaxExposurePageSize = ConstU32<64>; - type OffendingValidatorsThreshold = (); type ElectionProvider = onchain::OnChainExecution; type GenesisElectionProvider = Self::ElectionProvider; type VoterList = pallet_staking::UseNominatorsAndValidatorsMap; @@ -189,6 +185,7 @@ impl pallet_staking::Config for Test { type EventListeners = (); type BenchmarkingConfig = pallet_staking::TestBenchmarkingConfig; type WeightInfo = (); + type DisablingStrategy = pallet_staking::UpToLimitDisablingStrategy; } impl pallet_im_online::Config for Test { diff --git a/substrate/frame/offences/src/lib.rs b/substrate/frame/offences/src/lib.rs index 1c7ffeca7198325374f473cbae9e2f116697530c..a328b2fee4e2e72d3254f0a0a8283951bf5a5fc2 100644 --- a/substrate/frame/offences/src/lib.rs +++ b/substrate/frame/offences/src/lib.rs @@ -132,7 +132,6 @@ where &concurrent_offenders, &slash_perbill, offence.session_index(), - offence.disable_strategy(), ); // Deposit the event. diff --git a/substrate/frame/offences/src/migration.rs b/substrate/frame/offences/src/migration.rs index 3b5cf3ce926952df21248ea5b35271d6596a554b..199f47491369b8281e414076f35e43be823931c8 100644 --- a/substrate/frame/offences/src/migration.rs +++ b/substrate/frame/offences/src/migration.rs @@ -23,7 +23,7 @@ use frame_support::{ weights::Weight, Twox64Concat, }; -use sp_staking::offence::{DisableStrategy, OnOffenceHandler}; +use sp_staking::offence::OnOffenceHandler; use sp_std::vec::Vec; #[cfg(feature = "try-runtime")] @@ -106,12 +106,7 @@ pub fn remove_deferred_storage() -> Weight { let deferred = >::take(); log::info!(target: LOG_TARGET, "have {} deferred offences, applying.", deferred.len()); for (offences, perbill, session) in deferred.iter() { - let consumed = T::OnOffenceHandler::on_offence( - offences, - perbill, - *session, - DisableStrategy::WhenSlashed, - ); + let consumed = T::OnOffenceHandler::on_offence(offences, perbill, *session); weight = weight.saturating_add(consumed); } diff --git a/substrate/frame/offences/src/mock.rs b/substrate/frame/offences/src/mock.rs index 31d5f805f3e4894407cd245db8bd7856d73c57cc..9a3120e41eaa0ae04ef4d211868c53782e3a4cbf 100644 --- a/substrate/frame/offences/src/mock.rs +++ b/substrate/frame/offences/src/mock.rs @@ -33,7 +33,7 @@ use sp_runtime::{ BuildStorage, Perbill, }; use sp_staking::{ - offence::{self, DisableStrategy, Kind, OffenceDetails}, + offence::{self, Kind, OffenceDetails}, SessionIndex, }; @@ -51,7 +51,6 @@ impl offence::OnOffenceHandler _offenders: &[OffenceDetails], slash_fraction: &[Perbill], _offence_session: SessionIndex, - _disable_strategy: DisableStrategy, ) -> Weight { OnOffencePerbill::mutate(|f| { *f = slash_fraction.to_vec(); diff --git a/substrate/frame/paged-list/Cargo.toml b/substrate/frame/paged-list/Cargo.toml index 26f3d7e48ced011697194abe734f87bee84756ee..f550e694349468efcca9bacf51242d378b64ba64 100644 --- a/substrate/frame/paged-list/Cargo.toml +++ b/substrate/frame/paged-list/Cargo.toml @@ -15,7 +15,7 @@ workspace = true targets = ["x86_64-unknown-linux-gnu"] [dependencies] -codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = ["derive"] } +codec = { package = "parity-scale-codec", version = "3.6.12", default-features = false, features = ["derive"] } docify = "0.2.8" scale-info = { version = "2.11.1", default-features = false, features = ["derive"] } diff --git a/substrate/frame/parameters/Cargo.toml b/substrate/frame/parameters/Cargo.toml index b718b391019a701194678e819a1c823371e15231..c4d6d189d2d2c2a33a428cdcf3290c629464662b 100644 --- a/substrate/frame/parameters/Cargo.toml +++ b/substrate/frame/parameters/Cargo.toml @@ -8,7 +8,7 @@ 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"] } +codec = { package = "parity-scale-codec", version = "3.6.12", default-features = false, features = ["max-encoded-len"] } scale-info = { version = "2.11.1", default-features = false, features = ["derive"] } paste = { version = "1.0.14", default-features = false } serde = { features = ["derive"], optional = true, workspace = true, default-features = true } diff --git a/substrate/frame/preimage/Cargo.toml b/substrate/frame/preimage/Cargo.toml index d67fc7bead04c4dc01aca6494d823c786d69715c..d420accbd6d914816d00a57879d7187f0d0d4ead 100644 --- a/substrate/frame/preimage/Cargo.toml +++ b/substrate/frame/preimage/Cargo.toml @@ -12,7 +12,7 @@ description = "FRAME pallet for storing preimages of hashes" workspace = true [dependencies] -codec = { package = "parity-scale-codec", version = "3.6.1", default-features = false, features = ["derive"] } +codec = { package = "parity-scale-codec", version = "3.6.12", default-features = false, features = ["derive"] } scale-info = { version = "2.11.1", 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/proxy/Cargo.toml b/substrate/frame/proxy/Cargo.toml index 0a3b39e471d429f6bc5cfdec203aa085d8f6144e..fcebbb5f3e8a077c8505f333b073d384fb1646b2 100644 --- a/substrate/frame/proxy/Cargo.toml +++ b/substrate/frame/proxy/Cargo.toml @@ -16,7 +16,7 @@ workspace = true targets = ["x86_64-unknown-linux-gnu"] [dependencies] -codec = { package = "parity-scale-codec", version = "3.6.1", default-features = false, features = ["max-encoded-len"] } +codec = { package = "parity-scale-codec", version = "3.6.12", default-features = false, features = ["max-encoded-len"] } scale-info = { version = "2.11.1", 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/Cargo.toml b/substrate/frame/ranked-collective/Cargo.toml index 0a6595807750388d3a99016276f69d57772bbba7..05ce76cad2bbe133a77e9c318ce8f32a57f3a659 100644 --- a/substrate/frame/ranked-collective/Cargo.toml +++ b/substrate/frame/ranked-collective/Cargo.toml @@ -16,7 +16,7 @@ workspace = true targets = ["x86_64-unknown-linux-gnu"] [dependencies] -codec = { package = "parity-scale-codec", version = "3.6.1", default-features = false, features = ["derive"] } +codec = { package = "parity-scale-codec", version = "3.6.12", default-features = false, features = ["derive"] } log = { workspace = true } scale-info = { version = "2.11.1", default-features = false, features = ["derive"] } frame-benchmarking = { path = "../benchmarking", default-features = false, optional = true } diff --git a/substrate/frame/recovery/Cargo.toml b/substrate/frame/recovery/Cargo.toml index 43608de37fc3c08ecb9a266388c2b2b8b07d0255..2fd63597da9caf7ede188eb4a0e70a7d809bae05 100644 --- a/substrate/frame/recovery/Cargo.toml +++ b/substrate/frame/recovery/Cargo.toml @@ -16,7 +16,7 @@ workspace = true targets = ["x86_64-unknown-linux-gnu"] [dependencies] -codec = { package = "parity-scale-codec", version = "3.6.1", default-features = false, features = ["derive"] } +codec = { package = "parity-scale-codec", version = "3.6.12", default-features = false, features = ["derive"] } scale-info = { version = "2.11.1", 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/referenda/Cargo.toml b/substrate/frame/referenda/Cargo.toml index f4e0171443aa5181e13866edf07a98e6d1b0bf8e..dde522ff89b59a647e87dd8436cb32bf1bb0274f 100644 --- a/substrate/frame/referenda/Cargo.toml +++ b/substrate/frame/referenda/Cargo.toml @@ -17,7 +17,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] assert_matches = { version = "1.5", optional = true } -codec = { package = "parity-scale-codec", version = "3.6.1", default-features = false, features = [ +codec = { package = "parity-scale-codec", version = "3.6.12", default-features = false, features = [ "derive", ] } scale-info = { version = "2.11.1", default-features = false, features = ["derive"] } diff --git a/substrate/frame/remark/Cargo.toml b/substrate/frame/remark/Cargo.toml index e746b0382aea105009861aa14d4a9d9c63940556..d251aacfb5b2c204a29d3098b41cba4f0317b3ca 100644 --- a/substrate/frame/remark/Cargo.toml +++ b/substrate/frame/remark/Cargo.toml @@ -16,7 +16,7 @@ workspace = true targets = ["x86_64-unknown-linux-gnu"] [dependencies] -codec = { package = "parity-scale-codec", version = "3.6.1", default-features = false } +codec = { package = "parity-scale-codec", version = "3.6.12", default-features = false } scale-info = { version = "2.11.1", default-features = false, features = ["derive"] } serde = { optional = true, workspace = true, default-features = true } frame-benchmarking = { path = "../benchmarking", default-features = false, optional = true } diff --git a/substrate/frame/root-offences/Cargo.toml b/substrate/frame/root-offences/Cargo.toml index ad3dcf1f90eaf48d95cac601d397c2be673d9824..e7317d737fac125e5ebbafa2be46b0426014bd6e 100644 --- a/substrate/frame/root-offences/Cargo.toml +++ b/substrate/frame/root-offences/Cargo.toml @@ -16,7 +16,7 @@ workspace = true targets = ["x86_64-unknown-linux-gnu"] [dependencies] -codec = { package = "parity-scale-codec", version = "3.6.1", default-features = false, features = ["derive"] } +codec = { package = "parity-scale-codec", version = "3.6.12", default-features = false, features = ["derive"] } scale-info = { version = "2.11.1", default-features = false, features = ["derive"] } pallet-session = { path = "../session", default-features = false, features = ["historical"] } @@ -24,7 +24,7 @@ pallet-staking = { path = "../staking", default-features = false } frame-support = { path = "../support", default-features = false } frame-system = { path = "../system", default-features = false } -sp-runtime = { path = "../../primitives/runtime" } +sp-runtime = { path = "../../primitives/runtime", default-features = false } sp-staking = { path = "../../primitives/staking", default-features = false } [dev-dependencies] @@ -34,7 +34,7 @@ pallet-staking-reward-curve = { path = "../staking/reward-curve" } sp-core = { path = "../../primitives/core" } sp-io = { path = "../../primitives/io", default-features = false } -sp-std = { path = "../../primitives/std", default-features = false } +sp-std = { path = "../../primitives/std" } frame-election-provider-support = { path = "../election-provider-support" } @@ -74,5 +74,4 @@ std = [ "sp-io/std", "sp-runtime/std", "sp-staking/std", - "sp-std/std", ] diff --git a/substrate/frame/root-offences/src/lib.rs b/substrate/frame/root-offences/src/lib.rs index e6bb5bb188199c05c75def4cb19adbe4e5e1fecb..6531080b8d10436def07dfc3ae23e74c2b5962d4 100644 --- a/substrate/frame/root-offences/src/lib.rs +++ b/substrate/frame/root-offences/src/lib.rs @@ -27,10 +27,13 @@ mod mock; #[cfg(test)] mod tests; +extern crate alloc; + +use alloc::vec::Vec; use pallet_session::historical::IdentificationTuple; use pallet_staking::{BalanceOf, Exposure, ExposureOf, Pallet as Staking}; use sp_runtime::Perbill; -use sp_staking::offence::{DisableStrategy, OnOffenceHandler}; +use sp_staking::offence::OnOffenceHandler; pub use pallet::*; @@ -112,7 +115,7 @@ pub mod pallet { .into_iter() .map(|(o, _)| OffenceDetails:: { offender: (o.clone(), Staking::::eras_stakers(now, &o)), - reporters: vec![], + reporters: Default::default(), }) .collect()) } @@ -125,7 +128,7 @@ pub mod pallet { T::AccountId, IdentificationTuple, Weight, - >>::on_offence(&offenders, &slash_fraction, session_index, DisableStrategy::WhenSlashed); + >>::on_offence(&offenders, &slash_fraction, session_index); } } } diff --git a/substrate/frame/root-offences/src/mock.rs b/substrate/frame/root-offences/src/mock.rs index 626db138c2bf955b5d8b6b018f28f7e01acd753a..7e7332c3f7e3b39ca9457c6da05c7eb66197d0c4 100644 --- a/substrate/frame/root-offences/src/mock.rs +++ b/substrate/frame/root-offences/src/mock.rs @@ -133,7 +133,6 @@ parameter_types! { pub static SlashDeferDuration: EraIndex = 0; pub const BondingDuration: EraIndex = 3; pub static LedgerSlashPerEra: (BalanceOf, BTreeMap>) = (Zero::zero(), BTreeMap::new()); - pub const OffendingValidatorsThreshold: Perbill = Perbill::from_percent(75); } impl pallet_staking::Config for Test { @@ -153,7 +152,6 @@ impl pallet_staking::Config for Test { type EraPayout = pallet_staking::ConvertCurve; type NextNewSession = Session; type MaxExposurePageSize = ConstU32<64>; - type OffendingValidatorsThreshold = OffendingValidatorsThreshold; type ElectionProvider = onchain::OnChainExecution; type GenesisElectionProvider = Self::ElectionProvider; type TargetList = pallet_staking::UseValidatorsMap; @@ -165,6 +163,7 @@ impl pallet_staking::Config for Test { type EventListeners = (); type BenchmarkingConfig = pallet_staking::TestBenchmarkingConfig; type WeightInfo = (); + type DisablingStrategy = pallet_staking::UpToLimitDisablingStrategy; } impl pallet_session::historical::Config for Test { diff --git a/substrate/frame/root-testing/Cargo.toml b/substrate/frame/root-testing/Cargo.toml index bf14516ee32281558cbfba28d23f1e9f8526350a..74a3b8f479fa30df155de60d306251a7f8e7e694 100644 --- a/substrate/frame/root-testing/Cargo.toml +++ b/substrate/frame/root-testing/Cargo.toml @@ -16,7 +16,7 @@ workspace = true targets = ["x86_64-unknown-linux-gnu"] [dependencies] -codec = { package = "parity-scale-codec", version = "3.6.1", default-features = false, features = ["derive"] } +codec = { package = "parity-scale-codec", version = "3.6.12", default-features = false, features = ["derive"] } scale-info = { version = "2.11.1", default-features = false, features = ["derive"] } frame-support = { path = "../support", default-features = false } frame-system = { path = "../system", default-features = false } diff --git a/substrate/frame/safe-mode/Cargo.toml b/substrate/frame/safe-mode/Cargo.toml index b6b7e5a67e481a75914207410afe64a8c5b38280..7ecbdb6eeda5b16d35be7a98885ba0a027fbb89a 100644 --- a/substrate/frame/safe-mode/Cargo.toml +++ b/substrate/frame/safe-mode/Cargo.toml @@ -15,7 +15,7 @@ workspace = true targets = ["x86_64-unknown-linux-gnu"] [dependencies] -codec = { package = "parity-scale-codec", version = "3.2.2", default-features = false, features = ["derive"] } +codec = { package = "parity-scale-codec", version = "3.6.12", default-features = false, features = ["derive"] } docify = "0.2.8" frame-benchmarking = { path = "../benchmarking", default-features = false, optional = true } frame-support = { path = "../support", default-features = false } diff --git a/substrate/frame/safe-mode/src/lib.rs b/substrate/frame/safe-mode/src/lib.rs index 2bf2ebee0a4ac88aebe6d2ccc498ac8b5d958352..4be0776d6c1fa439da906ef239db072c26c68247 100644 --- a/substrate/frame/safe-mode/src/lib.rs +++ b/substrate/frame/safe-mode/src/lib.rs @@ -79,7 +79,6 @@ pub mod mock; mod tests; pub mod weights; -use core::convert::TryInto; use frame_support::{ defensive_assert, pallet_prelude::*, diff --git a/substrate/frame/salary/Cargo.toml b/substrate/frame/salary/Cargo.toml index 8c77edcb173a03ed4ed8a8c039c3e670d4bf02ce..25911269a95ddd3b51e639f56c10a647d321ba77 100644 --- a/substrate/frame/salary/Cargo.toml +++ b/substrate/frame/salary/Cargo.toml @@ -16,7 +16,7 @@ workspace = true targets = ["x86_64-unknown-linux-gnu"] [dependencies] -codec = { package = "parity-scale-codec", version = "3.6.1", default-features = false, features = ["derive"] } +codec = { package = "parity-scale-codec", version = "3.6.12", default-features = false, features = ["derive"] } log = { workspace = true } scale-info = { version = "2.11.1", default-features = false, features = ["derive"] } frame-benchmarking = { path = "../benchmarking", default-features = false, optional = true } diff --git a/substrate/frame/sassafras/Cargo.toml b/substrate/frame/sassafras/Cargo.toml index 09977142efc89a95b982ddef69be8d7552e5eee7..82fb9a1d8c5f1bd57073d9212003f6f35da42178 100644 --- a/substrate/frame/sassafras/Cargo.toml +++ b/substrate/frame/sassafras/Cargo.toml @@ -2,7 +2,7 @@ name = "pallet-sassafras" version = "0.3.5-dev" authors = ["Parity Technologies "] -edition = "2021" +edition.workspace = true license = "Apache-2.0" homepage = "https://substrate.io" repository = "https://github.com/paritytech/substrate/" @@ -17,7 +17,7 @@ workspace = true targets = ["x86_64-unknown-linux-gnu"] [dependencies] -scale-codec = { package = "parity-scale-codec", version = "3.6.1", default-features = false, features = ["derive"] } +scale-codec = { package = "parity-scale-codec", version = "3.6.12", default-features = false, features = ["derive"] } scale-info = { version = "2.11.1", default-features = false, features = ["derive"] } frame-benchmarking = { path = "../benchmarking", default-features = false, optional = true } frame-support = { path = "../support", default-features = false } @@ -29,7 +29,7 @@ sp-runtime = { path = "../../primitives/runtime", default-features = false } sp-std = { path = "../../primitives/std", default-features = false } [dev-dependencies] -array-bytes = "6.1" +array-bytes = "6.2.2" sp-core = { path = "../../primitives/core" } sp-crypto-hashing = { path = "../../primitives/crypto/hashing" } diff --git a/substrate/frame/scheduler/Cargo.toml b/substrate/frame/scheduler/Cargo.toml index 40a71736447076d10fd6d8f668a019581f5911f3..e851f876112e8829a7914b18f5695436040ebbb8 100644 --- a/substrate/frame/scheduler/Cargo.toml +++ b/substrate/frame/scheduler/Cargo.toml @@ -13,7 +13,7 @@ readme = "README.md" workspace = true [dependencies] -codec = { package = "parity-scale-codec", version = "3.6.1", default-features = false, features = ["derive"] } +codec = { package = "parity-scale-codec", version = "3.6.12", default-features = false, features = ["derive"] } log = { workspace = true } scale-info = { version = "2.11.1", default-features = false, features = ["derive"] } frame-benchmarking = { path = "../benchmarking", default-features = false, optional = true } diff --git a/substrate/frame/scored-pool/Cargo.toml b/substrate/frame/scored-pool/Cargo.toml index 92b70e01b9ab7e37d0274b434b357eb654773e83..f25bd1f1769ba458c8ea8c88ac9d0e18ce8fde2e 100644 --- a/substrate/frame/scored-pool/Cargo.toml +++ b/substrate/frame/scored-pool/Cargo.toml @@ -16,7 +16,7 @@ workspace = true targets = ["x86_64-unknown-linux-gnu"] [dependencies] -codec = { package = "parity-scale-codec", version = "3.6.1", default-features = false, features = ["derive"] } +codec = { package = "parity-scale-codec", version = "3.6.12", default-features = false, features = ["derive"] } scale-info = { version = "2.11.1", default-features = false, features = ["derive"] } frame-support = { path = "../support", default-features = false } frame-system = { path = "../system", default-features = false } diff --git a/substrate/frame/session/Cargo.toml b/substrate/frame/session/Cargo.toml index 86814f8276e7bed8625f726b17d5ea18c6cf604f..42ea957ac1581fa8434d94a0737597d82f4b74e5 100644 --- a/substrate/frame/session/Cargo.toml +++ b/substrate/frame/session/Cargo.toml @@ -16,7 +16,7 @@ workspace = true targets = ["x86_64-unknown-linux-gnu"] [dependencies] -codec = { package = "parity-scale-codec", version = "3.6.1", default-features = false, features = ["derive"] } +codec = { package = "parity-scale-codec", version = "3.6.12", default-features = false, features = ["derive"] } impl-trait-for-tuples = "0.2.2" log = { workspace = true } scale-info = { version = "2.11.1", default-features = false, features = ["derive", "serde"] } diff --git a/substrate/frame/session/benchmarking/Cargo.toml b/substrate/frame/session/benchmarking/Cargo.toml index a00fbd8f6fdf5452b1e225332efaac7f0d09adfb..a306f9015c02913da0f2ebf96a252a86f4333c51 100644 --- a/substrate/frame/session/benchmarking/Cargo.toml +++ b/substrate/frame/session/benchmarking/Cargo.toml @@ -16,7 +16,7 @@ workspace = true targets = ["x86_64-unknown-linux-gnu"] [dependencies] -codec = { package = "parity-scale-codec", version = "3.6.1", default-features = false } +codec = { package = "parity-scale-codec", version = "3.6.12", default-features = false } rand = { version = "0.8.5", default-features = false, features = ["std_rng"] } frame-benchmarking = { path = "../../benchmarking", default-features = false } frame-support = { path = "../../support", default-features = false } @@ -28,7 +28,7 @@ sp-session = { path = "../../../primitives/session", default-features = false } sp-std = { path = "../../../primitives/std", default-features = false } [dev-dependencies] -codec = { package = "parity-scale-codec", version = "3.6.1", features = ["derive"] } +codec = { package = "parity-scale-codec", version = "3.6.12", features = ["derive"] } scale-info = "2.11.1" frame-election-provider-support = { path = "../../election-provider-support" } pallet-balances = { path = "../../balances" } diff --git a/substrate/frame/session/benchmarking/src/inner.rs b/substrate/frame/session/benchmarking/src/inner.rs new file mode 100644 index 0000000000000000000000000000000000000000..d86c5d9ad278ea9d914877c63d7a316eebf148c9 --- /dev/null +++ b/substrate/frame/session/benchmarking/src/inner.rs @@ -0,0 +1,162 @@ +// 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 the Session Pallet. +// This is separated into its own crate due to cyclic dependency issues. + +use sp_runtime::traits::{One, StaticLookup, TrailingZeroInput}; +use sp_std::{prelude::*, vec}; + +use codec::Decode; +use frame_benchmarking::v1::benchmarks; +use frame_support::traits::{Get, KeyOwnerProofSystem, OnInitialize}; +use frame_system::{pallet_prelude::BlockNumberFor, RawOrigin}; +use pallet_session::{historical::Pallet as Historical, Pallet as Session, *}; +use pallet_staking::{ + benchmarking::create_validator_with_nominators, testing_utils::create_validators, + MaxNominationsOf, RewardDestination, +}; + +const MAX_VALIDATORS: u32 = 1000; + +pub struct Pallet(pallet_session::Pallet); +pub trait Config: + pallet_session::Config + pallet_session::historical::Config + pallet_staking::Config +{ +} + +impl OnInitialize> for Pallet { + fn on_initialize(n: BlockNumberFor) -> frame_support::weights::Weight { + pallet_session::Pallet::::on_initialize(n) + } +} + +benchmarks! { + set_keys { + let n = MaxNominationsOf::::get(); + let (v_stash, _) = create_validator_with_nominators::( + n, + MaxNominationsOf::::get(), + false, + true, + RewardDestination::Staked, + )?; + let v_controller = pallet_staking::Pallet::::bonded(&v_stash).ok_or("not stash")?; + + let keys = T::Keys::decode(&mut TrailingZeroInput::zeroes()).unwrap(); + let proof: Vec = vec![0,1,2,3]; + // Whitelist controller account from further DB operations. + let v_controller_key = frame_system::Account::::hashed_key_for(&v_controller); + frame_benchmarking::benchmarking::add_to_whitelist(v_controller_key.into()); + }: _(RawOrigin::Signed(v_controller), keys, proof) + + purge_keys { + let n = MaxNominationsOf::::get(); + let (v_stash, _) = create_validator_with_nominators::( + n, + MaxNominationsOf::::get(), + false, + true, + RewardDestination::Staked, + )?; + let v_controller = pallet_staking::Pallet::::bonded(&v_stash).ok_or("not stash")?; + let keys = T::Keys::decode(&mut TrailingZeroInput::zeroes()).unwrap(); + let proof: Vec = vec![0,1,2,3]; + Session::::set_keys(RawOrigin::Signed(v_controller.clone()).into(), keys, proof)?; + // Whitelist controller account from further DB operations. + let v_controller_key = frame_system::Account::::hashed_key_for(&v_controller); + frame_benchmarking::benchmarking::add_to_whitelist(v_controller_key.into()); + }: _(RawOrigin::Signed(v_controller)) + + #[extra] + check_membership_proof_current_session { + let n in 2 .. MAX_VALIDATORS as u32; + + let (key, key_owner_proof1) = check_membership_proof_setup::(n); + let key_owner_proof2 = key_owner_proof1.clone(); + }: { + Historical::::check_proof(key, key_owner_proof1); + } + verify { + assert!(Historical::::check_proof(key, key_owner_proof2).is_some()); + } + + #[extra] + check_membership_proof_historical_session { + let n in 2 .. MAX_VALIDATORS as u32; + + let (key, key_owner_proof1) = check_membership_proof_setup::(n); + + // skip to the next session so that the session is historical + // and the membership merkle proof must be checked. + Session::::rotate_session(); + + let key_owner_proof2 = key_owner_proof1.clone(); + }: { + Historical::::check_proof(key, key_owner_proof1); + } + verify { + assert!(Historical::::check_proof(key, key_owner_proof2).is_some()); + } + + impl_benchmark_test_suite!(Pallet, crate::mock::new_test_ext(), crate::mock::Test, extra = false); +} + +/// Sets up the benchmark for checking a membership proof. It creates the given +/// number of validators, sets random session keys and then creates a membership +/// proof for the first authority and returns its key and the proof. +fn check_membership_proof_setup( + n: u32, +) -> ((sp_runtime::KeyTypeId, &'static [u8; 32]), sp_session::MembershipProof) { + pallet_staking::ValidatorCount::::put(n); + + // create validators and set random session keys + for (n, who) in create_validators::(n, 1000).unwrap().into_iter().enumerate() { + use rand::{RngCore, SeedableRng}; + + let validator = T::Lookup::lookup(who).unwrap(); + let controller = pallet_staking::Pallet::::bonded(&validator).unwrap(); + + let keys = { + let mut keys = [0u8; 128]; + + // we keep the keys for the first validator as 0x00000... + if n > 0 { + let mut rng = rand::rngs::StdRng::seed_from_u64(n as u64); + rng.fill_bytes(&mut keys); + } + + keys + }; + + let keys: T::Keys = Decode::decode(&mut &keys[..]).unwrap(); + let proof: Vec = vec![]; + + Session::::set_keys(RawOrigin::Signed(controller).into(), keys, proof).unwrap(); + } + + Pallet::::on_initialize(frame_system::pallet_prelude::BlockNumberFor::::one()); + + // skip sessions until the new validator set is enacted + while Session::::validators().len() < n as usize { + Session::::rotate_session(); + } + + let key = (sp_runtime::KeyTypeId(*b"babe"), &[0u8; 32]); + + (key, Historical::::prove(key).unwrap()) +} diff --git a/substrate/frame/session/benchmarking/src/lib.rs b/substrate/frame/session/benchmarking/src/lib.rs index 84258d84994f45233e47a1ca413cb5b89ccf306a..b08955a133297f356a5fa884394b3a88a7e28727 100644 --- a/substrate/frame/session/benchmarking/src/lib.rs +++ b/substrate/frame/session/benchmarking/src/lib.rs @@ -15,153 +15,15 @@ // See the License for the specific language governing permissions and // limitations under the License. -//! Benchmarks for the Session Pallet. -// This is separated into its own crate due to cyclic dependency issues. +//! Offences pallet benchmarking. -#![cfg(feature = "runtime-benchmarks")] #![cfg_attr(not(feature = "std"), no_std)] -mod mock; +#[cfg(feature = "runtime-benchmarks")] +pub mod inner; -use sp_runtime::traits::{One, StaticLookup, TrailingZeroInput}; -use sp_std::{prelude::*, vec}; +#[cfg(feature = "runtime-benchmarks")] +pub use inner::*; -use codec::Decode; -use frame_benchmarking::v1::benchmarks; -use frame_support::traits::{Get, KeyOwnerProofSystem, OnInitialize}; -use frame_system::{pallet_prelude::BlockNumberFor, RawOrigin}; -use pallet_session::{historical::Pallet as Historical, Pallet as Session, *}; -use pallet_staking::{ - benchmarking::create_validator_with_nominators, testing_utils::create_validators, - MaxNominationsOf, RewardDestination, -}; - -const MAX_VALIDATORS: u32 = 1000; - -pub struct Pallet(pallet_session::Pallet); -pub trait Config: - pallet_session::Config + pallet_session::historical::Config + pallet_staking::Config -{ -} - -impl OnInitialize> for Pallet { - fn on_initialize(n: BlockNumberFor) -> frame_support::weights::Weight { - pallet_session::Pallet::::on_initialize(n) - } -} - -benchmarks! { - set_keys { - let n = MaxNominationsOf::::get(); - let (v_stash, _) = create_validator_with_nominators::( - n, - MaxNominationsOf::::get(), - false, - true, - RewardDestination::Staked, - )?; - let v_controller = pallet_staking::Pallet::::bonded(&v_stash).ok_or("not stash")?; - - let keys = T::Keys::decode(&mut TrailingZeroInput::zeroes()).unwrap(); - let proof: Vec = vec![0,1,2,3]; - // Whitelist controller account from further DB operations. - let v_controller_key = frame_system::Account::::hashed_key_for(&v_controller); - frame_benchmarking::benchmarking::add_to_whitelist(v_controller_key.into()); - }: _(RawOrigin::Signed(v_controller), keys, proof) - - purge_keys { - let n = MaxNominationsOf::::get(); - let (v_stash, _) = create_validator_with_nominators::( - n, - MaxNominationsOf::::get(), - false, - true, - RewardDestination::Staked, - )?; - let v_controller = pallet_staking::Pallet::::bonded(&v_stash).ok_or("not stash")?; - let keys = T::Keys::decode(&mut TrailingZeroInput::zeroes()).unwrap(); - let proof: Vec = vec![0,1,2,3]; - Session::::set_keys(RawOrigin::Signed(v_controller.clone()).into(), keys, proof)?; - // Whitelist controller account from further DB operations. - let v_controller_key = frame_system::Account::::hashed_key_for(&v_controller); - frame_benchmarking::benchmarking::add_to_whitelist(v_controller_key.into()); - }: _(RawOrigin::Signed(v_controller)) - - #[extra] - check_membership_proof_current_session { - let n in 2 .. MAX_VALIDATORS as u32; - - let (key, key_owner_proof1) = check_membership_proof_setup::(n); - let key_owner_proof2 = key_owner_proof1.clone(); - }: { - Historical::::check_proof(key, key_owner_proof1); - } - verify { - assert!(Historical::::check_proof(key, key_owner_proof2).is_some()); - } - - #[extra] - check_membership_proof_historical_session { - let n in 2 .. MAX_VALIDATORS as u32; - - let (key, key_owner_proof1) = check_membership_proof_setup::(n); - - // skip to the next session so that the session is historical - // and the membership merkle proof must be checked. - Session::::rotate_session(); - - let key_owner_proof2 = key_owner_proof1.clone(); - }: { - Historical::::check_proof(key, key_owner_proof1); - } - verify { - assert!(Historical::::check_proof(key, key_owner_proof2).is_some()); - } - - impl_benchmark_test_suite!(Pallet, crate::mock::new_test_ext(), crate::mock::Test, extra = false); -} - -/// Sets up the benchmark for checking a membership proof. It creates the given -/// number of validators, sets random session keys and then creates a membership -/// proof for the first authority and returns its key and the proof. -fn check_membership_proof_setup( - n: u32, -) -> ((sp_runtime::KeyTypeId, &'static [u8; 32]), sp_session::MembershipProof) { - pallet_staking::ValidatorCount::::put(n); - - // create validators and set random session keys - for (n, who) in create_validators::(n, 1000).unwrap().into_iter().enumerate() { - use rand::{RngCore, SeedableRng}; - - let validator = T::Lookup::lookup(who).unwrap(); - let controller = pallet_staking::Pallet::::bonded(&validator).unwrap(); - - let keys = { - let mut keys = [0u8; 128]; - - // we keep the keys for the first validator as 0x00000... - if n > 0 { - let mut rng = rand::rngs::StdRng::seed_from_u64(n as u64); - rng.fill_bytes(&mut keys); - } - - keys - }; - - let keys: T::Keys = Decode::decode(&mut &keys[..]).unwrap(); - let proof: Vec = vec![]; - - Session::::set_keys(RawOrigin::Signed(controller).into(), keys, proof).unwrap(); - } - - Pallet::::on_initialize(frame_system::pallet_prelude::BlockNumberFor::::one()); - - // skip sessions until the new validator set is enacted - while Session::::validators().len() < n as usize { - Session::::rotate_session(); - } - - let key = (sp_runtime::KeyTypeId(*b"babe"), &[0u8; 32]); - - (key, Historical::::prove(key).unwrap()) -} +#[cfg(all(feature = "runtime-benchmarks", test))] +pub(crate) mod mock; diff --git a/substrate/frame/session/benchmarking/src/mock.rs b/substrate/frame/session/benchmarking/src/mock.rs index 81052141fd8650106a2bbc68a5a67f2dbf457545..6cefa8f39a8c6081be0f5dfcec4b1d7ed0f8122c 100644 --- a/substrate/frame/session/benchmarking/src/mock.rs +++ b/substrate/frame/session/benchmarking/src/mock.rs @@ -174,7 +174,6 @@ impl pallet_staking::Config for Test { type EraPayout = pallet_staking::ConvertCurve; type NextNewSession = Session; type MaxExposurePageSize = ConstU32<64>; - type OffendingValidatorsThreshold = (); type ElectionProvider = onchain::OnChainExecution; type GenesisElectionProvider = Self::ElectionProvider; type MaxUnlockingChunks = ConstU32<32>; @@ -186,6 +185,7 @@ impl pallet_staking::Config for Test { type EventListeners = (); type BenchmarkingConfig = pallet_staking::TestBenchmarkingConfig; type WeightInfo = (); + type DisablingStrategy = pallet_staking::UpToLimitDisablingStrategy; } impl crate::Config for Test {} diff --git a/substrate/frame/session/src/lib.rs b/substrate/frame/session/src/lib.rs index 17b6aa7a4640ce764919c7e20a07cb7ba1261486..9506e98adf7d70004a3caf57adb9c0c1dd44d5f3 100644 --- a/substrate/frame/session/src/lib.rs +++ b/substrate/frame/session/src/lib.rs @@ -627,7 +627,7 @@ impl Pallet { Validators::::put(&validators); if changed { - // reset disabled validators + // reset disabled validators if active set was changed >::take(); } diff --git a/substrate/frame/society/Cargo.toml b/substrate/frame/society/Cargo.toml index 3d99ddba392bcee045d122e6b898552d0f5e9b75..ed7fea523bffbd15a4da83e16f167ba239ecfca8 100644 --- a/substrate/frame/society/Cargo.toml +++ b/substrate/frame/society/Cargo.toml @@ -17,9 +17,9 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] log = { workspace = true } -rand_chacha = { version = "0.2", default-features = false } +rand_chacha = { version = "0.3.1", default-features = false } scale-info = { version = "2.11.1", default-features = false, features = ["derive"] } -codec = { package = "parity-scale-codec", version = "3.6.1", default-features = false, features = ["derive"] } +codec = { package = "parity-scale-codec", version = "3.6.12", default-features = false, features = ["derive"] } sp-std = { path = "../../primitives/std", default-features = false } sp-io = { path = "../../primitives/io", default-features = false } diff --git a/substrate/frame/src/lib.rs b/substrate/frame/src/lib.rs index f93f4d31e777c93e999f4346b9b74e2a13979e4d..f6507cd02c71ae5542836119821fc29070a24f6a 100644 --- a/substrate/frame/src/lib.rs +++ b/substrate/frame/src/lib.rs @@ -34,9 +34,9 @@ //! //! See [`polkadot_sdk::frame`](../polkadot_sdk_docs/polkadot_sdk/frame_runtime/index.html). //! -//! ## Warning: Experimental +//! ## WARNING: Experimental //! -//! This crate and all of its content is experimental, and should not yet be used in production. +//! **This crate and all of its content is experimental, and should not yet be used in production.** //! //! ## Underlying dependencies //! @@ -363,5 +363,15 @@ pub mod deps { #[cfg(feature = "runtime")] pub use sp_offchain; #[cfg(feature = "runtime")] + pub use sp_storage; + #[cfg(feature = "runtime")] pub use sp_version; + + #[cfg(feature = "runtime-benchmarks")] + pub use frame_benchmarking; + #[cfg(feature = "runtime-benchmarks")] + pub use frame_system_benchmarking; + + #[cfg(feature = "frame-try-runtime")] + pub use frame_try_runtime; } diff --git a/substrate/frame/staking/CHANGELOG.md b/substrate/frame/staking/CHANGELOG.md index 719aa388755fce3523cadb273bb542e48076d3f5..113b7a6200b6e5b8014db37c0b43b7f45b96e62b 100644 --- a/substrate/frame/staking/CHANGELOG.md +++ b/substrate/frame/staking/CHANGELOG.md @@ -7,6 +7,25 @@ on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/). We maintain a single integer version number for staking pallet to keep track of all storage migrations. +## [v15] + +### Added + +- New trait `DisablingStrategy` which is responsible for making a decision which offenders should be + disabled on new offence. +- Default implementation of `DisablingStrategy` - `UpToLimitDisablingStrategy`. It + disables each new offender up to a threshold (1/3 by default). Offenders are not runtime disabled for + offences in previous era(s). But they will be low-priority node-side disabled for dispute initiation. +- `OffendingValidators` storage item is replaced with `DisabledValidators`. The former keeps all + offenders and if they are disabled or not. The latter just keeps a list of all offenders as they + are disabled by default. + +### Deprecated + +- `enum DisableStrategy` is no longer needed because disabling is not related to the type of the + offence anymore. A decision if a offender is disabled or not is made by a `DisablingStrategy` + implementation. + ## [v14] ### Added diff --git a/substrate/frame/staking/Cargo.toml b/substrate/frame/staking/Cargo.toml index 4fd0cedbae63fb3c484549c2f4388f912e7a428d..22df746d667ab477dc576c6c085bbf1bf1675fb6 100644 --- a/substrate/frame/staking/Cargo.toml +++ b/substrate/frame/staking/Cargo.toml @@ -17,7 +17,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] serde = { features = ["alloc", "derive"], workspace = true } -codec = { package = "parity-scale-codec", version = "3.6.1", default-features = false, features = [ +codec = { package = "parity-scale-codec", version = "3.6.12", default-features = false, features = [ "derive", ] } scale-info = { version = "2.11.1", default-features = false, features = ["derive", "serde"] } @@ -37,7 +37,7 @@ log = { workspace = true } # Optional imports for benchmarking frame-benchmarking = { path = "../benchmarking", default-features = false, optional = true } -rand_chacha = { version = "0.2", default-features = false, optional = true } +rand_chacha = { version = "0.3.1", default-features = false, optional = true } [dev-dependencies] pallet-balances = { path = "../balances" } @@ -50,7 +50,7 @@ pallet-bags-list = { path = "../bags-list" } substrate-test-utils = { path = "../../test-utils" } frame-benchmarking = { path = "../benchmarking" } frame-election-provider-support = { path = "../election-provider-support" } -rand_chacha = { version = "0.2" } +rand_chacha = { version = "0.3.1" } [features] default = ["std"] diff --git a/substrate/frame/staking/runtime-api/Cargo.toml b/substrate/frame/staking/runtime-api/Cargo.toml index 50a19be92da8e6be4ddaf8fe29e649ee7b59c256..19da2f24ff00e80321e20506b2fe13a0ddd71978 100644 --- a/substrate/frame/staking/runtime-api/Cargo.toml +++ b/substrate/frame/staking/runtime-api/Cargo.toml @@ -16,7 +16,7 @@ workspace = true targets = ["x86_64-unknown-linux-gnu"] [dependencies] -codec = { package = "parity-scale-codec", version = "3.6.1", default-features = false, features = ["derive"] } +codec = { package = "parity-scale-codec", version = "3.6.12", default-features = false, features = ["derive"] } sp-api = { default-features = false, path = "../../../primitives/api" } sp-staking = { default-features = false, path = "../../../primitives/staking" } diff --git a/substrate/frame/staking/runtime-api/src/lib.rs b/substrate/frame/staking/runtime-api/src/lib.rs index b04c383a077dc8fcb1c70b2fe6ff6117837c2867..7955f4184a434545a013b2967e6d15a5c63b9764 100644 --- a/substrate/frame/staking/runtime-api/src/lib.rs +++ b/substrate/frame/staking/runtime-api/src/lib.rs @@ -30,7 +30,10 @@ sp_api::decl_runtime_apis! { /// Returns the nominations quota for a nominator with a given balance. fn nominations_quota(balance: Balance) -> u32; - /// Returns the page count of exposures for a validator in a given era. + /// Returns the page count of exposures for a validator `account` in a given era. fn eras_stakers_page_count(era: sp_staking::EraIndex, account: AccountId) -> sp_staking::Page; + + /// Returns true if validator `account` has pages to be claimed for the given era. + fn pending_rewards(era: sp_staking::EraIndex, account: AccountId) -> bool; } } diff --git a/substrate/frame/staking/src/ledger.rs b/substrate/frame/staking/src/ledger.rs index 9461daefed65e74c778a248a0bbaeeedd3ee6222..67a86b86226cfb1aa5da4c8bca794f315f348009 100644 --- a/substrate/frame/staking/src/ledger.rs +++ b/substrate/frame/staking/src/ledger.rs @@ -33,13 +33,14 @@ use frame_support::{ defensive, ensure, - traits::{Defensive, LockableCurrency, WithdrawReasons}, + traits::{Defensive, LockableCurrency}, }; use sp_staking::StakingAccount; use sp_std::prelude::*; use crate::{ - BalanceOf, Bonded, Config, Error, Ledger, Payee, RewardDestination, StakingLedger, STAKING_ID, + BalanceOf, Bonded, Config, Error, Ledger, Pallet, Payee, RewardDestination, StakingLedger, + VirtualStakers, STAKING_ID, }; #[cfg(any(feature = "runtime-benchmarks", test))] @@ -187,7 +188,17 @@ impl StakingLedger { return Err(Error::::NotStash) } - T::Currency::set_lock(STAKING_ID, &self.stash, self.total, WithdrawReasons::all()); + // We skip locking virtual stakers. + if !Pallet::::is_virtual_staker(&self.stash) { + // for direct stakers, update lock on stash based on ledger. + T::Currency::set_lock( + STAKING_ID, + &self.stash, + self.total, + frame_support::traits::WithdrawReasons::all(), + ); + } + Ledger::::insert( &self.controller().ok_or_else(|| { defensive!("update called on a ledger that is not bonded."); @@ -204,22 +215,22 @@ impl StakingLedger { /// It sets the reward preferences for the bonded stash. pub(crate) fn bond(self, payee: RewardDestination) -> Result<(), Error> { if >::contains_key(&self.stash) { - Err(Error::::AlreadyBonded) - } else { - >::insert(&self.stash, payee); - >::insert(&self.stash, &self.stash); - self.update() + return Err(Error::::AlreadyBonded) } + + >::insert(&self.stash, payee); + >::insert(&self.stash, &self.stash); + self.update() } /// Sets the ledger Payee. pub(crate) fn set_payee(self, payee: RewardDestination) -> Result<(), Error> { if !>::contains_key(&self.stash) { - Err(Error::::NotStash) - } else { - >::insert(&self.stash, payee); - Ok(()) + return Err(Error::::NotStash) } + + >::insert(&self.stash, payee); + Ok(()) } /// Sets the ledger controller to its stash. @@ -252,12 +263,16 @@ impl StakingLedger { let controller = >::get(stash).ok_or(Error::::NotStash)?; >::get(&controller).ok_or(Error::::NotController).map(|ledger| { - T::Currency::remove_lock(STAKING_ID, &ledger.stash); Ledger::::remove(controller); - >::remove(&stash); >::remove(&stash); + // kill virtual staker if it exists. + if >::take(&stash).is_none() { + // if not virtual staker, clear locks. + T::Currency::remove_lock(STAKING_ID, &ledger.stash); + } + Ok(()) })? } diff --git a/substrate/frame/staking/src/lib.rs b/substrate/frame/staking/src/lib.rs index f5b7e3eca3de7cd49b6a5cbdef37dfa4feff80ec..4f91fd6dff220d7fbf2b768a3b9f9a4d3e8c29ab 100644 --- a/substrate/frame/staking/src/lib.rs +++ b/substrate/frame/staking/src/lib.rs @@ -376,7 +376,7 @@ pub struct ActiveEraInfo { /// /// Start can be none if start hasn't been set for the era yet, /// Start is set on the first on_finalize of the era to guarantee usage of `Time`. - start: Option, + pub start: Option, } /// Reward points of an era. Used to split era total payout between validators. @@ -1035,11 +1035,37 @@ where /// can and add more functions to it as needed. pub struct EraInfo(sp_std::marker::PhantomData); impl EraInfo { + /// Returns true if validator has one or more page of era rewards not claimed yet. + // Also looks at legacy storage that can be cleaned up after #433. + pub fn pending_rewards(era: EraIndex, validator: &T::AccountId) -> bool { + let page_count = if let Some(overview) = >::get(&era, validator) { + overview.page_count + } else { + if >::contains_key(era, validator) { + // this means non paged exposure, and we treat them as single paged. + 1 + } else { + // if no exposure, then no rewards to claim. + return false + } + }; + + // check if era is marked claimed in legacy storage. + if >::get(validator) + .map(|l| l.legacy_claimed_rewards.contains(&era)) + .unwrap_or_default() + { + return false + } + + ClaimedRewards::::get(era, validator).len() < page_count as usize + } + /// Temporary function which looks at both (1) passed param `T::StakingLedger` for legacy /// non-paged rewards, and (2) `T::ClaimedRewards` for paged rewards. This function can be /// removed once `T::HistoryDepth` eras have passed and none of the older non-paged rewards /// are relevant/claimable. - // Refer tracker issue for cleanup: #13034 + // Refer tracker issue for cleanup: https://github.com/paritytech/polkadot-sdk/issues/433 pub(crate) fn is_rewards_claimed_with_legacy_fallback( era: EraIndex, ledger: &StakingLedger, @@ -1239,3 +1265,79 @@ impl BenchmarkingConfig for TestBenchmarkingConfig { type MaxValidators = frame_support::traits::ConstU32<100>; type MaxNominators = frame_support::traits::ConstU32<100>; } + +/// Controls validator disabling +pub trait DisablingStrategy { + /// Make a disabling decision. Returns the index of the validator to disable or `None` if no new + /// validator should be disabled. + fn decision( + offender_stash: &T::AccountId, + slash_era: EraIndex, + currently_disabled: &Vec, + ) -> Option; +} + +/// Implementation of [`DisablingStrategy`] which disables validators from the active set up to a +/// threshold. `DISABLING_LIMIT_FACTOR` is the factor of the maximum disabled validators in the +/// active set. E.g. setting this value to `3` means no more than 1/3 of the validators in the +/// active set can be disabled in an era. +/// By default a factor of 3 is used which is the byzantine threshold. +pub struct UpToLimitDisablingStrategy; + +impl UpToLimitDisablingStrategy { + /// Disabling limit calculated from the total number of validators in the active set. When + /// reached no more validators will be disabled. + pub fn disable_limit(validators_len: usize) -> usize { + validators_len + .saturating_sub(1) + .checked_div(DISABLING_LIMIT_FACTOR) + .unwrap_or_else(|| { + defensive!("DISABLING_LIMIT_FACTOR should not be 0"); + 0 + }) + } +} + +impl DisablingStrategy + for UpToLimitDisablingStrategy +{ + fn decision( + offender_stash: &T::AccountId, + slash_era: EraIndex, + currently_disabled: &Vec, + ) -> Option { + let active_set = T::SessionInterface::validators(); + + // We don't disable more than the limit + if currently_disabled.len() >= Self::disable_limit(active_set.len()) { + log!( + debug, + "Won't disable: reached disabling limit {:?}", + Self::disable_limit(active_set.len()) + ); + return None + } + + // We don't disable for offences in previous eras + if ActiveEra::::get().map(|e| e.index).unwrap_or_default() > slash_era { + log!( + debug, + "Won't disable: current_era {:?} > slash_era {:?}", + Pallet::::current_era().unwrap_or_default(), + slash_era + ); + return None + } + + let offender_idx = if let Some(idx) = active_set.iter().position(|i| i == offender_stash) { + idx as u32 + } else { + log!(debug, "Won't disable: offender not in active set",); + return None + }; + + log!(debug, "Will disable {:?}", offender_idx); + + Some(offender_idx) + } +} diff --git a/substrate/frame/staking/src/migrations.rs b/substrate/frame/staking/src/migrations.rs index d5b18421d5b67fbeaac27cbbdecde174fa3d024b..b2ddf77004f95ecf86df6d177cdb6af454947657 100644 --- a/substrate/frame/staking/src/migrations.rs +++ b/substrate/frame/staking/src/migrations.rs @@ -20,9 +20,10 @@ use super::*; use frame_election_provider_support::SortedListProvider; use frame_support::{ + migrations::VersionedMigration, pallet_prelude::ValueQuery, storage_alias, - traits::{GetStorageVersion, OnRuntimeUpgrade}, + traits::{GetStorageVersion, OnRuntimeUpgrade, UncheckedOnRuntimeUpgrade}, }; #[cfg(feature = "try-runtime")] @@ -59,11 +60,61 @@ impl Default for ObsoleteReleases { #[storage_alias] type StorageVersion = StorageValue, ObsoleteReleases, ValueQuery>; +/// Migrating `OffendingValidators` from `Vec<(u32, bool)>` to `Vec` +pub mod v15 { + use super::*; + + // The disabling strategy used by staking pallet + type DefaultDisablingStrategy = UpToLimitDisablingStrategy; + + pub struct VersionUncheckedMigrateV14ToV15(sp_std::marker::PhantomData); + impl UncheckedOnRuntimeUpgrade for VersionUncheckedMigrateV14ToV15 { + fn on_runtime_upgrade() -> Weight { + let mut migrated = v14::OffendingValidators::::take() + .into_iter() + .filter(|p| p.1) // take only disabled validators + .map(|p| p.0) + .collect::>(); + + // Respect disabling limit + migrated.truncate(DefaultDisablingStrategy::disable_limit( + T::SessionInterface::validators().len(), + )); + + DisabledValidators::::set(migrated); + + log!(info, "v15 applied successfully."); + T::DbWeight::get().reads_writes(1, 1) + } + + #[cfg(feature = "try-runtime")] + fn post_upgrade(_state: Vec) -> Result<(), TryRuntimeError> { + frame_support::ensure!( + v14::OffendingValidators::::decode_len().is_none(), + "OffendingValidators is not empty after the migration" + ); + Ok(()) + } + } + + pub type MigrateV14ToV15 = VersionedMigration< + 14, + 15, + VersionUncheckedMigrateV14ToV15, + Pallet, + ::DbWeight, + >; +} + /// Migration of era exposure storage items to paged exposures. /// Changelog: [v14.](https://github.com/paritytech/substrate/blob/ankan/paged-rewards-rebased2/frame/staking/CHANGELOG.md#14) pub mod v14 { use super::*; + #[frame_support::storage_alias] + pub(crate) type OffendingValidators = + StorageValue, Vec<(u32, bool)>, ValueQuery>; + pub struct MigrateToV14(core::marker::PhantomData); impl OnRuntimeUpgrade for MigrateToV14 { fn on_runtime_upgrade() -> Weight { @@ -73,10 +124,10 @@ pub mod v14 { if in_code == 14 && on_chain == 13 { in_code.put::>(); - log!(info, "v14 applied successfully."); + log!(info, "staking v14 applied successfully."); T::DbWeight::get().reads_writes(1, 1) } else { - log!(warn, "v14 not applied."); + log!(warn, "staking v14 not applied."); T::DbWeight::get().reads(1) } } @@ -319,7 +370,7 @@ pub mod v10 { StorageVersion::::put(ObsoleteReleases::V10_0_0); log!(info, "MigrateToV10 executed successfully"); - T::DbWeight::get().reads_writes(1, 1) + T::DbWeight::get().reads_writes(1, 2) } else { log!(warn, "MigrateToV10 should be removed."); T::DbWeight::get().reads(1) diff --git a/substrate/frame/staking/src/mock.rs b/substrate/frame/staking/src/mock.rs index 6db462c1a70fbce4ed2d531bf9ad4d837e83b585..8c60dec65a81a123b5d1bd04b3ea8614ae1e9f0f 100644 --- a/substrate/frame/staking/src/mock.rs +++ b/substrate/frame/staking/src/mock.rs @@ -34,7 +34,7 @@ use frame_system::{EnsureRoot, EnsureSignedBy}; use sp_io; use sp_runtime::{curve::PiecewiseLinear, testing::UintAuthorityId, traits::Zero, BuildStorage}; use sp_staking::{ - offence::{DisableStrategy, OffenceDetails, OnOffenceHandler}, + offence::{OffenceDetails, OnOffenceHandler}, OnStakingUpdate, }; @@ -186,7 +186,6 @@ pallet_staking_reward_curve::build! { parameter_types! { pub const BondingDuration: EraIndex = 3; pub const RewardCurve: &'static PiecewiseLinear<'static> = &I_NPOS; - pub const OffendingValidatorsThreshold: Perbill = Perbill::from_percent(75); } parameter_types! { @@ -249,20 +248,27 @@ parameter_types! { pub static LedgerSlashPerEra: (BalanceOf, BTreeMap>) = (Zero::zero(), BTreeMap::new()); + pub static SlashObserver: BTreeMap> = BTreeMap::new(); } pub struct EventListenerMock; impl OnStakingUpdate for EventListenerMock { fn on_slash( - _pool_account: &AccountId, + pool_account: &AccountId, slashed_bonded: Balance, slashed_chunks: &BTreeMap, - _total_slashed: Balance, + total_slashed: Balance, ) { LedgerSlashPerEra::set((slashed_bonded, slashed_chunks.clone())); + SlashObserver::mutate(|map| { + map.insert(*pool_account, map.get(pool_account).unwrap_or(&0) + total_slashed) + }); } } +// Disabling threshold for `UpToLimitDisablingStrategy` +pub(crate) const DISABLING_LIMIT_FACTOR: usize = 3; + impl crate::pallet::pallet::Config for Test { type Currency = Balances; type CurrencyBalance = ::Balance; @@ -280,7 +286,6 @@ impl crate::pallet::pallet::Config for Test { type EraPayout = ConvertCurve; type NextNewSession = Session; type MaxExposurePageSize = MaxExposurePageSize; - type OffendingValidatorsThreshold = OffendingValidatorsThreshold; type ElectionProvider = onchain::OnChainExecution; type GenesisElectionProvider = Self::ElectionProvider; // NOTE: consider a macro and use `UseNominatorsAndValidatorsMap` as well. @@ -293,6 +298,7 @@ impl crate::pallet::pallet::Config for Test { type EventListeners = EventListenerMock; type BenchmarkingConfig = TestBenchmarkingConfig; type WeightInfo = (); + type DisablingStrategy = pallet_staking::UpToLimitDisablingStrategy; } pub struct WeightedNominationsQuota; @@ -457,6 +463,8 @@ impl ExtBuilder { (31, self.balance_factor * 2000), (41, self.balance_factor * 2000), (51, self.balance_factor * 2000), + (201, self.balance_factor * 2000), + (202, self.balance_factor * 2000), // optional nominator (100, self.balance_factor * 2000), (101, self.balance_factor * 2000), @@ -484,8 +492,10 @@ impl ExtBuilder { (31, 31, self.balance_factor * 500, StakerStatus::::Validator), // an idle validator (41, 41, self.balance_factor * 1000, StakerStatus::::Idle), - ]; - // optionally add a nominator + (51, 51, self.balance_factor * 1000, StakerStatus::::Idle), + (201, 201, self.balance_factor * 1000, StakerStatus::::Idle), + (202, 202, self.balance_factor * 1000, StakerStatus::::Idle), + ]; // optionally add a nominator if self.nominate { stakers.push(( 101, @@ -598,6 +608,21 @@ pub(crate) fn bond_nominator(who: AccountId, val: Balance, target: Vec, +) { + // In a real scenario, `who` is a keyless account managed by another pallet which provides for + // it. + System::inc_providers(&who); + + // Bond who virtually. + assert_ok!(::virtual_bond(&who, val, &payee)); + assert_ok!(Staking::nominate(RuntimeOrigin::signed(who), target)); +} + /// Progress to the given block, triggering session and era changes as we progress. /// /// This will finalize the previous block, initialize up to the given block, essentially simulating @@ -709,12 +734,11 @@ pub(crate) fn on_offence_in_era( >], slash_fraction: &[Perbill], era: EraIndex, - disable_strategy: DisableStrategy, ) { let bonded_eras = crate::BondedEras::::get(); for &(bonded_era, start_session) in bonded_eras.iter() { if bonded_era == era { - let _ = Staking::on_offence(offenders, slash_fraction, start_session, disable_strategy); + let _ = Staking::on_offence(offenders, slash_fraction, start_session); return } else if bonded_era > era { break @@ -726,7 +750,6 @@ pub(crate) fn on_offence_in_era( offenders, slash_fraction, Staking::eras_start_session_index(era).unwrap(), - disable_strategy, ); } else { panic!("cannot slash in era {}", era); @@ -741,7 +764,7 @@ pub(crate) fn on_offence_now( slash_fraction: &[Perbill], ) { let now = Staking::active_era().unwrap().index; - on_offence_in_era(offenders, slash_fraction, now, DisableStrategy::WhenSlashed) + on_offence_in_era(offenders, slash_fraction, now) } pub(crate) fn add_slash(who: &AccountId) { diff --git a/substrate/frame/staking/src/pallet/impls.rs b/substrate/frame/staking/src/pallet/impls.rs index 2f43e4847e451a7cc10413bb58e3d98d82577e9f..52361c6ccdc13653e155df8e1535ec6a16cbe65a 100644 --- a/substrate/frame/staking/src/pallet/impls.rs +++ b/substrate/frame/staking/src/pallet/impls.rs @@ -28,19 +28,22 @@ use frame_support::{ pallet_prelude::*, traits::{ Currency, Defensive, DefensiveSaturating, EstimateNextNewSession, Get, Imbalance, - InspectLockableCurrency, Len, OnUnbalanced, TryCollect, UnixTime, + InspectLockableCurrency, Len, LockableCurrency, OnUnbalanced, TryCollect, UnixTime, }, weights::Weight, }; use frame_system::{pallet_prelude::BlockNumberFor, RawOrigin}; use pallet_session::historical; use sp_runtime::{ - traits::{Bounded, Convert, One, SaturatedConversion, Saturating, StaticLookup, Zero}, - Perbill, Percent, + traits::{ + Bounded, CheckedAdd, CheckedSub, Convert, One, SaturatedConversion, Saturating, + StaticLookup, Zero, + }, + ArithmeticError, Perbill, Percent, }; use sp_staking::{ currency_to_vote::CurrencyToVote, - offence::{DisableStrategy, OffenceDetails, OnOffenceHandler}, + offence::{OffenceDetails, OnOffenceHandler}, EraIndex, OnStakingUpdate, Page, SessionIndex, Stake, StakingAccount::{self, Controller, Stash}, StakingInterface, @@ -84,10 +87,12 @@ impl Pallet { StakingLedger::::paired_account(Stash(stash.clone())) } - /// Inspects and returns the corruption state of a ledger and bond, if any. + /// Inspects and returns the corruption state of a ledger and direct bond, if any. /// /// Note: all operations in this method access directly the `Bonded` and `Ledger` storage maps /// instead of using the [`StakingLedger`] API since the bond and/or ledger may be corrupted. + /// It is also meant to check state for direct bonds and may not work as expected for virtual + /// bonds. pub(crate) fn inspect_bond_state( stash: &T::AccountId, ) -> Result> { @@ -149,6 +154,39 @@ impl Pallet { Self::slashable_balance_of_vote_weight(who, issuance) } + pub(super) fn do_bond_extra(stash: &T::AccountId, additional: BalanceOf) -> DispatchResult { + let mut ledger = Self::ledger(StakingAccount::Stash(stash.clone()))?; + + // for virtual stakers, we don't need to check the balance. Since they are only accessed + // via low level apis, we can assume that the caller has done the due diligence. + let extra = if Self::is_virtual_staker(stash) { + additional + } else { + // additional amount or actual balance of stash whichever is lower. + additional.min( + T::Currency::free_balance(stash) + .checked_sub(&ledger.total) + .ok_or(ArithmeticError::Overflow)?, + ) + }; + + ledger.total = ledger.total.checked_add(&extra).ok_or(ArithmeticError::Overflow)?; + ledger.active = ledger.active.checked_add(&extra).ok_or(ArithmeticError::Overflow)?; + // last check: the new active amount of ledger must be more than ED. + ensure!(ledger.active >= T::Currency::minimum_balance(), Error::::InsufficientBond); + + // NOTE: ledger must be updated prior to calling `Self::weight_of`. + ledger.update()?; + // update this staker in the sorted list, if they exist in it. + if T::VoterList::contains(stash) { + let _ = T::VoterList::on_update(&stash, Self::weight_of(stash)).defensive(); + } + + Self::deposit_event(Event::::Bonded { stash: stash.clone(), amount: extra }); + + Ok(()) + } + pub(super) fn do_withdraw_unbonded( controller: &T::AccountId, num_slashing_spans: u32, @@ -160,8 +198,9 @@ impl Pallet { } let new_total = ledger.total; + let ed = T::Currency::minimum_balance(); let used_weight = - if ledger.unlocking.is_empty() && ledger.active < T::Currency::minimum_balance() { + if ledger.unlocking.is_empty() && (ledger.active < ed || ledger.active.is_zero()) { // This account must have called `unbond()` with some value that caused the active // portion to fall below existential deposit + will have no more unlocking chunks // left. We can now safely remove all staking-related information. @@ -469,10 +508,8 @@ impl Pallet { } // disable all offending validators that have been disabled for the whole era - for (index, disabled) in >::get() { - if disabled { - T::SessionInterface::disable_validator(index); - } + for index in >::get() { + T::SessionInterface::disable_validator(index); } } @@ -562,8 +599,8 @@ impl Pallet { >::insert(&active_era.index, validator_payout); T::RewardRemainder::on_unbalanced(T::Currency::issue(remainder)); - // Clear offending validators. - >::kill(); + // Clear disabled validators. + >::kill(); } } @@ -832,14 +869,6 @@ impl Pallet { Self::deposit_event(Event::::ForceEra { mode }); } - /// Ensures that at the end of the current session there will be a new era. - pub(crate) fn ensure_new_era() { - match ForceEra::::get() { - Forcing::ForceAlways | Forcing::ForceNew => (), - _ => Self::set_force_era(Forcing::ForceNew), - } - } - #[cfg(feature = "runtime-benchmarks")] pub fn add_era_stakers( current_era: EraIndex, @@ -1132,6 +1161,11 @@ impl Pallet { ) -> Exposure> { EraInfo::::get_full_exposure(era, account) } + + /// Whether `who` is a virtual staker whose funds are managed by another pallet. + pub(crate) fn is_virtual_staker(who: &T::AccountId) -> bool { + VirtualStakers::::contains_key(who) + } } impl Pallet { @@ -1152,6 +1186,10 @@ impl Pallet { pub fn api_eras_stakers_page_count(era: EraIndex, account: T::AccountId) -> Page { EraInfo::::get_page_count(era, &account) } + + pub fn api_pending_rewards(era: EraIndex, account: T::AccountId) -> bool { + EraInfo::::pending_rewards(era, &account) + } } impl ElectionDataProvider for Pallet { @@ -1406,7 +1444,6 @@ where >], slash_fraction: &[Perbill], slash_session: SessionIndex, - disable_strategy: DisableStrategy, ) -> Weight { let reward_proportion = SlashRewardFraction::::get(); let mut consumed_weight = Weight::from_parts(0, 0); @@ -1471,7 +1508,6 @@ where window_start, now: active_era, reward_proportion, - disable_strategy, }); Self::deposit_event(Event::::SlashReported { @@ -1748,6 +1784,23 @@ impl StakingInterface for Pallet { .map(|_| ()) } + fn update_payee(stash: &Self::AccountId, reward_acc: &Self::AccountId) -> DispatchResult { + // Since virtual stakers are not allowed to compound their rewards as this pallet does not + // manage their locks, we do not allow reward account to be set same as stash. For + // external pallets that manage the virtual bond, they can claim rewards and re-bond them. + ensure!( + !Self::is_virtual_staker(stash) || stash != reward_acc, + Error::::RewardDestinationRestricted + ); + + // since controller is deprecated and this function is never used for old ledgers with + // distinct controllers, we can safely assume that stash is the controller. + Self::set_payee( + RawOrigin::Signed(stash.clone()).into(), + RewardDestination::Account(reward_acc.clone()), + ) + } + fn chill(who: &Self::AccountId) -> DispatchResult { // defensive-only: any account bonded via this interface has the stash set as the // controller, but we have to be sure. Same comment anywhere else that we read this. @@ -1832,6 +1885,10 @@ impl StakingInterface for Pallet { } } + fn slash_reward_fraction() -> Perbill { + SlashRewardFraction::::get() + } + sp_staking::runtime_benchmarks_enabled! { fn nominations(who: &Self::AccountId) -> Option> { Nominators::::get(who).map(|n| n.targets.into_inner()) @@ -1860,6 +1917,55 @@ impl StakingInterface for Pallet { } } +impl sp_staking::StakingUnchecked for Pallet { + fn migrate_to_virtual_staker(who: &Self::AccountId) { + T::Currency::remove_lock(crate::STAKING_ID, who); + VirtualStakers::::insert(who, ()); + } + + /// Virtually bonds `keyless_who` to `payee` with `value`. + /// + /// The payee must not be the same as the `keyless_who`. + fn virtual_bond( + keyless_who: &Self::AccountId, + value: Self::Balance, + payee: &Self::AccountId, + ) -> DispatchResult { + if StakingLedger::::is_bonded(StakingAccount::Stash(keyless_who.clone())) { + return Err(Error::::AlreadyBonded.into()) + } + + // check if payee not same as who. + ensure!(keyless_who != payee, Error::::RewardDestinationRestricted); + + // mark this pallet as consumer of `who`. + frame_system::Pallet::::inc_consumers(&keyless_who).map_err(|_| Error::::BadState)?; + + // mark who as a virtual staker. + VirtualStakers::::insert(keyless_who, ()); + + Self::deposit_event(Event::::Bonded { stash: keyless_who.clone(), amount: value }); + let ledger = StakingLedger::::new(keyless_who.clone(), value); + + ledger.bond(RewardDestination::Account(payee.clone()))?; + + Ok(()) + } + + #[cfg(feature = "runtime-benchmarks")] + fn migrate_to_direct_staker(who: &Self::AccountId) { + assert!(VirtualStakers::::contains_key(who)); + let ledger = StakingLedger::::get(Stash(who.clone())).unwrap(); + T::Currency::set_lock( + crate::STAKING_ID, + who, + ledger.total, + frame_support::traits::WithdrawReasons::all(), + ); + VirtualStakers::::remove(who); + } +} + #[cfg(any(test, feature = "try-runtime"))] impl Pallet { pub(crate) fn do_try_state(_: BlockNumberFor) -> Result<(), TryRuntimeError> { @@ -1875,7 +1981,8 @@ impl Pallet { Self::check_nominators()?; Self::check_exposures()?; Self::check_paged_exposures()?; - Self::check_count() + Self::check_count()?; + Self::ensure_disabled_validators_sorted() } /// Invariants: @@ -1980,16 +2087,44 @@ impl Pallet { /// Invariants: /// * Stake consistency: ledger.total == ledger.active + sum(ledger.unlocking). /// * The ledger's controller and stash matches the associated `Bonded` tuple. - /// * Staking locked funds for every bonded stash should be the same as its ledger's total. + /// * Staking locked funds for every bonded stash (non virtual stakers) should be the same as + /// its ledger's total. + /// * For virtual stakers, locked funds should be zero and payee should be non-stash account. /// * Staking ledger and bond are not corrupted. fn check_ledgers() -> Result<(), TryRuntimeError> { Bonded::::iter() .map(|(stash, ctrl)| { // ensure locks consistency. - ensure!( - Self::inspect_bond_state(&stash) == Ok(LedgerIntegrityState::Ok), - "bond, ledger and/or staking lock inconsistent for a bonded stash." - ); + if VirtualStakers::::contains_key(stash.clone()) { + ensure!( + T::Currency::balance_locked(crate::STAKING_ID, &stash) == Zero::zero(), + "virtual stakers should not have any locked balance" + ); + ensure!( + >::get(stash.clone()).unwrap() == stash.clone(), + "stash and controller should be same" + ); + ensure!( + Ledger::::get(stash.clone()).unwrap().stash == stash, + "ledger corrupted for virtual staker" + ); + let reward_destination = >::get(stash.clone()).unwrap(); + if let RewardDestination::Account(payee) = reward_destination { + ensure!( + payee != stash.clone(), + "reward destination should not be same as stash for virtual staker" + ); + } else { + return Err(DispatchError::Other( + "reward destination must be of account variant for virtual staker", + )); + } + } else { + ensure!( + Self::inspect_bond_state(&stash) == Ok(LedgerIntegrityState::Ok), + "bond, ledger and/or staking lock inconsistent for a bonded stash." + ); + } // ensure ledger consistency. Self::ensure_ledger_consistent(ctrl) @@ -2161,4 +2296,12 @@ impl Pallet { Ok(()) } + + fn ensure_disabled_validators_sorted() -> Result<(), TryRuntimeError> { + ensure!( + DisabledValidators::::get().windows(2).all(|pair| pair[0] <= pair[1]), + "DisabledValidators is not sorted" + ); + Ok(()) + } } diff --git a/substrate/frame/staking/src/pallet/mod.rs b/substrate/frame/staking/src/pallet/mod.rs index 2e5b3aa7b873e2c123b3176a4e80d6e0cd1b6177..f82266c03903ceb09703324ba8e79a75d8a0fa16 100644 --- a/substrate/frame/staking/src/pallet/mod.rs +++ b/substrate/frame/staking/src/pallet/mod.rs @@ -32,7 +32,7 @@ use frame_support::{ }; use frame_system::{ensure_root, ensure_signed, pallet_prelude::*}; use sp_runtime::{ - traits::{CheckedSub, SaturatedConversion, StaticLookup, Zero}, + traits::{SaturatedConversion, StaticLookup, Zero}, ArithmeticError, Perbill, Percent, }; @@ -47,10 +47,11 @@ mod impls; pub use impls::*; use crate::{ - slashing, weights::WeightInfo, AccountIdLookupOf, ActiveEraInfo, BalanceOf, EraPayout, - EraRewardPoints, Exposure, ExposurePage, Forcing, LedgerIntegrityState, MaxNominationsOf, - NegativeImbalanceOf, Nominations, NominationsQuota, PositiveImbalanceOf, RewardDestination, - SessionInterface, StakingLedger, UnappliedSlash, UnlockChunk, ValidatorPrefs, + slashing, weights::WeightInfo, AccountIdLookupOf, ActiveEraInfo, BalanceOf, DisablingStrategy, + EraPayout, EraRewardPoints, Exposure, ExposurePage, Forcing, LedgerIntegrityState, + MaxNominationsOf, NegativeImbalanceOf, Nominations, NominationsQuota, PositiveImbalanceOf, + RewardDestination, SessionInterface, StakingLedger, UnappliedSlash, UnlockChunk, + ValidatorPrefs, }; // The speculative number of spans are used as an input of the weight annotation of @@ -67,7 +68,7 @@ pub mod pallet { use super::*; /// The in-code storage version. - const STORAGE_VERSION: StorageVersion = StorageVersion::new(14); + const STORAGE_VERSION: StorageVersion = StorageVersion::new(15); #[pallet::pallet] #[pallet::storage_version(STORAGE_VERSION)] @@ -217,10 +218,6 @@ pub mod pallet { #[pallet::constant] type MaxExposurePageSize: Get; - /// The fraction of the validator set that is safe to be offending. - /// After the threshold is reached a new era will be forced. - type OffendingValidatorsThreshold: Get; - /// Something that provides a best-effort sorted list of voters aka electing nominators, /// used for NPoS election. /// @@ -278,6 +275,9 @@ pub mod pallet { /// WARNING: this only reports slashing and withdraw events for the time being. type EventListeners: sp_staking::OnStakingUpdate>; + // `DisablingStragegy` controls how validators are disabled + type DisablingStrategy: DisablingStrategy; + /// Some parameters of the benchmarking. type BenchmarkingConfig: BenchmarkingConfig; @@ -379,6 +379,15 @@ pub mod pallet { pub type Nominators = CountedStorageMap<_, Twox64Concat, T::AccountId, Nominations>; + /// Stakers whose funds are managed by other pallets. + /// + /// This pallet does not apply any locks on them, therefore they are only virtually bonded. They + /// are expected to be keyless accounts and hence should not be allowed to mutate their ledger + /// directly via this pallet. Instead, these accounts are managed by other pallets and accessed + /// via low level apis. We keep track of them to do minimal integrity checks. + #[pallet::storage] + pub type VirtualStakers = CountedStorageMap<_, Twox64Concat, T::AccountId, ()>; + /// The maximum nominator count before we stop allowing new validators to join. /// /// When this value is not set, no limits are enforced. @@ -645,19 +654,16 @@ pub mod pallet { #[pallet::getter(fn current_planned_session)] pub type CurrentPlannedSession = StorageValue<_, SessionIndex, ValueQuery>; - /// Indices of validators that have offended in the active era and whether they are currently - /// disabled. + /// Indices of validators that have offended in the active era. The offenders are disabled for a + /// whole era. For this reason they are kept here - only staking pallet knows about eras. The + /// implementor of [`DisablingStrategy`] defines if a validator should be disabled which + /// implicitly means that the implementor also controls the max number of disabled validators. /// - /// This value should be a superset of disabled validators since not all offences lead to the - /// validator being disabled (if there was no slash). This is needed to track the percentage of - /// validators that have offended in the current era, ensuring a new era is forced if - /// `OffendingValidatorsThreshold` is reached. The vec is always kept sorted so that we can find - /// whether a given validator has previously offended using binary search. It gets cleared when - /// the era ends. + /// The vec is always kept sorted so that we can find whether a given validator has previously + /// offended using binary search. #[pallet::storage] #[pallet::unbounded] - #[pallet::getter(fn offending_validators)] - pub type OffendingValidators = StorageValue<_, Vec<(u32, bool)>, ValueQuery>; + pub type DisabledValidators = StorageValue<_, Vec, ValueQuery>; /// The threshold for when users can start calling `chill_other` for other validators / /// nominators. The threshold is compared to the actual number of validators / nominators @@ -858,6 +864,12 @@ pub mod pallet { ControllerDeprecated, /// Cannot reset a ledger. CannotRestoreLedger, + /// Provided reward destination is not allowed. + RewardDestinationRestricted, + /// Not enough funds available to withdraw. + NotEnoughFunds, + /// Operation not allowed for virtual stakers. + VirtualStakerNotAllowed, } #[pallet::hooks] @@ -926,7 +938,8 @@ pub mod pallet { /// - Three extra DB entries. /// /// NOTE: Two of the storage writes (`Self::bonded`, `Self::payee`) are _never_ cleaned - /// unless the `origin` falls below _existential deposit_ and gets removed as dust. + /// unless the `origin` falls below _existential deposit_ (or equal to 0) and gets removed + /// as dust. #[pallet::call_index(0)] #[pallet::weight(T::WeightInfo::bond())] pub fn bond( @@ -985,29 +998,7 @@ pub mod pallet { #[pallet::compact] max_additional: BalanceOf, ) -> DispatchResult { let stash = ensure_signed(origin)?; - let mut ledger = Self::ledger(StakingAccount::Stash(stash.clone()))?; - - let stash_balance = T::Currency::free_balance(&stash); - if let Some(extra) = stash_balance.checked_sub(&ledger.total) { - let extra = extra.min(max_additional); - ledger.total += extra; - ledger.active += extra; - // Last check: the new active amount of ledger must be more than ED. - ensure!( - ledger.active >= T::Currency::minimum_balance(), - Error::::InsufficientBond - ); - - // NOTE: ledger must be updated prior to calling `Self::weight_of`. - ledger.update()?; - // update this staker in the sorted list, if they exist in it. - if T::VoterList::contains(&stash) { - let _ = T::VoterList::on_update(&stash, Self::weight_of(&stash)).defensive(); - } - - Self::deposit_event(Event::::Bonded { stash, amount: extra }); - } - Ok(()) + Self::do_bond_extra(&stash, max_additional) } /// Schedule a portion of the stash to be unlocked ready for transfer out after the bond @@ -1625,6 +1616,7 @@ pub mod pallet { /// /// 1. the `total_balance` of the stash is below existential deposit. /// 2. or, the `ledger.total` of the stash is below existential deposit. + /// 3. or, existential deposit is zero and either `total_balance` or `ledger.total` is zero. /// /// The former can happen in cases like a slash; the latter when a fully unbonded account /// is still receiving staking rewards in `RewardDestination::Staked`. @@ -1646,9 +1638,17 @@ pub mod pallet { ) -> DispatchResultWithPostInfo { let _ = ensure_signed(origin)?; + // virtual stakers should not be allowed to be reaped. + ensure!(!Self::is_virtual_staker(&stash), Error::::VirtualStakerNotAllowed); + let ed = T::Currency::minimum_balance(); - let reapable = T::Currency::total_balance(&stash) < ed || - Self::ledger(Stash(stash.clone())).map(|l| l.total).unwrap_or_default() < ed; + let origin_balance = T::Currency::total_balance(&stash); + let ledger_total = + Self::ledger(Stash(stash.clone())).map(|l| l.total).unwrap_or_default(); + let reapable = origin_balance < ed || + origin_balance.is_zero() || + ledger_total < ed || + ledger_total.is_zero(); ensure!(reapable, Error::::FundedTarget); // Remove all staking-related information and lock. @@ -2006,6 +2006,9 @@ pub mod pallet { ) -> DispatchResult { T::AdminOrigin::ensure_origin(origin)?; + // cannot restore ledger for virtual stakers. + ensure!(!Self::is_virtual_staker(&stash), Error::::VirtualStakerNotAllowed); + let current_lock = T::Currency::balance_locked(crate::STAKING_ID, &stash); let stash_balance = T::Currency::free_balance(&stash); diff --git a/substrate/frame/staking/src/slashing.rs b/substrate/frame/staking/src/slashing.rs index 709fd1441ec3af313220486aa8000c959e30fd07..f831f625957d4c495fce3b239e68faed737cb3ab 100644 --- a/substrate/frame/staking/src/slashing.rs +++ b/substrate/frame/staking/src/slashing.rs @@ -50,21 +50,21 @@ //! Based on research at use crate::{ - BalanceOf, Config, Error, Exposure, NegativeImbalanceOf, NominatorSlashInEra, - OffendingValidators, Pallet, Perbill, SessionInterface, SpanSlash, UnappliedSlash, + BalanceOf, Config, DisabledValidators, DisablingStrategy, Error, Exposure, NegativeImbalanceOf, + NominatorSlashInEra, Pallet, Perbill, SessionInterface, SpanSlash, UnappliedSlash, ValidatorSlashInEra, }; use codec::{Decode, Encode, MaxEncodedLen}; use frame_support::{ ensure, - traits::{Currency, Defensive, DefensiveSaturating, Get, Imbalance, OnUnbalanced}, + traits::{Currency, Defensive, DefensiveSaturating, Imbalance, OnUnbalanced}, }; use scale_info::TypeInfo; use sp_runtime::{ traits::{Saturating, Zero}, DispatchResult, RuntimeDebug, }; -use sp_staking::{offence::DisableStrategy, EraIndex}; +use sp_staking::EraIndex; use sp_std::vec::Vec; /// The proportion of the slashing reward to be paid out on the first slashing detection. @@ -220,8 +220,6 @@ pub(crate) struct SlashParams<'a, T: 'a + Config> { /// The maximum percentage of a slash that ever gets paid out. /// This is f_inf in the paper. pub(crate) reward_proportion: Perbill, - /// When to disable offenders. - pub(crate) disable_strategy: DisableStrategy, } /// Computes a slash of a validator and nominators. It returns an unapplied @@ -280,18 +278,13 @@ pub(crate) fn compute_slash( let target_span = spans.compare_and_update_span_slash(params.slash_era, own_slash); if target_span == Some(spans.span_index()) { - // misbehavior occurred within the current slashing span - take appropriate - // actions. - - // chill the validator - it misbehaved in the current span and should - // not continue in the next election. also end the slashing span. + // misbehavior occurred within the current slashing span - end current span. + // Check for details. spans.end_span(params.now); - >::chill_stash(params.stash); } } - let disable_when_slashed = params.disable_strategy != DisableStrategy::Never; - add_offending_validator::(params.stash, disable_when_slashed); + add_offending_validator::(¶ms); let mut nominators_slashed = Vec::new(); reward_payout += slash_nominators::(params.clone(), prior_slash_p, &mut nominators_slashed); @@ -320,54 +313,31 @@ fn kick_out_if_recent(params: SlashParams) { ); if spans.era_span(params.slash_era).map(|s| s.index) == Some(spans.span_index()) { + // Check https://github.com/paritytech/polkadot-sdk/issues/2650 for details spans.end_span(params.now); - >::chill_stash(params.stash); } - let disable_without_slash = params.disable_strategy == DisableStrategy::Always; - add_offending_validator::(params.stash, disable_without_slash); + add_offending_validator::(¶ms); } -/// Add the given validator to the offenders list and optionally disable it. -/// If after adding the validator `OffendingValidatorsThreshold` is reached -/// a new era will be forced. -fn add_offending_validator(stash: &T::AccountId, disable: bool) { - OffendingValidators::::mutate(|offending| { - let validators = T::SessionInterface::validators(); - let validator_index = match validators.iter().position(|i| i == stash) { - Some(index) => index, - None => return, - }; - - let validator_index_u32 = validator_index as u32; - - match offending.binary_search_by_key(&validator_index_u32, |(index, _)| *index) { - // this is a new offending validator - Err(index) => { - offending.insert(index, (validator_index_u32, disable)); - - let offending_threshold = - T::OffendingValidatorsThreshold::get() * validators.len() as u32; - - if offending.len() >= offending_threshold as usize { - // force a new era, to select a new validator set - >::ensure_new_era() - } - - if disable { - T::SessionInterface::disable_validator(validator_index_u32); - } - }, - Ok(index) => { - if disable && !offending[index].1 { - // the validator had previously offended without being disabled, - // let's make sure we disable it now - offending[index].1 = true; - T::SessionInterface::disable_validator(validator_index_u32); - } - }, +/// Inform the [`DisablingStrategy`] implementation about the new offender and disable the list of +/// validators provided by [`make_disabling_decision`]. +fn add_offending_validator(params: &SlashParams) { + DisabledValidators::::mutate(|disabled| { + if let Some(offender) = + T::DisablingStrategy::decision(params.stash, params.slash_era, &disabled) + { + // Add the validator to `DisabledValidators` and disable it. Do nothing if it is + // already disabled. + if let Err(index) = disabled.binary_search_by_key(&offender, |index| *index) { + disabled.insert(index, offender); + T::SessionInterface::disable_validator(offender); + } } }); + + // `DisabledValidators` should be kept sorted + debug_assert!(DisabledValidators::::get().windows(2).all(|pair| pair[0] < pair[1])); } /// Slash nominators. Accepts general parameters and the prior slash percentage of the validator. @@ -609,8 +579,13 @@ pub fn do_slash( }; let value = ledger.slash(value, T::Currency::minimum_balance(), slash_era); + if value.is_zero() { + // nothing to do + return + } - if !value.is_zero() { + // Skip slashing for virtual stakers. The pallets managing them should handle the slashing. + if !Pallet::::is_virtual_staker(stash) { let (imbalance, missing) = T::Currency::slash(stash, value); slashed_imbalance.subsume(imbalance); @@ -618,17 +593,14 @@ pub fn do_slash( // deduct overslash from the reward payout *reward_payout = reward_payout.saturating_sub(missing); } + } - let _ = ledger - .update() - .defensive_proof("ledger fetched from storage so it exists in storage; qed."); + let _ = ledger + .update() + .defensive_proof("ledger fetched from storage so it exists in storage; qed."); - // trigger the event - >::deposit_event(super::Event::::Slashed { - staker: stash.clone(), - amount: value, - }); - } + // trigger the event + >::deposit_event(super::Event::::Slashed { staker: stash.clone(), amount: value }); } /// Apply a previously-unapplied slash. diff --git a/substrate/frame/staking/src/testing_utils.rs b/substrate/frame/staking/src/testing_utils.rs index 28e08230d701d6cc477c840311b274d0535a88bf..d4938ea43ebe2800b3894a21e17f93e45d591ff5 100644 --- a/substrate/frame/staking/src/testing_utils.rs +++ b/substrate/frame/staking/src/testing_utils.rs @@ -77,7 +77,8 @@ pub fn create_stash_controller( destination: RewardDestination, ) -> Result<(T::AccountId, T::AccountId), &'static str> { let staker = create_funded_user::("stash", n, balance_factor); - let amount = T::Currency::minimum_balance() * (balance_factor / 10).max(1).into(); + let amount = + T::Currency::minimum_balance().max(1u64.into()) * (balance_factor / 10).max(1).into(); Staking::::bond(RawOrigin::Signed(staker.clone()).into(), amount, destination)?; Ok((staker.clone(), staker)) } diff --git a/substrate/frame/staking/src/tests.rs b/substrate/frame/staking/src/tests.rs index a5c9abe2f176233f1f66e9872fde0a6bde99bbcb..76afa3333cb465b9f7f9e119871730f31fcd6720 100644 --- a/substrate/frame/staking/src/tests.rs +++ b/substrate/frame/staking/src/tests.rs @@ -27,7 +27,7 @@ use frame_support::{ assert_noop, assert_ok, assert_storage_noop, dispatch::{extract_actual_weight, GetDispatchInfo, WithPostDispatchInfo}, pallet_prelude::*, - traits::{Currency, Get, ReservableCurrency}, + traits::{Currency, Get, InspectLockableCurrency, ReservableCurrency}, }; use mock::*; @@ -38,7 +38,7 @@ use sp_runtime::{ Perbill, Percent, Perquintill, Rounding, TokenError, }; use sp_staking::{ - offence::{DisableStrategy, OffenceDetails, OnOffenceHandler}, + offence::{OffenceDetails, OnOffenceHandler}, SessionIndex, }; use sp_std::prelude::*; @@ -623,12 +623,8 @@ fn nominating_and_rewards_should_work() { )); assert_ok!(Staking::nominate(RuntimeOrigin::signed(1), vec![11, 21, 31])); - assert_ok!(Staking::bond( - RuntimeOrigin::signed(3), - 1000, - RewardDestination::Account(3) - )); - assert_ok!(Staking::nominate(RuntimeOrigin::signed(3), vec![11, 21, 41])); + // the second nominator is virtual. + bond_virtual_nominator(3, 333, 1000, vec![11, 21, 41]); // the total reward for era 0 let total_payout_0 = current_total_payout_for_duration(reward_time_per_era()); @@ -694,10 +690,12 @@ fn nominating_and_rewards_should_work() { ); // Nominator 3: has [400/1800 ~ 2/9 from 10] + [600/2200 ~ 3/11 from 21]'s reward. ==> // 2/9 + 3/11 + assert_eq!(Balances::total_balance(&3), initial_balance); + // 333 is the reward destination for 3. assert_eq_error_rate!( - Balances::total_balance(&3), - initial_balance + (2 * payout_for_11 / 9 + 3 * payout_for_21 / 11), - 2, + Balances::total_balance(&333), + 2 * payout_for_11 / 9 + 3 * payout_for_21 / 11, + 2 ); // Validator 11: got 800 / 1800 external stake => 8/18 =? 4/9 => Validator's share = 5/9 @@ -718,56 +716,65 @@ fn nominating_and_rewards_should_work() { #[test] fn nominators_also_get_slashed_pro_rata() { - ExtBuilder::default().build_and_execute(|| { - mock::start_active_era(1); - let slash_percent = Perbill::from_percent(5); - let initial_exposure = Staking::eras_stakers(active_era(), &11); - // 101 is a nominator for 11 - assert_eq!(initial_exposure.others.first().unwrap().who, 101); - - // staked values; - let nominator_stake = Staking::ledger(101.into()).unwrap().active; - let nominator_balance = balances(&101).0; - let validator_stake = Staking::ledger(11.into()).unwrap().active; - let validator_balance = balances(&11).0; - let exposed_stake = initial_exposure.total; - let exposed_validator = initial_exposure.own; - let exposed_nominator = initial_exposure.others.first().unwrap().value; - - // 11 goes offline - on_offence_now( - &[OffenceDetails { offender: (11, initial_exposure.clone()), reporters: vec![] }], - &[slash_percent], - ); + ExtBuilder::default() + .validator_count(4) + .set_status(41, StakerStatus::Validator) + .build_and_execute(|| { + mock::start_active_era(1); + let slash_percent = Perbill::from_percent(5); + let initial_exposure = Staking::eras_stakers(active_era(), &11); + // 101 is a nominator for 11 + assert_eq!(initial_exposure.others.first().unwrap().who, 101); + + // staked values; + let nominator_stake = Staking::ledger(101.into()).unwrap().active; + let nominator_balance = balances(&101).0; + let validator_stake = Staking::ledger(11.into()).unwrap().active; + let validator_balance = balances(&11).0; + let exposed_stake = initial_exposure.total; + let exposed_validator = initial_exposure.own; + let exposed_nominator = initial_exposure.others.first().unwrap().value; + + // 11 goes offline + on_offence_now( + &[OffenceDetails { offender: (11, initial_exposure.clone()), reporters: vec![] }], + &[slash_percent], + ); - // both stakes must have been decreased. - assert!(Staking::ledger(101.into()).unwrap().active < nominator_stake); - assert!(Staking::ledger(11.into()).unwrap().active < validator_stake); + // both stakes must have been decreased. + assert!(Staking::ledger(101.into()).unwrap().active < nominator_stake); + assert!(Staking::ledger(11.into()).unwrap().active < validator_stake); - let slash_amount = slash_percent * exposed_stake; - let validator_share = - Perbill::from_rational(exposed_validator, exposed_stake) * slash_amount; - let nominator_share = - Perbill::from_rational(exposed_nominator, exposed_stake) * slash_amount; + let slash_amount = slash_percent * exposed_stake; + let validator_share = + Perbill::from_rational(exposed_validator, exposed_stake) * slash_amount; + let nominator_share = + Perbill::from_rational(exposed_nominator, exposed_stake) * slash_amount; - // both slash amounts need to be positive for the test to make sense. - assert!(validator_share > 0); - assert!(nominator_share > 0); + // both slash amounts need to be positive for the test to make sense. + assert!(validator_share > 0); + assert!(nominator_share > 0); - // both stakes must have been decreased pro-rata. - assert_eq!(Staking::ledger(101.into()).unwrap().active, nominator_stake - nominator_share); - assert_eq!(Staking::ledger(11.into()).unwrap().active, validator_stake - validator_share); - assert_eq!( - balances(&101).0, // free balance - nominator_balance - nominator_share, - ); - assert_eq!( - balances(&11).0, // free balance - validator_balance - validator_share, - ); - // Because slashing happened. - assert!(is_disabled(11)); - }); + // both stakes must have been decreased pro-rata. + assert_eq!( + Staking::ledger(101.into()).unwrap().active, + nominator_stake - nominator_share + ); + assert_eq!( + Staking::ledger(11.into()).unwrap().active, + validator_stake - validator_share + ); + assert_eq!( + balances(&101).0, // free balance + nominator_balance - nominator_share, + ); + assert_eq!( + balances(&11).0, // free balance + validator_balance - validator_share, + ); + // Because slashing happened. + assert!(is_disabled(11)); + }); } #[test] @@ -1893,7 +1900,7 @@ fn reap_stash_works() { .balance_factor(10) .build_and_execute(|| { // given - assert_eq!(Balances::free_balance(11), 10 * 1000); + assert_eq!(Balances::balance_locked(STAKING_ID, &11), 10 * 1000); assert_eq!(Staking::bonded(&11), Some(11)); assert!(>::contains_key(&11)); @@ -1919,6 +1926,46 @@ fn reap_stash_works() { assert!(!>::contains_key(&11)); assert!(!>::contains_key(&11)); assert!(!>::contains_key(&11)); + // lock is removed. + assert_eq!(Balances::balance_locked(STAKING_ID, &11), 0); + }); +} + +#[test] +fn reap_stash_works_with_existential_deposit_zero() { + ExtBuilder::default() + .existential_deposit(0) + .balance_factor(10) + .build_and_execute(|| { + // given + assert_eq!(Balances::balance_locked(STAKING_ID, &11), 10 * 1000); + assert_eq!(Staking::bonded(&11), Some(11)); + + assert!(>::contains_key(&11)); + assert!(>::contains_key(&11)); + assert!(>::contains_key(&11)); + assert!(>::contains_key(&11)); + + // stash is not reapable + assert_noop!( + Staking::reap_stash(RuntimeOrigin::signed(20), 11, 0), + Error::::FundedTarget + ); + + // no easy way to cause an account to go below ED, we tweak their staking ledger + // instead. + Ledger::::insert(11, StakingLedger::::new(11, 0)); + + // reap-able + assert_ok!(Staking::reap_stash(RuntimeOrigin::signed(20), 11, 0)); + + // then + assert!(!>::contains_key(&11)); + assert!(!>::contains_key(&11)); + assert!(!>::contains_key(&11)); + assert!(!>::contains_key(&11)); + // lock is removed. + assert_eq!(Balances::balance_locked(STAKING_ID, &11), 0); }); } @@ -2401,7 +2448,7 @@ fn era_is_always_same_length() { } #[test] -fn offence_forces_new_era() { +fn offence_doesnt_force_new_era() { ExtBuilder::default().build_and_execute(|| { on_offence_now( &[OffenceDetails { @@ -2411,7 +2458,7 @@ fn offence_forces_new_era() { &[Perbill::from_percent(5)], ); - assert_eq!(Staking::force_era(), Forcing::ForceNew); + assert_eq!(Staking::force_era(), Forcing::NotForcing); }); } @@ -2435,26 +2482,32 @@ fn offence_ensures_new_era_without_clobbering() { #[test] fn offence_deselects_validator_even_when_slash_is_zero() { - ExtBuilder::default().build_and_execute(|| { - assert!(Session::validators().contains(&11)); - assert!(>::contains_key(11)); + ExtBuilder::default() + .validator_count(7) + .set_status(41, StakerStatus::Validator) + .set_status(51, StakerStatus::Validator) + .set_status(201, StakerStatus::Validator) + .set_status(202, StakerStatus::Validator) + .build_and_execute(|| { + assert!(Session::validators().contains(&11)); + assert!(>::contains_key(11)); - on_offence_now( - &[OffenceDetails { - offender: (11, Staking::eras_stakers(active_era(), &11)), - reporters: vec![], - }], - &[Perbill::from_percent(0)], - ); + on_offence_now( + &[OffenceDetails { + offender: (11, Staking::eras_stakers(active_era(), &11)), + reporters: vec![], + }], + &[Perbill::from_percent(0)], + ); - assert_eq!(Staking::force_era(), Forcing::ForceNew); - assert!(!>::contains_key(11)); + assert_eq!(Staking::force_era(), Forcing::NotForcing); + assert!(is_disabled(11)); - mock::start_active_era(1); + mock::start_active_era(1); - assert!(!Session::validators().contains(&11)); - assert!(!>::contains_key(11)); - }); + // The validator should be reenabled in the new era + assert!(!is_disabled(11)); + }); } #[test] @@ -2479,71 +2532,70 @@ fn slashing_performed_according_exposure() { } #[test] -fn slash_in_old_span_does_not_deselect() { - ExtBuilder::default().build_and_execute(|| { - mock::start_active_era(1); - - assert!(>::contains_key(11)); - assert!(Session::validators().contains(&11)); - - on_offence_now( - &[OffenceDetails { - offender: (11, Staking::eras_stakers(active_era(), &11)), - reporters: vec![], - }], - &[Perbill::from_percent(0)], - ); +fn validator_is_not_disabled_for_an_offence_in_previous_era() { + ExtBuilder::default() + .validator_count(4) + .set_status(41, StakerStatus::Validator) + .build_and_execute(|| { + mock::start_active_era(1); - assert_eq!(Staking::force_era(), Forcing::ForceNew); - assert!(!>::contains_key(11)); + assert!(>::contains_key(11)); + assert!(Session::validators().contains(&11)); - mock::start_active_era(2); + on_offence_now( + &[OffenceDetails { + offender: (11, Staking::eras_stakers(active_era(), &11)), + reporters: vec![], + }], + &[Perbill::from_percent(0)], + ); - Staking::validate(RuntimeOrigin::signed(11), Default::default()).unwrap(); - assert_eq!(Staking::force_era(), Forcing::NotForcing); - assert!(>::contains_key(11)); - assert!(!Session::validators().contains(&11)); + assert_eq!(Staking::force_era(), Forcing::NotForcing); + assert!(is_disabled(11)); - mock::start_active_era(3); + mock::start_active_era(2); - // this staker is in a new slashing span now, having re-registered after - // their prior slash. + // the validator is not disabled in the new era + Staking::validate(RuntimeOrigin::signed(11), Default::default()).unwrap(); + assert_eq!(Staking::force_era(), Forcing::NotForcing); + assert!(>::contains_key(11)); + assert!(Session::validators().contains(&11)); - on_offence_in_era( - &[OffenceDetails { - offender: (11, Staking::eras_stakers(active_era(), &11)), - reporters: vec![], - }], - &[Perbill::from_percent(0)], - 1, - DisableStrategy::WhenSlashed, - ); + mock::start_active_era(3); - // the validator doesn't get chilled again - assert!(Validators::::iter().any(|(stash, _)| stash == 11)); + // an offence committed in era 1 is reported in era 3 + on_offence_in_era( + &[OffenceDetails { + offender: (11, Staking::eras_stakers(active_era(), &11)), + reporters: vec![], + }], + &[Perbill::from_percent(0)], + 1, + ); - // but we are still forcing a new era - assert_eq!(Staking::force_era(), Forcing::ForceNew); + // the validator doesn't get disabled for an old offence + assert!(Validators::::iter().any(|(stash, _)| stash == 11)); + assert!(!is_disabled(11)); - on_offence_in_era( - &[OffenceDetails { - offender: (11, Staking::eras_stakers(active_era(), &11)), - reporters: vec![], - }], - // NOTE: A 100% slash here would clean up the account, causing de-registration. - &[Perbill::from_percent(95)], - 1, - DisableStrategy::WhenSlashed, - ); + // and we are not forcing a new era + assert_eq!(Staking::force_era(), Forcing::NotForcing); - // the validator doesn't get chilled again - assert!(Validators::::iter().any(|(stash, _)| stash == 11)); + on_offence_in_era( + &[OffenceDetails { + offender: (11, Staking::eras_stakers(active_era(), &11)), + reporters: vec![], + }], + // NOTE: A 100% slash here would clean up the account, causing de-registration. + &[Perbill::from_percent(95)], + 1, + ); - // but it's disabled - assert!(is_disabled(11)); - // and we are still forcing a new era - assert_eq!(Staking::force_era(), Forcing::ForceNew); - }); + // the validator doesn't get disabled again + assert!(Validators::::iter().any(|(stash, _)| stash == 11)); + assert!(!is_disabled(11)); + // and we are still not forcing a new era + assert_eq!(Staking::force_era(), Forcing::NotForcing); + }); } #[test] @@ -2671,7 +2723,7 @@ fn dont_slash_if_fraction_is_zero() { // The validator hasn't been slashed. The new era is not forced. assert_eq!(Balances::free_balance(11), 1000); - assert_eq!(Staking::force_era(), Forcing::ForceNew); + assert_eq!(Staking::force_era(), Forcing::NotForcing); }); } @@ -2692,7 +2744,7 @@ fn only_slash_for_max_in_era() { // The validator has been slashed and has been force-chilled. assert_eq!(Balances::free_balance(11), 500); - assert_eq!(Staking::force_era(), Forcing::ForceNew); + assert_eq!(Staking::force_era(), Forcing::NotForcing); on_offence_now( &[OffenceDetails { @@ -2833,7 +2885,6 @@ fn slashing_nominators_by_span_max() { }], &[Perbill::from_percent(10)], 2, - DisableStrategy::WhenSlashed, ); assert_eq!(Balances::free_balance(11), 900); @@ -2860,7 +2911,6 @@ fn slashing_nominators_by_span_max() { }], &[Perbill::from_percent(30)], 3, - DisableStrategy::WhenSlashed, ); // 11 was not further slashed, but 21 and 101 were. @@ -2882,7 +2932,6 @@ fn slashing_nominators_by_span_max() { }], &[Perbill::from_percent(20)], 2, - DisableStrategy::WhenSlashed, ); // 11 was further slashed, but 21 and 101 were not. @@ -2999,11 +3048,8 @@ fn deferred_slashes_are_deferred() { assert!(matches!( staking_events_since_last_call().as_slice(), &[ - Event::Chilled { stash: 11 }, - Event::ForceEra { mode: Forcing::ForceNew }, Event::SlashReported { validator: 11, slash_era: 1, .. }, Event::StakersElected, - Event::ForceEra { mode: Forcing::NotForcing }, .., Event::Slashed { staker: 11, amount: 100 }, Event::Slashed { staker: 101, amount: 12 } @@ -3029,7 +3075,6 @@ fn retroactive_deferred_slashes_two_eras_before() { &[OffenceDetails { offender: (11, exposure_11_at_era1), reporters: vec![] }], &[Perbill::from_percent(10)], 1, // should be deferred for two full eras, and applied at the beginning of era 4. - DisableStrategy::Never, ); mock::start_active_era(4); @@ -3037,8 +3082,6 @@ fn retroactive_deferred_slashes_two_eras_before() { assert!(matches!( staking_events_since_last_call().as_slice(), &[ - Event::Chilled { stash: 11 }, - Event::ForceEra { mode: Forcing::ForceNew }, Event::SlashReported { validator: 11, slash_era: 1, .. }, .., Event::Slashed { staker: 11, amount: 100 }, @@ -3067,7 +3110,6 @@ fn retroactive_deferred_slashes_one_before() { &[OffenceDetails { offender: (11, exposure_11_at_era1), reporters: vec![] }], &[Perbill::from_percent(10)], 2, // should be deferred for two full eras, and applied at the beginning of era 5. - DisableStrategy::Never, ); mock::start_active_era(4); @@ -3197,7 +3239,6 @@ fn remove_deferred() { &[OffenceDetails { offender: (11, exposure.clone()), reporters: vec![] }], &[Perbill::from_percent(15)], 1, - DisableStrategy::WhenSlashed, ); // fails if empty @@ -3312,192 +3353,198 @@ fn remove_multi_deferred() { #[test] fn slash_kicks_validators_not_nominators_and_disables_nominator_for_kicked_validator() { - ExtBuilder::default().build_and_execute(|| { - mock::start_active_era(1); - assert_eq_uvec!(Session::validators(), vec![11, 21]); + ExtBuilder::default() + .validator_count(7) + .set_status(41, StakerStatus::Validator) + .set_status(51, StakerStatus::Validator) + .set_status(201, StakerStatus::Validator) + .set_status(202, StakerStatus::Validator) + .build_and_execute(|| { + mock::start_active_era(1); + assert_eq_uvec!(Session::validators(), vec![11, 21, 31, 41, 51, 201, 202]); - // pre-slash balance - assert_eq!(Balances::free_balance(11), 1000); - assert_eq!(Balances::free_balance(101), 2000); + // pre-slash balance + assert_eq!(Balances::free_balance(11), 1000); + assert_eq!(Balances::free_balance(101), 2000); - // 100 has approval for 11 as of now - assert!(Staking::nominators(101).unwrap().targets.contains(&11)); + // 100 has approval for 11 as of now + assert!(Staking::nominators(101).unwrap().targets.contains(&11)); - // 11 and 21 both have the support of 100 - let exposure_11 = Staking::eras_stakers(active_era(), &11); - let exposure_21 = Staking::eras_stakers(active_era(), &21); + // 11 and 21 both have the support of 100 + let exposure_11 = Staking::eras_stakers(active_era(), &11); + let exposure_21 = Staking::eras_stakers(active_era(), &21); - assert_eq!(exposure_11.total, 1000 + 125); - assert_eq!(exposure_21.total, 1000 + 375); + assert_eq!(exposure_11.total, 1000 + 125); + assert_eq!(exposure_21.total, 1000 + 375); - on_offence_now( - &[OffenceDetails { offender: (11, exposure_11.clone()), reporters: vec![] }], - &[Perbill::from_percent(10)], - ); - - assert_eq!( - staking_events_since_last_call(), - vec![ - Event::StakersElected, - Event::EraPaid { era_index: 0, validator_payout: 11075, remainder: 33225 }, - Event::Chilled { stash: 11 }, - Event::ForceEra { mode: Forcing::ForceNew }, - Event::SlashReported { - validator: 11, - fraction: Perbill::from_percent(10), - slash_era: 1 - }, - Event::Slashed { staker: 11, amount: 100 }, - Event::Slashed { staker: 101, amount: 12 }, - ] - ); + on_offence_now( + &[OffenceDetails { offender: (11, exposure_11.clone()), reporters: vec![] }], + &[Perbill::from_percent(10)], + ); - // post-slash balance - let nominator_slash_amount_11 = 125 / 10; - assert_eq!(Balances::free_balance(11), 900); - assert_eq!(Balances::free_balance(101), 2000 - nominator_slash_amount_11); + assert_eq!( + staking_events_since_last_call(), + vec![ + Event::StakersElected, + Event::EraPaid { era_index: 0, validator_payout: 11075, remainder: 33225 }, + Event::SlashReported { + validator: 11, + fraction: Perbill::from_percent(10), + slash_era: 1 + }, + Event::Slashed { staker: 11, amount: 100 }, + Event::Slashed { staker: 101, amount: 12 }, + ] + ); - // check that validator was chilled. - assert!(Validators::::iter().all(|(stash, _)| stash != 11)); + // post-slash balance + let nominator_slash_amount_11 = 125 / 10; + assert_eq!(Balances::free_balance(11), 900); + assert_eq!(Balances::free_balance(101), 2000 - nominator_slash_amount_11); - // actually re-bond the slashed validator - assert_ok!(Staking::validate(RuntimeOrigin::signed(11), Default::default())); + // check that validator was disabled. + assert!(is_disabled(11)); - mock::start_active_era(2); - let exposure_11 = Staking::eras_stakers(active_era(), &11); - let exposure_21 = Staking::eras_stakers(active_era(), &21); + // actually re-bond the slashed validator + assert_ok!(Staking::validate(RuntimeOrigin::signed(11), Default::default())); - // 11's own expo is reduced. sum of support from 11 is less (448), which is 500 - // 900 + 146 - assert!(matches!(exposure_11, Exposure { own: 900, total: 1046, .. })); - // 1000 + 342 - assert!(matches!(exposure_21, Exposure { own: 1000, total: 1342, .. })); - assert_eq!(500 - 146 - 342, nominator_slash_amount_11); - }); + mock::start_active_era(2); + let exposure_11 = Staking::eras_stakers(active_era(), &11); + let exposure_21 = Staking::eras_stakers(active_era(), &21); + + // 11's own expo is reduced. sum of support from 11 is less (448), which is 500 + // 900 + 146 + assert!(matches!(exposure_11, Exposure { own: 900, total: 1046, .. })); + // 1000 + 342 + assert!(matches!(exposure_21, Exposure { own: 1000, total: 1342, .. })); + assert_eq!(500 - 146 - 342, nominator_slash_amount_11); + }); } #[test] -fn non_slashable_offence_doesnt_disable_validator() { - ExtBuilder::default().build_and_execute(|| { - mock::start_active_era(1); - assert_eq_uvec!(Session::validators(), vec![11, 21]); +fn non_slashable_offence_disables_validator() { + ExtBuilder::default() + .validator_count(7) + .set_status(41, StakerStatus::Validator) + .set_status(51, StakerStatus::Validator) + .set_status(201, StakerStatus::Validator) + .set_status(202, StakerStatus::Validator) + .build_and_execute(|| { + mock::start_active_era(1); + assert_eq_uvec!(Session::validators(), vec![11, 21, 31, 41, 51, 201, 202]); - let exposure_11 = Staking::eras_stakers(Staking::active_era().unwrap().index, &11); - let exposure_21 = Staking::eras_stakers(Staking::active_era().unwrap().index, &21); + let exposure_11 = Staking::eras_stakers(Staking::active_era().unwrap().index, &11); + let exposure_21 = Staking::eras_stakers(Staking::active_era().unwrap().index, &21); - // offence with no slash associated - on_offence_now( - &[OffenceDetails { offender: (11, exposure_11.clone()), reporters: vec![] }], - &[Perbill::zero()], - ); + // offence with no slash associated + on_offence_now( + &[OffenceDetails { offender: (11, exposure_11.clone()), reporters: vec![] }], + &[Perbill::zero()], + ); - // it does NOT affect the nominator. - assert_eq!(Staking::nominators(101).unwrap().targets, vec![11, 21]); + // it does NOT affect the nominator. + assert_eq!(Staking::nominators(101).unwrap().targets, vec![11, 21]); - // offence that slashes 25% of the bond - on_offence_now( - &[OffenceDetails { offender: (21, exposure_21.clone()), reporters: vec![] }], - &[Perbill::from_percent(25)], - ); + // offence that slashes 25% of the bond + on_offence_now( + &[OffenceDetails { offender: (21, exposure_21.clone()), reporters: vec![] }], + &[Perbill::from_percent(25)], + ); - // it DOES NOT affect the nominator. - assert_eq!(Staking::nominators(101).unwrap().targets, vec![11, 21]); + // it DOES NOT affect the nominator. + assert_eq!(Staking::nominators(101).unwrap().targets, vec![11, 21]); - assert_eq!( - staking_events_since_last_call(), - vec![ - Event::StakersElected, - Event::EraPaid { era_index: 0, validator_payout: 11075, remainder: 33225 }, - Event::Chilled { stash: 11 }, - Event::ForceEra { mode: Forcing::ForceNew }, - Event::SlashReported { - validator: 11, - fraction: Perbill::from_percent(0), - slash_era: 1 - }, - Event::Chilled { stash: 21 }, - Event::SlashReported { - validator: 21, - fraction: Perbill::from_percent(25), - slash_era: 1 - }, - Event::Slashed { staker: 21, amount: 250 }, - Event::Slashed { staker: 101, amount: 94 } - ] - ); + assert_eq!( + staking_events_since_last_call(), + vec![ + Event::StakersElected, + Event::EraPaid { era_index: 0, validator_payout: 11075, remainder: 33225 }, + Event::SlashReported { + validator: 11, + fraction: Perbill::from_percent(0), + slash_era: 1 + }, + Event::SlashReported { + validator: 21, + fraction: Perbill::from_percent(25), + slash_era: 1 + }, + Event::Slashed { staker: 21, amount: 250 }, + Event::Slashed { staker: 101, amount: 94 } + ] + ); - // the offence for validator 10 wasn't slashable so it wasn't disabled - assert!(!is_disabled(11)); - // whereas validator 20 gets disabled - assert!(is_disabled(21)); - }); + // the offence for validator 11 wasn't slashable but it is disabled + assert!(is_disabled(11)); + // validator 21 gets disabled too + assert!(is_disabled(21)); + }); } #[test] fn slashing_independent_of_disabling_validator() { - ExtBuilder::default().build_and_execute(|| { - mock::start_active_era(1); - assert_eq_uvec!(Session::validators(), vec![11, 21]); - - let exposure_11 = Staking::eras_stakers(Staking::active_era().unwrap().index, &11); - let exposure_21 = Staking::eras_stakers(Staking::active_era().unwrap().index, &21); + ExtBuilder::default() + .validator_count(5) + .set_status(41, StakerStatus::Validator) + .set_status(51, StakerStatus::Validator) + .build_and_execute(|| { + mock::start_active_era(1); + assert_eq_uvec!(Session::validators(), vec![11, 21, 31, 41, 51]); - let now = Staking::active_era().unwrap().index; + let exposure_11 = Staking::eras_stakers(Staking::active_era().unwrap().index, &11); + let exposure_21 = Staking::eras_stakers(Staking::active_era().unwrap().index, &21); - // offence with no slash associated, BUT disabling - on_offence_in_era( - &[OffenceDetails { offender: (11, exposure_11.clone()), reporters: vec![] }], - &[Perbill::zero()], - now, - DisableStrategy::Always, - ); + let now = Staking::active_era().unwrap().index; - // nomination remains untouched. - assert_eq!(Staking::nominators(101).unwrap().targets, vec![11, 21]); - - // offence that slashes 25% of the bond, BUT not disabling - on_offence_in_era( - &[OffenceDetails { offender: (21, exposure_21.clone()), reporters: vec![] }], - &[Perbill::from_percent(25)], - now, - DisableStrategy::Never, - ); + // offence with no slash associated + on_offence_in_era( + &[OffenceDetails { offender: (11, exposure_11.clone()), reporters: vec![] }], + &[Perbill::zero()], + now, + ); - // nomination remains untouched. - assert_eq!(Staking::nominators(101).unwrap().targets, vec![11, 21]); + // nomination remains untouched. + assert_eq!(Staking::nominators(101).unwrap().targets, vec![11, 21]); - assert_eq!( - staking_events_since_last_call(), - vec![ - Event::StakersElected, - Event::EraPaid { era_index: 0, validator_payout: 11075, remainder: 33225 }, - Event::Chilled { stash: 11 }, - Event::ForceEra { mode: Forcing::ForceNew }, - Event::SlashReported { - validator: 11, - fraction: Perbill::from_percent(0), - slash_era: 1 - }, - Event::Chilled { stash: 21 }, - Event::SlashReported { - validator: 21, - fraction: Perbill::from_percent(25), - slash_era: 1 - }, - Event::Slashed { staker: 21, amount: 250 }, - Event::Slashed { staker: 101, amount: 94 } - ] - ); + // offence that slashes 25% of the bond + on_offence_in_era( + &[OffenceDetails { offender: (21, exposure_21.clone()), reporters: vec![] }], + &[Perbill::from_percent(25)], + now, + ); - // the offence for validator 10 was explicitly disabled - assert!(is_disabled(11)); - // whereas validator 21 is explicitly not disabled - assert!(!is_disabled(21)); - }); + // nomination remains untouched. + assert_eq!(Staking::nominators(101).unwrap().targets, vec![11, 21]); + + assert_eq!( + staking_events_since_last_call(), + vec![ + Event::StakersElected, + Event::EraPaid { era_index: 0, validator_payout: 11075, remainder: 33225 }, + Event::SlashReported { + validator: 11, + fraction: Perbill::from_percent(0), + slash_era: 1 + }, + Event::SlashReported { + validator: 21, + fraction: Perbill::from_percent(25), + slash_era: 1 + }, + Event::Slashed { staker: 21, amount: 250 }, + Event::Slashed { staker: 101, amount: 94 } + ] + ); + + // first validator is disabled but not slashed + assert!(is_disabled(11)); + // second validator is slashed but not disabled + assert!(!is_disabled(21)); + }); } #[test] -fn offence_threshold_triggers_new_era() { +fn offence_threshold_doesnt_trigger_new_era() { ExtBuilder::default() .validator_count(4) .set_status(41, StakerStatus::Validator) @@ -3506,12 +3553,14 @@ fn offence_threshold_triggers_new_era() { assert_eq_uvec!(Session::validators(), vec![11, 21, 31, 41]); assert_eq!( - ::OffendingValidatorsThreshold::get(), - Perbill::from_percent(75), + UpToLimitDisablingStrategy::::disable_limit( + Session::validators().len() + ), + 1 ); - // we have 4 validators and an offending validator threshold of 75%, - // once the third validator commits an offence a new era should be forced + // we have 4 validators and an offending validator threshold of 1/3, + // even if the third validator commits an offence a new era should not be forced let exposure_11 = Staking::eras_stakers(Staking::active_era().unwrap().index, &11); let exposure_21 = Staking::eras_stakers(Staking::active_era().unwrap().index, &21); @@ -3522,6 +3571,9 @@ fn offence_threshold_triggers_new_era() { &[Perbill::zero()], ); + // 11 should be disabled because the byzantine threshold is 1 + assert!(is_disabled(11)); + assert_eq!(ForceEra::::get(), Forcing::NotForcing); on_offence_now( @@ -3529,6 +3581,10 @@ fn offence_threshold_triggers_new_era() { &[Perbill::zero()], ); + // 21 should not be disabled because the number of disabled validators will be above the + // byzantine threshold + assert!(!is_disabled(21)); + assert_eq!(ForceEra::::get(), Forcing::NotForcing); on_offence_now( @@ -3536,28 +3592,29 @@ fn offence_threshold_triggers_new_era() { &[Perbill::zero()], ); - assert_eq!(ForceEra::::get(), Forcing::ForceNew); + // same for 31 + assert!(!is_disabled(31)); + + assert_eq!(ForceEra::::get(), Forcing::NotForcing); }); } #[test] fn disabled_validators_are_kept_disabled_for_whole_era() { ExtBuilder::default() - .validator_count(4) + .validator_count(7) .set_status(41, StakerStatus::Validator) + .set_status(51, StakerStatus::Validator) + .set_status(201, StakerStatus::Validator) + .set_status(202, StakerStatus::Validator) .build_and_execute(|| { mock::start_active_era(1); - assert_eq_uvec!(Session::validators(), vec![11, 21, 31, 41]); + assert_eq_uvec!(Session::validators(), vec![11, 21, 31, 41, 51, 201, 202]); assert_eq!(::SessionsPerEra::get(), 3); let exposure_11 = Staking::eras_stakers(Staking::active_era().unwrap().index, &11); let exposure_21 = Staking::eras_stakers(Staking::active_era().unwrap().index, &21); - on_offence_now( - &[OffenceDetails { offender: (11, exposure_11.clone()), reporters: vec![] }], - &[Perbill::zero()], - ); - on_offence_now( &[OffenceDetails { offender: (21, exposure_21.clone()), reporters: vec![] }], &[Perbill::from_percent(25)], @@ -3566,18 +3623,15 @@ fn disabled_validators_are_kept_disabled_for_whole_era() { // nominations are not updated. assert_eq!(Staking::nominators(101).unwrap().targets, vec![11, 21]); - // validator 11 should not be disabled since the offence wasn't slashable - assert!(!is_disabled(11)); // validator 21 gets disabled since it got slashed assert!(is_disabled(21)); advance_session(); // disabled validators should carry-on through all sessions in the era - assert!(!is_disabled(11)); assert!(is_disabled(21)); - // validator 11 should now get disabled + // validator 11 commits an offence on_offence_now( &[OffenceDetails { offender: (11, exposure_11.clone()), reporters: vec![] }], &[Perbill::from_percent(25)], @@ -3687,27 +3741,34 @@ fn claim_reward_at_the_last_era_and_no_double_claim_and_invalid_claim() { #[test] fn zero_slash_keeps_nominators() { - ExtBuilder::default().build_and_execute(|| { - mock::start_active_era(1); + ExtBuilder::default() + .validator_count(7) + .set_status(41, StakerStatus::Validator) + .set_status(51, StakerStatus::Validator) + .set_status(201, StakerStatus::Validator) + .set_status(202, StakerStatus::Validator) + .build_and_execute(|| { + mock::start_active_era(1); - assert_eq!(Balances::free_balance(11), 1000); + assert_eq!(Balances::free_balance(11), 1000); - let exposure = Staking::eras_stakers(active_era(), &11); - assert_eq!(Balances::free_balance(101), 2000); + let exposure = Staking::eras_stakers(active_era(), &11); + assert_eq!(Balances::free_balance(101), 2000); - on_offence_now( - &[OffenceDetails { offender: (11, exposure.clone()), reporters: vec![] }], - &[Perbill::from_percent(0)], - ); + on_offence_now( + &[OffenceDetails { offender: (11, exposure.clone()), reporters: vec![] }], + &[Perbill::from_percent(0)], + ); - assert_eq!(Balances::free_balance(11), 1000); - assert_eq!(Balances::free_balance(101), 2000); + assert_eq!(Balances::free_balance(11), 1000); + assert_eq!(Balances::free_balance(101), 2000); - // 11 is still removed.. - assert!(Validators::::iter().all(|(stash, _)| stash != 11)); - // but their nominations are kept. - assert_eq!(Staking::nominators(101).unwrap().targets, vec![11, 21]); - }); + // 11 is not removed but disabled + assert!(Validators::::iter().any(|(stash, _)| stash == 11)); + assert!(is_disabled(11)); + // and their nominations are kept. + assert_eq!(Staking::nominators(101).unwrap().targets, vec![11, 21]); + }); } #[test] @@ -4710,7 +4771,7 @@ fn offences_weight_calculated_correctly() { let zero_offence_weight = ::DbWeight::get().reads_writes(4, 1); assert_eq!( - Staking::on_offence(&[], &[Perbill::from_percent(50)], 0, DisableStrategy::WhenSlashed), + Staking::on_offence(&[], &[Perbill::from_percent(50)], 0), zero_offence_weight ); @@ -4735,7 +4796,6 @@ fn offences_weight_calculated_correctly() { &offenders, &[Perbill::from_percent(50)], 0, - DisableStrategy::WhenSlashed ), n_offence_unapplied_weight ); @@ -4765,7 +4825,6 @@ fn offences_weight_calculated_correctly() { &one_offender, &[Perbill::from_percent(50)], 0, - DisableStrategy::WhenSlashed{} ), one_offence_unapplied_weight ); @@ -6775,6 +6834,113 @@ fn test_validator_exposure_is_backward_compatible_with_non_paged_rewards_payout( }); } +#[test] +fn test_runtime_api_pending_rewards() { + ExtBuilder::default().build_and_execute(|| { + // GIVEN + let err_weight = ::WeightInfo::payout_stakers_alive_staked(0); + let stake = 100; + + // validator with non-paged exposure, rewards marked in legacy claimed rewards. + let validator_one = 301; + // validator with non-paged exposure, rewards marked in paged claimed rewards. + let validator_two = 302; + // validator with paged exposure. + let validator_three = 303; + + // Set staker + for v in validator_one..=validator_three { + let _ = Balances::make_free_balance_be(&v, stake); + assert_ok!(Staking::bond(RuntimeOrigin::signed(v), stake, RewardDestination::Staked)); + } + + // Add reward points + let reward = EraRewardPoints:: { + total: 1, + individual: vec![(validator_one, 1), (validator_two, 1), (validator_three, 1)] + .into_iter() + .collect(), + }; + ErasRewardPoints::::insert(0, reward); + + // build exposure + let mut individual_exposures: Vec> = vec![]; + for i in 0..=MaxExposurePageSize::get() { + individual_exposures.push(IndividualExposure { who: i.into(), value: stake }); + } + let exposure = Exposure:: { + total: stake * (MaxExposurePageSize::get() as Balance + 2), + own: stake, + others: individual_exposures, + }; + + // add non-paged exposure for one and two. + >::insert(0, validator_one, exposure.clone()); + >::insert(0, validator_two, exposure.clone()); + // add paged exposure for third validator + EraInfo::::set_exposure(0, &validator_three, exposure); + + // add some reward to be distributed + ErasValidatorReward::::insert(0, 1000); + + // mark rewards claimed for validator_one in legacy claimed rewards + >::insert( + validator_one, + StakingLedgerInspect { + stash: validator_one, + total: stake, + active: stake, + unlocking: Default::default(), + legacy_claimed_rewards: bounded_vec![0], + }, + ); + + // SCENARIO ONE: rewards already marked claimed in legacy storage. + // runtime api should return false for pending rewards for validator_one. + assert!(!EraInfo::::pending_rewards(0, &validator_one)); + // and if we try to pay, we get an error. + assert_noop!( + Staking::payout_stakers(RuntimeOrigin::signed(1337), validator_one, 0), + Error::::AlreadyClaimed.with_weight(err_weight) + ); + + // SCENARIO TWO: non-paged exposure + // validator two has not claimed rewards, so pending rewards is true. + assert!(EraInfo::::pending_rewards(0, &validator_two)); + // and payout works + assert_ok!(Staking::payout_stakers(RuntimeOrigin::signed(1337), validator_two, 0)); + // now pending rewards is false. + assert!(!EraInfo::::pending_rewards(0, &validator_two)); + // and payout fails + assert_noop!( + Staking::payout_stakers(RuntimeOrigin::signed(1337), validator_two, 0), + Error::::AlreadyClaimed.with_weight(err_weight) + ); + + // SCENARIO THREE: validator with paged exposure (two pages). + // validator three has not claimed rewards, so pending rewards is true. + assert!(EraInfo::::pending_rewards(0, &validator_three)); + // and payout works + assert_ok!(Staking::payout_stakers(RuntimeOrigin::signed(1337), validator_three, 0)); + // validator three has two pages of exposure, so pending rewards is still true. + assert!(EraInfo::::pending_rewards(0, &validator_three)); + // payout again + assert_ok!(Staking::payout_stakers(RuntimeOrigin::signed(1337), validator_three, 0)); + // now pending rewards is false. + assert!(!EraInfo::::pending_rewards(0, &validator_three)); + // and payout fails + assert_noop!( + Staking::payout_stakers(RuntimeOrigin::signed(1337), validator_three, 0), + Error::::AlreadyClaimed.with_weight(err_weight) + ); + + // for eras with no exposure, pending rewards is false. + assert!(!EraInfo::::pending_rewards(0, &validator_one)); + assert!(!EraInfo::::pending_rewards(0, &validator_two)); + assert!(!EraInfo::::pending_rewards(0, &validator_three)); + }); +} + mod staking_interface { use frame_support::storage::with_storage_layer; use sp_staking::StakingInterface; @@ -6825,6 +6991,59 @@ mod staking_interface { }); } + #[test] + fn do_withdraw_unbonded_can_kill_stash_with_existential_deposit_zero() { + ExtBuilder::default() + .existential_deposit(0) + .nominate(false) + .build_and_execute(|| { + // Initial state of 11 + assert_eq!(Staking::bonded(&11), Some(11)); + assert_eq!( + Staking::ledger(11.into()).unwrap(), + StakingLedgerInspect { + stash: 11, + total: 1000, + active: 1000, + unlocking: Default::default(), + legacy_claimed_rewards: bounded_vec![], + } + ); + assert_eq!( + Staking::eras_stakers(active_era(), &11), + Exposure { total: 1000, own: 1000, others: vec![] } + ); + + // Unbond all of the funds in stash. + Staking::chill(RuntimeOrigin::signed(11)).unwrap(); + Staking::unbond(RuntimeOrigin::signed(11), 1000).unwrap(); + assert_eq!( + Staking::ledger(11.into()).unwrap(), + StakingLedgerInspect { + stash: 11, + total: 1000, + active: 0, + unlocking: bounded_vec![UnlockChunk { value: 1000, era: 3 }], + legacy_claimed_rewards: bounded_vec![], + }, + ); + + // trigger future era. + mock::start_active_era(3); + + // withdraw unbonded + assert_ok!(Staking::withdraw_unbonded(RuntimeOrigin::signed(11), 0)); + + // empty stash has been reaped + assert!(!>::contains_key(&11)); + assert!(!>::contains_key(&11)); + assert!(!>::contains_key(&11)); + assert!(!>::contains_key(&11)); + // lock is removed. + assert_eq!(Balances::balance_locked(STAKING_ID, &11), 0); + }); + } + #[test] fn status() { ExtBuilder::default().build_and_execute(|| { @@ -6849,6 +7068,328 @@ mod staking_interface { } } +mod staking_unchecked { + use sp_staking::{Stake, StakingInterface, StakingUnchecked}; + + use super::*; + + #[test] + fn virtual_bond_does_not_lock() { + ExtBuilder::default().build_and_execute(|| { + mock::start_active_era(1); + assert_eq!(Balances::free_balance(10), 1); + // 10 can bond more than its balance amount since we do not require lock for virtual + // bonding. + assert_ok!(::virtual_bond(&10, 100, &15)); + // nothing is locked on 10. + assert_eq!(Balances::balance_locked(STAKING_ID, &10), 0); + // adding more balance does not lock anything as well. + assert_ok!(::bond_extra(&10, 1000)); + // but ledger is updated correctly. + assert_eq!( + ::stake(&10), + Ok(Stake { total: 1100, active: 1100 }) + ); + + // lets try unbonding some amount. + assert_ok!(::unbond(&10, 200)); + assert_eq!( + Staking::ledger(10.into()).unwrap(), + StakingLedgerInspect { + stash: 10, + total: 1100, + active: 1100 - 200, + unlocking: bounded_vec![UnlockChunk { value: 200, era: 1 + 3 }], + legacy_claimed_rewards: bounded_vec![], + } + ); + + assert_eq!( + ::stake(&10), + Ok(Stake { total: 1100, active: 900 }) + ); + // still no locks. + assert_eq!(Balances::balance_locked(STAKING_ID, &10), 0); + + mock::start_active_era(2); + // cannot withdraw without waiting for unbonding period. + assert_ok!(::withdraw_unbonded(10, 0)); + assert_eq!( + ::stake(&10), + Ok(Stake { total: 1100, active: 900 }) + ); + + // in era 4, 10 can withdraw unlocking amount. + mock::start_active_era(4); + assert_ok!(::withdraw_unbonded(10, 0)); + assert_eq!( + ::stake(&10), + Ok(Stake { total: 900, active: 900 }) + ); + + // unbond all. + assert_ok!(::unbond(&10, 900)); + assert_eq!( + ::stake(&10), + Ok(Stake { total: 900, active: 0 }) + ); + mock::start_active_era(7); + assert_ok!(::withdraw_unbonded(10, 0)); + + // ensure withdrawing all amount cleans up storage. + assert_eq!(Staking::ledger(10.into()), Err(Error::::NotStash)); + assert_eq!(VirtualStakers::::contains_key(10), false); + }) + } + + #[test] + fn virtual_staker_cannot_pay_reward_to_self_account() { + ExtBuilder::default().build_and_execute(|| { + // cannot set payee to self + assert_noop!( + ::virtual_bond(&10, 100, &10), + Error::::RewardDestinationRestricted + ); + + // to another account works + assert_ok!(::virtual_bond(&10, 100, &11)); + + // cannot set via set_payee as well. + assert_noop!( + ::update_payee(&10, &10), + Error::::RewardDestinationRestricted + ); + }); + } + + #[test] + fn virtual_staker_cannot_bond_again() { + ExtBuilder::default().build_and_execute(|| { + // 200 virtual bonds + bond_virtual_nominator(200, 201, 500, vec![11, 21]); + + // Tries bonding again + assert_noop!( + ::virtual_bond(&200, 200, &201), + Error::::AlreadyBonded + ); + + // And again with a different reward destination. + assert_noop!( + ::virtual_bond(&200, 200, &202), + Error::::AlreadyBonded + ); + + // Direct bond is not allowed as well. + assert_noop!( + ::bond(&200, 200, &202), + Error::::AlreadyBonded + ); + }); + } + + #[test] + fn normal_staker_cannot_virtual_bond() { + ExtBuilder::default().build_and_execute(|| { + // 101 is a nominator trying to virtual bond + assert_noop!( + ::virtual_bond(&101, 200, &102), + Error::::AlreadyBonded + ); + + // validator 21 tries to virtual bond + assert_noop!( + ::virtual_bond(&21, 200, &22), + Error::::AlreadyBonded + ); + }); + } + + #[test] + fn migrate_virtual_staker() { + ExtBuilder::default().build_and_execute(|| { + // give some balance to 200 + Balances::make_free_balance_be(&200, 2000); + + // stake + assert_ok!(Staking::bond(RuntimeOrigin::signed(200), 1000, RewardDestination::Staked)); + assert_eq!(Balances::balance_locked(crate::STAKING_ID, &200), 1000); + + // migrate them to virtual staker + ::migrate_to_virtual_staker(&200); + // payee needs to be updated to a non-stash account. + assert_ok!(::update_payee(&200, &201)); + + // ensure the balance is not locked anymore + assert_eq!(Balances::balance_locked(crate::STAKING_ID, &200), 0); + + // and they are marked as virtual stakers + assert_eq!(Pallet::::is_virtual_staker(&200), true); + }); + } + + #[test] + fn virtual_nominators_are_lazily_slashed() { + ExtBuilder::default() + .validator_count(7) + .set_status(41, StakerStatus::Validator) + .set_status(51, StakerStatus::Validator) + .set_status(201, StakerStatus::Validator) + .set_status(202, StakerStatus::Validator) + .build_and_execute(|| { + mock::start_active_era(1); + let slash_percent = Perbill::from_percent(5); + let initial_exposure = Staking::eras_stakers(active_era(), &11); + // 101 is a nominator for 11 + assert_eq!(initial_exposure.others.first().unwrap().who, 101); + // make 101 a virtual nominator + ::migrate_to_virtual_staker(&101); + // set payee different to self. + assert_ok!(::update_payee(&101, &102)); + + // cache values + let nominator_stake = Staking::ledger(101.into()).unwrap().active; + let nominator_balance = balances(&101).0; + let validator_stake = Staking::ledger(11.into()).unwrap().active; + let validator_balance = balances(&11).0; + let exposed_stake = initial_exposure.total; + let exposed_validator = initial_exposure.own; + let exposed_nominator = initial_exposure.others.first().unwrap().value; + + // 11 goes offline + on_offence_now( + &[OffenceDetails { + offender: (11, initial_exposure.clone()), + reporters: vec![], + }], + &[slash_percent], + ); + + let slash_amount = slash_percent * exposed_stake; + let validator_share = + Perbill::from_rational(exposed_validator, exposed_stake) * slash_amount; + let nominator_share = + Perbill::from_rational(exposed_nominator, exposed_stake) * slash_amount; + + // both slash amounts need to be positive for the test to make sense. + assert!(validator_share > 0); + assert!(nominator_share > 0); + + // both stakes must have been decreased pro-rata. + assert_eq!( + Staking::ledger(101.into()).unwrap().active, + nominator_stake - nominator_share + ); + assert_eq!( + Staking::ledger(11.into()).unwrap().active, + validator_stake - validator_share + ); + + // validator balance is slashed as usual + assert_eq!(balances(&11).0, validator_balance - validator_share); + // Because slashing happened. + assert!(is_disabled(11)); + + // but virtual nominator's balance is not slashed. + assert_eq!(Balances::free_balance(&101), nominator_balance); + // but slash is broadcasted to slash observers. + assert_eq!(SlashObserver::get().get(&101).unwrap(), &nominator_share); + }) + } + + #[test] + fn virtual_stakers_cannot_be_reaped() { + ExtBuilder::default() + // we need enough validators such that disables are allowed. + .validator_count(7) + .set_status(41, StakerStatus::Validator) + .set_status(51, StakerStatus::Validator) + .set_status(201, StakerStatus::Validator) + .set_status(202, StakerStatus::Validator) + .build_and_execute(|| { + // make 101 only nominate 11. + assert_ok!(Staking::nominate(RuntimeOrigin::signed(101), vec![11])); + + mock::start_active_era(1); + + // slash all stake. + let slash_percent = Perbill::from_percent(100); + let initial_exposure = Staking::eras_stakers(active_era(), &11); + // 101 is a nominator for 11 + assert_eq!(initial_exposure.others.first().unwrap().who, 101); + // make 101 a virtual nominator + ::migrate_to_virtual_staker(&101); + // set payee different to self. + assert_ok!(::update_payee(&101, &102)); + + // cache values + let validator_balance = Balances::free_balance(&11); + let validator_stake = Staking::ledger(11.into()).unwrap().total; + let nominator_balance = Balances::free_balance(&101); + let nominator_stake = Staking::ledger(101.into()).unwrap().total; + + // 11 goes offline + on_offence_now( + &[OffenceDetails { + offender: (11, initial_exposure.clone()), + reporters: vec![], + }], + &[slash_percent], + ); + + // both stakes must have been decreased to 0. + assert_eq!(Staking::ledger(101.into()).unwrap().active, 0); + assert_eq!(Staking::ledger(11.into()).unwrap().active, 0); + + // all validator stake is slashed + assert_eq_error_rate!( + validator_balance - validator_stake, + Balances::free_balance(&11), + 1 + ); + // Because slashing happened. + assert!(is_disabled(11)); + + // Virtual nominator's balance is not slashed. + assert_eq!(Balances::free_balance(&101), nominator_balance); + // Slash is broadcasted to slash observers. + assert_eq!(SlashObserver::get().get(&101).unwrap(), &nominator_stake); + + // validator can be reaped. + assert_ok!(Staking::reap_stash(RuntimeOrigin::signed(10), 11, u32::MAX)); + // nominator is a virtual staker and cannot be reaped. + assert_noop!( + Staking::reap_stash(RuntimeOrigin::signed(10), 101, u32::MAX), + Error::::VirtualStakerNotAllowed + ); + }) + } + + #[test] + fn restore_ledger_not_allowed_for_virtual_stakers() { + ExtBuilder::default().has_stakers(true).build_and_execute(|| { + setup_double_bonded_ledgers(); + assert_eq!(Staking::inspect_bond_state(&333).unwrap(), LedgerIntegrityState::Ok); + set_controller_no_checks(&444); + // 333 is corrupted + assert_eq!(Staking::inspect_bond_state(&333).unwrap(), LedgerIntegrityState::Corrupted); + // migrate to virtual staker. + ::migrate_to_virtual_staker(&333); + + // recover the ledger won't work for virtual staker + assert_noop!( + Staking::restore_ledger(RuntimeOrigin::root(), 333, None, None, None), + Error::::VirtualStakerNotAllowed + ); + + // migrate 333 back to normal staker + >::remove(333); + + // try restore again + assert_ok!(Staking::restore_ledger(RuntimeOrigin::root(), 333, None, None, None)); + }) + } +} mod ledger { use super::*; @@ -7327,7 +7868,6 @@ mod ledger { mod ledger_recovery { use super::*; - use frame_support::traits::InspectLockableCurrency; #[test] fn inspect_recovery_ledger_simple_works() { @@ -7707,3 +8247,69 @@ mod ledger_recovery { }) } } + +mod byzantine_threshold_disabling_strategy { + use crate::{ + tests::Test, ActiveEra, ActiveEraInfo, DisablingStrategy, UpToLimitDisablingStrategy, + }; + use sp_staking::EraIndex; + + // Common test data - the stash of the offending validator, the era of the offence and the + // active set + const OFFENDER_ID: ::AccountId = 7; + const SLASH_ERA: EraIndex = 1; + const ACTIVE_SET: [::ValidatorId; 7] = [1, 2, 3, 4, 5, 6, 7]; + const OFFENDER_VALIDATOR_IDX: u32 = 6; // the offender is with index 6 in the active set + + #[test] + fn dont_disable_for_ancient_offence() { + sp_io::TestExternalities::default().execute_with(|| { + let initially_disabled = vec![]; + pallet_session::Validators::::put(ACTIVE_SET.to_vec()); + ActiveEra::::put(ActiveEraInfo { index: 2, start: None }); + + let disable_offender = + >::decision( + &OFFENDER_ID, + SLASH_ERA, + &initially_disabled, + ); + + assert!(disable_offender.is_none()); + }); + } + + #[test] + fn dont_disable_beyond_byzantine_threshold() { + sp_io::TestExternalities::default().execute_with(|| { + let initially_disabled = vec![1, 2]; + pallet_session::Validators::::put(ACTIVE_SET.to_vec()); + + let disable_offender = + >::decision( + &OFFENDER_ID, + SLASH_ERA, + &initially_disabled, + ); + + assert!(disable_offender.is_none()); + }); + } + + #[test] + fn disable_when_below_byzantine_threshold() { + sp_io::TestExternalities::default().execute_with(|| { + let initially_disabled = vec![1]; + pallet_session::Validators::::put(ACTIVE_SET.to_vec()); + + let disable_offender = + >::decision( + &OFFENDER_ID, + SLASH_ERA, + &initially_disabled, + ); + + assert_eq!(disable_offender, Some(OFFENDER_VALIDATOR_IDX)); + }); + } +} diff --git a/substrate/frame/state-trie-migration/Cargo.toml b/substrate/frame/state-trie-migration/Cargo.toml index 613308c308e1f15eace901af1a192202f1aa8cad..0870989d81f15df54cec9c41a0fa408edb45af36 100644 --- a/substrate/frame/state-trie-migration/Cargo.toml +++ b/substrate/frame/state-trie-migration/Cargo.toml @@ -15,7 +15,7 @@ workspace = true targets = ["x86_64-unknown-linux-gnu"] [dependencies] -codec = { package = "parity-scale-codec", version = "3.6.1", default-features = false } +codec = { package = "parity-scale-codec", version = "3.6.12", default-features = false } log = { workspace = true } scale-info = { version = "2.11.1", default-features = false, features = ["derive"] } serde = { optional = true, workspace = true, default-features = true } diff --git a/substrate/frame/statement/Cargo.toml b/substrate/frame/statement/Cargo.toml index 92bc32191ab84d41e9dd18ef5f3863d2c5502edd..989f0c330fc10b19bde46d92d853fcbdef2b463a 100644 --- a/substrate/frame/statement/Cargo.toml +++ b/substrate/frame/statement/Cargo.toml @@ -15,7 +15,7 @@ workspace = true targets = ["x86_64-unknown-linux-gnu"] [dependencies] -codec = { package = "parity-scale-codec", version = "3.6.1", default-features = false, features = ["derive"] } +codec = { package = "parity-scale-codec", version = "3.6.12", default-features = false, features = ["derive"] } scale-info = { version = "2.11.1", default-features = false, features = ["derive"] } frame-support = { path = "../support", default-features = false } frame-system = { path = "../system", default-features = false } diff --git a/substrate/frame/sudo/Cargo.toml b/substrate/frame/sudo/Cargo.toml index 805f46a77f2eb0c3f7433a83659972a9d7da65c7..fcbb00087e26c7b08a00227c142a2565b2c0c04b 100644 --- a/substrate/frame/sudo/Cargo.toml +++ b/substrate/frame/sudo/Cargo.toml @@ -16,7 +16,7 @@ workspace = true targets = ["x86_64-unknown-linux-gnu"] [dependencies] -codec = { package = "parity-scale-codec", version = "3.6.1", default-features = false, features = ["derive"] } +codec = { package = "parity-scale-codec", version = "3.6.12", default-features = false, features = ["derive"] } frame-benchmarking = { path = "../benchmarking", default-features = false, optional = true } scale-info = { version = "2.11.1", default-features = false, features = ["derive"] } frame-support = { path = "../support", default-features = false } diff --git a/substrate/frame/support/Cargo.toml b/substrate/frame/support/Cargo.toml index ecdd93826327798a76b36a54dc6ad0a2b0106c24..a6c4fd6ee309ec4fc07495b59df341b854dfb1a9 100644 --- a/substrate/frame/support/Cargo.toml +++ b/substrate/frame/support/Cargo.toml @@ -16,9 +16,9 @@ workspace = true targets = ["x86_64-unknown-linux-gnu"] [dependencies] -array-bytes = { version = "6.1", default-features = false } +array-bytes = { version = "6.2.2", default-features = false } serde = { features = ["alloc", "derive"], workspace = true } -codec = { package = "parity-scale-codec", version = "3.6.1", default-features = false, features = [ +codec = { package = "parity-scale-codec", version = "3.6.12", default-features = false, features = [ "derive", "max-encoded-len", ] } diff --git a/substrate/frame/support/procedural/Cargo.toml b/substrate/frame/support/procedural/Cargo.toml index 9f8727f7adef58b68876dadc8907877c886d2d5d..b04af63de81174d02592c6d7caa51ad902c10ca8 100644 --- a/substrate/frame/support/procedural/Cargo.toml +++ b/substrate/frame/support/procedural/Cargo.toml @@ -21,7 +21,7 @@ proc-macro = true derive-syn-parse = "0.2.0" Inflector = "0.11.4" cfg-expr = "0.15.5" -itertools = "0.10.3" +itertools = "0.11" proc-macro2 = "1.0.56" quote = { workspace = true } syn = { features = ["full", "visit-mut"], workspace = true } diff --git a/substrate/frame/support/procedural/src/construct_runtime/expand/call.rs b/substrate/frame/support/procedural/src/construct_runtime/expand/call.rs index b0041ccc07541966863e51d40f4b6e26e50a396f..f055e8ce28e904639dba11f9f7639bf64c934d95 100644 --- a/substrate/frame/support/procedural/src/construct_runtime/expand/call.rs +++ b/substrate/frame/support/procedural/src/construct_runtime/expand/call.rs @@ -66,6 +66,7 @@ pub fn expand_outer_dispatch( quote! { #( #query_call_part_macros )* + /// The aggregated runtime call type. #[derive( Clone, PartialEq, Eq, #scrate::__private::codec::Encode, diff --git a/substrate/frame/support/procedural/src/construct_runtime/mod.rs b/substrate/frame/support/procedural/src/construct_runtime/mod.rs index b083abbb2a8db65e1abd1f0cc2e4a15dbd922e2d..1505d158895f0fa172884eef6aa748f44734e042 100644 --- a/substrate/frame/support/procedural/src/construct_runtime/mod.rs +++ b/substrate/frame/support/procedural/src/construct_runtime/mod.rs @@ -533,6 +533,7 @@ pub(crate) fn decl_all_pallets<'a>( for pallet_declaration in pallet_declarations { let type_name = &pallet_declaration.name; let pallet = &pallet_declaration.path; + let docs = &pallet_declaration.docs; let mut generics = vec![quote!(#runtime)]; generics.extend(pallet_declaration.instance.iter().map(|name| quote!(#pallet::#name))); let mut attrs = Vec::new(); @@ -541,6 +542,7 @@ pub(crate) fn decl_all_pallets<'a>( attrs.extend(TokenStream2::from_str(&feat).expect("was parsed successfully; qed")); } let type_decl = quote!( + #( #[doc = #docs] )* #(#attrs)* pub type #type_name = #pallet::Pallet <#(#generics),*>; ); diff --git a/substrate/frame/support/procedural/src/construct_runtime/parse.rs b/substrate/frame/support/procedural/src/construct_runtime/parse.rs index 31866c787b0f339d6d83b810476e840216f70bbc..ded77bed4c8e29145b721581aec12eef1dcd952a 100644 --- a/substrate/frame/support/procedural/src/construct_runtime/parse.rs +++ b/substrate/frame/support/procedural/src/construct_runtime/parse.rs @@ -605,6 +605,8 @@ pub struct Pallet { pub pallet_parts: Vec, /// Expressions specified inside of a #[cfg] attribute. pub cfg_pattern: Vec, + /// The doc literals + pub docs: Vec, } impl Pallet { @@ -774,6 +776,7 @@ fn convert_pallets(pallets: Vec) -> syn::Result>>()?; diff --git a/substrate/frame/support/procedural/src/pallet/expand/storage.rs b/substrate/frame/support/procedural/src/pallet/expand/storage.rs index 937b068cfabd14e04b05177be2f0242eccd3abec..3cc8a843e3b1669aa054040a49101ee4ae8d3f5f 100644 --- a/substrate/frame/support/procedural/src/pallet/expand/storage.rs +++ b/substrate/frame/support/procedural/src/pallet/expand/storage.rs @@ -854,7 +854,7 @@ pub fn expand_storages(def: &mut Def) -> proc_macro2::TokenStream { for #pallet_ident<#type_use_gen> #completed_where_clause { fn try_decode_entire_state() -> Result> { - let pallet_name = <::PalletInfo as frame_support::traits::PalletInfo> + let pallet_name = <::PalletInfo as #frame_support::traits::PalletInfo> ::name::<#pallet_ident<#type_use_gen>>() .expect("Every active pallet has a name in the runtime; qed"); 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 99364aaa96cd7808def45563392be207604151d7..1975f059152c81c88c641c80b6013f5ff69f2613 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 @@ -198,9 +198,9 @@ pub fn expand_tt_default_parts(def: &mut Def) -> proc_macro2::TokenStream { macro_rules! #default_parts_unique_id_v2 { { $caller:tt - frame_support = [{ $($frame_support:ident)::* }] + your_tt_return = [{ $my_tt_return:path }] } => { - $($frame_support)*::__private::tt_return! { + $my_tt_return! { $caller tokens = [{ + Pallet #call_part_v2 #storage_part_v2 #event_part_v2 #error_part_v2 #origin_part_v2 #config_part_v2 diff --git a/substrate/frame/support/procedural/src/runtime/expand/mod.rs b/substrate/frame/support/procedural/src/runtime/expand/mod.rs index 93c88fce94b73665efa7912b36056b661b12be1e..43f11896808c71aed001a4660f3a73de2825dc8b 100644 --- a/substrate/frame/support/procedural/src/runtime/expand/mod.rs +++ b/substrate/frame/support/procedural/src/runtime/expand/mod.rs @@ -93,7 +93,7 @@ fn construct_runtime_implicit_to_explicit( 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] + #[#frame_support::runtime #attr] #input ); for pallet in definition.pallet_decls.iter() { @@ -103,7 +103,7 @@ fn construct_runtime_implicit_to_explicit( expansion = quote::quote!( #frame_support::__private::tt_call! { macro = [{ #pallet_path::tt_default_parts_v2 }] - frame_support = [{ #frame_support }] + your_tt_return = [{ #frame_support::__private::tt_return }] ~~> #frame_support::match_and_insert! { target = [{ #expansion }] pattern = [{ #pallet_name = #pallet_path #pallet_instance }] @@ -244,7 +244,7 @@ fn construct_runtime_final_expansion( // Prevent UncheckedExtrinsic to print unused warning. const _: () = { #[allow(unused)] - type __hidden_use_of_unchecked_extrinsic = #unchecked_extrinsic; + type __HiddenUseOfUncheckedExtrinsic = #unchecked_extrinsic; }; #[derive( diff --git a/substrate/frame/support/procedural/src/runtime/parse/pallet.rs b/substrate/frame/support/procedural/src/runtime/parse/pallet.rs index d2f1857fb2b4feec841224f28d691076c8853427..09f5290541d3a6ac038cd863a96330f10b605c44 100644 --- a/substrate/frame/support/procedural/src/runtime/parse/pallet.rs +++ b/substrate/frame/support/procedural/src/runtime/parse/pallet.rs @@ -16,6 +16,7 @@ // limitations under the License. use crate::construct_runtime::parse::{Pallet, PalletPart, PalletPartKeyword, PalletPath}; +use frame_support_procedural_tools::get_doc_literals; use quote::ToTokens; use syn::{punctuated::Punctuated, spanned::Spanned, token, Error, Ident, PathArguments}; @@ -86,6 +87,8 @@ impl Pallet { let cfg_pattern = vec![]; + let docs = get_doc_literals(&item.attrs); + Ok(Pallet { is_expanded: true, name, @@ -94,6 +97,7 @@ impl Pallet { instance, cfg_pattern, pallet_parts, + docs, }) } } diff --git a/substrate/frame/support/procedural/src/runtime/parse/pallet_decl.rs b/substrate/frame/support/procedural/src/runtime/parse/pallet_decl.rs index 437a163cfbc44973e753075d4a139fca5df81af8..e167d37d5f14099c1f8f656e9aa5e6e5e44780b5 100644 --- a/substrate/frame/support/procedural/src/runtime/parse/pallet_decl.rs +++ b/substrate/frame/support/procedural/src/runtime/parse/pallet_decl.rs @@ -21,13 +21,14 @@ 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`. + /// The name of the pallet, e.g.`System` in `pub type 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`. + /// The path of the pallet, e.g. `frame_system` in `pub type System = frame_system`. pub path: syn::Path, - /// The instance of the pallet, e.g. `Instance1` in `Council: pallet_collective::`. + /// The instance of the pallet, e.g. `Instance1` in `pub type Council = + /// pallet_collective`. pub instance: Option, } diff --git a/substrate/frame/support/src/lib.rs b/substrate/frame/support/src/lib.rs index 895215d364e3dfccad33a805c6db34857c014ae8..7eddea1259d7d040e57084232feb53eb2b6b1270 100644 --- a/substrate/frame/support/src/lib.rs +++ b/substrate/frame/support/src/lib.rs @@ -936,6 +936,83 @@ pub mod pallet_prelude { pub use sp_weights::Weight; } +/// The pallet macro has 2 purposes: +/// +/// * [For declaring a pallet as a rust module](#1---pallet-module-declaration) +/// * [For declaring the `struct` placeholder of a +/// pallet](#2---pallet-struct-placeholder-declaration) +/// +/// # 1 - Pallet module declaration +/// +/// The module to declare a pallet is organized as follow: +/// ``` +/// #[frame_support::pallet] // <- the macro +/// mod pallet { +/// #[pallet::pallet] +/// pub struct Pallet(_); +/// +/// #[pallet::config] +/// pub trait Config: frame_system::Config {} +/// +/// #[pallet::call] +/// impl Pallet { +/// } +/// +/// /* ... */ +/// } +/// ``` +/// +/// The documentation for each individual part can be found at [frame_support::pallet_macros] +/// +/// ## Dev Mode (`#[pallet(dev_mode)]`) +/// +/// Syntax: +/// +/// ``` +/// #[frame_support::pallet(dev_mode)] +/// mod pallet { +/// # #[pallet::pallet] +/// # pub struct Pallet(_); +/// # #[pallet::config] +/// # pub trait Config: frame_system::Config {} +/// /* ... */ +/// } +/// ``` +/// +/// 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`](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`. +/// +/// 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 never deploy or use dev mode pallets in production. Doing so can break your
+/// chain. 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.
+/// 
+/// +/// # 2 - Pallet struct placeholder declaration +/// /// The pallet struct placeholder `#[pallet::pallet]` is mandatory and allows you to /// specify pallet information. /// @@ -984,40 +1061,6 @@ pub mod pallet_prelude { /// [`StorageInfoTrait`](frame_support::traits::StorageInfoTrait) for the pallet using the /// [`PartialStorageInfoTrait`](frame_support::traits::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`](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`. -/// -/// 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.
-/// 
pub use frame_support_procedural::pallet; /// Contains macro stubs for all of the `pallet::` macros @@ -1456,16 +1499,24 @@ pub mod pallet_macros { /// # use core::fmt::Debug; /// # use frame_support::traits::Contains; /// # + /// # pub trait SomeMoreComplexBound {} + /// # /// #[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 + /// #[pallet::no_default_bounds] // Default with bounds is not supported for RuntimeEvent /// type RuntimeEvent: From> + IsType<::RuntimeEvent>; /// - /// // ...other config items get default + /// /// A more complex type. + /// #[pallet::no_default] // Example of type where no default should be provided + /// type MoreComplexType: SomeMoreComplexBound; + /// + /// /// A simple type. + /// // Default with bounds is supported for simple types + /// type SimpleType: From; /// } /// /// #[pallet::event] @@ -1475,12 +1526,23 @@ pub mod pallet_macros { /// } /// ``` /// - /// As shown above, you may also attach the [`#[pallet::no_default]`](`no_default`) + /// As shown above: + /// * you may 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`). + /// * you may attach the [`#[pallet::no_default_bounds]`](`no_default_bounds`) + /// attribute to specify that a particular trait item can be used as a default when a + /// test `Config` is derived using the [`#[derive_impl(..)]`](`frame_support::derive_impl`) + /// attribute macro. But its bounds cannot be enforced at this point and should be + /// discarded when generating the default config trait. + /// * you may not specify any attribute to generate a trait item in the default config + /// trait. + /// + /// In case origin of error is not clear it is recommended to disable all default with + /// [`#[pallet::no_default]`](`no_default`) and enable them one by one. /// /// ### `DefaultConfig` Caveats /// @@ -1500,7 +1562,10 @@ pub mod pallet_macros { /// the `DefaultConfig` trait, and therefore any impl of `DefaultConfig` doesn't need to /// implement such items. /// - /// For more information, see [`frame_support::derive_impl`]. + /// For more information, see: + /// * [`frame_support::derive_impl`]. + /// * [`#[pallet::no_default]`](`no_default`) + /// * [`#[pallet::no_default_bounds]`](`no_default_bounds`) pub use frame_support_procedural::config; /// Allows defining an enum that gets composed as an aggregate enum by `construct_runtime`. @@ -2400,6 +2465,9 @@ pub mod pallet_macros { /// Finally, the `RuntimeTask` can then used by a script or off-chain worker to create and /// submit such tasks via an extrinsic defined in `frame_system` called `do_task`. /// + /// When submitted as unsigned transactions (for example via an off-chain workder), note + /// that the tasks will be executed in a random order. + /// /// ## Example #[doc = docify::embed!("src/tests/tasks.rs", tasks_example)] /// Now, this can be executed as follows: diff --git a/substrate/frame/support/src/traits.rs b/substrate/frame/support/src/traits.rs index 66777cef7b8e81960c1169c2fb1fd1033e58c4a2..a423656c394f28158da2aedd5d552814ccabb3c5 100644 --- a/substrate/frame/support/src/traits.rs +++ b/substrate/frame/support/src/traits.rs @@ -36,7 +36,7 @@ mod members; pub use members::{AllowAll, DenyAll, Filter}; pub use members::{ AsContains, ChangeMembers, Contains, ContainsLengthBound, ContainsPair, Equals, Everything, - EverythingBut, FromContainsPair, InitializeMembers, InsideBoth, IsInVec, Nothing, + EverythingBut, FromContains, FromContainsPair, InitializeMembers, InsideBoth, IsInVec, Nothing, RankedMembers, RankedMembersSwapHandler, SortedMembers, TheseExcept, }; diff --git a/substrate/frame/support/src/traits/members.rs b/substrate/frame/support/src/traits/members.rs index 3a6e3719593a22c33ad24c24c56f858ea82779ee..53de84ab22455f2d778c1fd64ba94c348c685db0 100644 --- a/substrate/frame/support/src/traits/members.rs +++ b/substrate/frame/support/src/traits/members.rs @@ -66,6 +66,15 @@ impl> Contains<(A, B)> for FromContainsPair { } } +/// A [`ContainsPair`] implementation that has a `Contains` implementation for each member of the +/// pair. +pub struct FromContains(PhantomData<(CA, CB)>); +impl, CB: Contains> ContainsPair for FromContains { + fn contains(a: &A, b: &B) -> bool { + CA::contains(a) && CB::contains(b) + } +} + /// A [`Contains`] implementation that contains every value. pub enum Everything {} impl Contains for Everything { diff --git a/substrate/frame/support/src/traits/messages.rs b/substrate/frame/support/src/traits/messages.rs index f3d893bcc1d899fce06ef00a38d687bfb3ea0181..2eec606b6d18b20a086e4ce7b44a877c3b8fb4d5 100644 --- a/substrate/frame/support/src/traits/messages.rs +++ b/substrate/frame/support/src/traits/messages.rs @@ -46,6 +46,8 @@ pub enum ProcessMessageError { /// the case that a queue is re-serviced within the same block after *yielding*. A queue is /// not required to *yield* again when it is being re-serviced withing the same block. Yield, + /// The message could not be processed for reaching the stack depth limit. + StackLimitReached, } /// Can process messages from a specific origin. @@ -96,6 +98,8 @@ pub trait ServiceQueues { /// - `weight_limit`: The maximum amount of dynamic weight that this call can use. /// /// Returns the dynamic weight used by this call; is never greater than `weight_limit`. + /// Should only be called in top-level runtime entry points like `on_initialize` or `on_idle`. + /// Otherwise, stack depth limit errors may be miss-handled. fn service_queues(weight_limit: Weight) -> Weight; /// Executes a message that could not be executed by [`Self::service_queues()`] because it was diff --git a/substrate/frame/support/src/traits/tasks.rs b/substrate/frame/support/src/traits/tasks.rs index 24f3430cf50b5a23175c4c586c1642da580cf862..42b837e55970def3c4d99f3c5f3cc9ca5dacaaf3 100644 --- a/substrate/frame/support/src/traits/tasks.rs +++ b/substrate/frame/support/src/traits/tasks.rs @@ -46,6 +46,10 @@ pub trait Task: Sized + FullCodec + TypeInfo + Clone + Debug + PartialEq + Eq { fn iter() -> Self::Enumeration; /// Checks if a particular instance of this `Task` variant is a valid piece of work. + /// + /// This is used to validate tasks for unsigned execution. Hence, it MUST be cheap + /// with minimal to no storage reads. Else, it can make the blockchain vulnerable + /// to DoS attacks. fn is_valid(&self) -> bool; /// Performs the work for this particular `Task` variant. diff --git a/substrate/frame/support/src/traits/tokens.rs b/substrate/frame/support/src/traits/tokens.rs index 3635311e64357bbd2e7041d653a4268dfb65a182..8842b20580181f81e4377a0d9f6223e59a6fee6a 100644 --- a/substrate/frame/support/src/traits/tokens.rs +++ b/substrate/frame/support/src/traits/tokens.rs @@ -31,7 +31,7 @@ pub mod pay; pub use misc::{ AssetId, Balance, BalanceStatus, ConversionFromAssetBalance, ConversionToAssetBalance, ConvertRank, DepositConsequence, ExistenceRequirement, Fortitude, GetSalary, Locker, Precision, - Preservation, Provenance, Restriction, UnityAssetBalanceConversion, WithdrawConsequence, - WithdrawReasons, + Preservation, Provenance, Restriction, UnityAssetBalanceConversion, UnityOrOuterConversion, + WithdrawConsequence, WithdrawReasons, }; pub use pay::{Pay, PayFromAccount, PaymentStatus}; diff --git a/substrate/frame/support/src/traits/tokens/fungible/conformance_tests/inspect_mutate.rs b/substrate/frame/support/src/traits/tokens/fungible/conformance_tests/inspect_mutate.rs index 732742cca9b54aaf08b9bf42a1898709e556e693..fb52eb7037dbdbe3f0cbcfe66deb9c743ddf378d 100644 --- a/substrate/frame/support/src/traits/tokens/fungible/conformance_tests/inspect_mutate.rs +++ b/substrate/frame/support/src/traits/tokens/fungible/conformance_tests/inspect_mutate.rs @@ -166,9 +166,10 @@ where // Test: Burn an exact amount from the account let amount_to_burn = T::Balance::from(5); + let preservation = Preservation::Expendable; let precision = Precision::Exact; let force = Fortitude::Polite; - T::burn_from(&account, amount_to_burn, precision, force).unwrap(); + T::burn_from(&account, amount_to_burn, preservation, precision, force).unwrap(); // Verify: The balance and total issuance should be reduced by the burned amount assert_eq!(T::balance(&account), initial_balance - amount_to_burn); @@ -209,10 +210,11 @@ where // Test: Burn a best effort amount from the account that is greater than the reducible balance let amount_to_burn = reducible_balance + 5.into(); + let preservation = Preservation::Expendable; let precision = Precision::BestEffort; assert!(amount_to_burn > reducible_balance); assert!(amount_to_burn > T::balance(&account)); - T::burn_from(&account, amount_to_burn, precision, force).unwrap(); + T::burn_from(&account, amount_to_burn, preservation, precision, force).unwrap(); // Verify: The balance and total issuance should be reduced by the reducible_balance assert_eq!(T::balance(&account), initial_balance - reducible_balance); @@ -248,9 +250,10 @@ where // Verify: Burn an amount greater than the account's balance with Exact precision returns Err let amount_to_burn = initial_balance + 10.into(); + let preservation = Preservation::Expendable; let precision = Precision::Exact; let force = Fortitude::Polite; - T::burn_from(&account, amount_to_burn, precision, force).unwrap_err(); + T::burn_from(&account, amount_to_burn, preservation, precision, force).unwrap_err(); // Verify: The balance and total issuance should remain unchanged assert_eq!(T::balance(&account), initial_balance); diff --git a/substrate/frame/support/src/traits/tokens/fungible/conformance_tests/regular/mutate.rs b/substrate/frame/support/src/traits/tokens/fungible/conformance_tests/regular/mutate.rs index 95b5256bb4912269b9ad7c40ba637f966035c56b..b17ce6f518c0303058c6918f46a54e03d8c3188f 100644 --- a/substrate/frame/support/src/traits/tokens/fungible/conformance_tests/regular/mutate.rs +++ b/substrate/frame/support/src/traits/tokens/fungible/conformance_tests/regular/mutate.rs @@ -137,9 +137,10 @@ where // Test: Burn an exact amount from the account let amount_to_burn = T::Balance::from(5); + let preservation = Preservation::Expendable; let precision = Precision::Exact; let force = Fortitude::Polite; - T::burn_from(&account, amount_to_burn, precision, force).unwrap(); + T::burn_from(&account, amount_to_burn, preservation, precision, force).unwrap(); // Verify: The balance and total issuance should be reduced by the burned amount assert_eq!(T::balance(&account), initial_balance - amount_to_burn); @@ -174,10 +175,11 @@ where // Test: Burn a best effort amount from the account that is greater than the reducible // balance let amount_to_burn = reducible_balance + 5.into(); + let preservation = Preservation::Expendable; let precision = Precision::BestEffort; assert!(amount_to_burn > reducible_balance); assert!(amount_to_burn > T::balance(&account)); - T::burn_from(&account, amount_to_burn, precision, force).unwrap(); + T::burn_from(&account, amount_to_burn, preservation, precision, force).unwrap(); // Verify: The balance and total issuance should be reduced by the reducible_balance assert_eq!(T::balance(&account), initial_balance - reducible_balance); @@ -207,9 +209,10 @@ where // Verify: Burn an amount greater than the account's balance with Exact precision returns // Err let amount_to_burn = initial_balance + 10.into(); + let preservation = Preservation::Expendable; let precision = Precision::Exact; let force = Fortitude::Polite; - T::burn_from(&account, amount_to_burn, precision, force).unwrap_err(); + T::burn_from(&account, amount_to_burn, preservation, precision, force).unwrap_err(); // Verify: The balance and total issuance should remain unchanged assert_eq!(T::balance(&account), initial_balance); diff --git a/substrate/frame/support/src/traits/tokens/fungible/item_of.rs b/substrate/frame/support/src/traits/tokens/fungible/item_of.rs index 5374cc52bab72a25270606e89f97a6f035f3a704..2aa53d622dbff7280cb4f2b742f490249c73ca69 100644 --- a/substrate/frame/support/src/traits/tokens/fungible/item_of.rs +++ b/substrate/frame/support/src/traits/tokens/fungible/item_of.rs @@ -235,10 +235,18 @@ impl< fn burn_from( who: &AccountId, amount: Self::Balance, + preservation: Preservation, precision: Precision, force: Fortitude, ) -> Result { - >::burn_from(A::get(), who, amount, precision, force) + >::burn_from( + A::get(), + who, + amount, + preservation, + precision, + force, + ) } fn shelve(who: &AccountId, amount: Self::Balance) -> Result { >::shelve(A::get(), who, amount) diff --git a/substrate/frame/support/src/traits/tokens/fungible/regular.rs b/substrate/frame/support/src/traits/tokens/fungible/regular.rs index 4ed31dcf9fb1f099ebc576ae981d289613775b60..c46614be4734c659d50619fde3734a34be14783e 100644 --- a/substrate/frame/support/src/traits/tokens/fungible/regular.rs +++ b/substrate/frame/support/src/traits/tokens/fungible/regular.rs @@ -254,19 +254,23 @@ where Ok(actual) } - /// Decrease the balance of `who` by at least `amount`, possibly slightly more in the case of - /// minimum-balance requirements, burning the tokens. If that isn't possible then an `Err` is - /// returned and nothing is changed. If successful, the amount of tokens reduced is returned. + /// Attempt to decrease the balance of `who`, burning the tokens. + /// The actual amount burned is derived from the `amount`, `preservation`, `precision` and + /// `force`, and might end up being more, less or equal to the `amount` specified. + /// + /// If the burn isn't possible then an `Err` is returned and nothing is changed. + /// If successful, the amount of tokens reduced is returned. fn burn_from( who: &AccountId, amount: Self::Balance, + preservation: Preservation, precision: Precision, force: Fortitude, ) -> Result { - let actual = Self::reducible_balance(who, Expendable, force).min(amount); + let actual = Self::reducible_balance(who, preservation, force).min(amount); ensure!(actual == amount || precision == BestEffort, TokenError::FundsUnavailable); Self::total_issuance().checked_sub(&actual).ok_or(ArithmeticError::Overflow)?; - let actual = Self::decrease_balance(who, actual, BestEffort, Expendable, force)?; + let actual = Self::decrease_balance(who, actual, BestEffort, preservation, force)?; Self::set_total_issuance(Self::total_issuance().saturating_sub(actual)); Self::done_burn_from(who, actual); Ok(actual) @@ -342,7 +346,8 @@ where fn set_balance(who: &AccountId, amount: Self::Balance) -> Self::Balance { let b = Self::balance(who); if b > amount { - Self::burn_from(who, b - amount, BestEffort, Force).map(|d| b.saturating_sub(d)) + Self::burn_from(who, b - amount, Expendable, BestEffort, Force) + .map(|d| b.saturating_sub(d)) } else { Self::mint_into(who, amount - b).map(|d| b.saturating_add(d)) } diff --git a/substrate/frame/support/src/traits/tokens/fungible/union_of.rs b/substrate/frame/support/src/traits/tokens/fungible/union_of.rs index 575b771a614480147d5afe878dc71652d278bb67..63791b05223701ae8c689f00c4769cb510c6e208 100644 --- a/substrate/frame/support/src/traits/tokens/fungible/union_of.rs +++ b/substrate/frame/support/src/traits/tokens/fungible/union_of.rs @@ -442,14 +442,26 @@ impl< asset: Self::AssetId, who: &AccountId, amount: Self::Balance, + preservation: Preservation, precision: Precision, force: Fortitude, ) -> Result { match Criterion::convert(asset) { - Left(()) => - >::burn_from(who, amount, precision, force), - Right(a) => - >::burn_from(a, who, amount, precision, force), + Left(()) => >::burn_from( + who, + amount, + preservation, + precision, + force, + ), + Right(a) => >::burn_from( + a, + who, + amount, + preservation, + precision, + force, + ), } } fn shelve( @@ -925,3 +937,28 @@ impl< } } } + +impl< + Left: fungible::Inspect, + Right: fungibles::Inspect + fungibles::Refund, + Criterion: Convert>::AssetId>>, + AssetKind: AssetId, + AccountId, + > fungibles::Refund for UnionOf +{ + type AssetId = AssetKind; + type Balance = >::Balance; + + fn deposit_held(asset: AssetKind, who: AccountId) -> Option<(AccountId, Self::Balance)> { + match Criterion::convert(asset) { + Left(()) => None, + Right(a) => >::deposit_held(a, who), + } + } + fn refund(asset: AssetKind, who: AccountId) -> DispatchResult { + match Criterion::convert(asset) { + Left(()) => Err(DispatchError::Unavailable), + Right(a) => >::refund(a, who), + } + } +} diff --git a/substrate/frame/support/src/traits/tokens/fungibles/lifetime.rs b/substrate/frame/support/src/traits/tokens/fungibles/lifetime.rs index 49f6c846ccdd54adeceb668bb10a8cb2ca11281f..7f882c1fc4fe84875c7172664c4720e7c70aed37 100644 --- a/substrate/frame/support/src/traits/tokens/fungibles/lifetime.rs +++ b/substrate/frame/support/src/traits/tokens/fungibles/lifetime.rs @@ -15,13 +15,13 @@ // See the License for the specific language governing permissions and // limitations under the License. -//! Traits for creating and destroying assets. +//! Traits for creating, editing and destroying assets. //! //! See the [`crate::traits::fungibles`] doc for more information about fungibles traits. -use sp_runtime::{DispatchError, DispatchResult}; - use super::Inspect; +use crate::traits::tokens::{AssetId, Balance}; +use sp_runtime::{DispatchError, DispatchResult}; /// Trait for providing the ability to create new fungible assets. pub trait Create: Inspect { @@ -34,6 +34,22 @@ pub trait Create: Inspect { ) -> DispatchResult; } +/// Trait for refunding the existence deposit of a target asset account. +/// +/// The existence deposit might by necessary and present in cases where the asset held by the +/// account is insufficient for the required storage, or when the system cannot provide a consumer +/// reference for any reason. +pub trait Refund { + /// Means of identifying one asset class from another. + type AssetId: AssetId; + /// Scalar type for representing deposit balance of an account. + type Balance: Balance; + /// Returns the amount of account deposit and depositor address, if any. + fn deposit_held(id: Self::AssetId, who: AccountId) -> Option<(AccountId, Self::Balance)>; + /// Return the deposit (if any) of a target asset account. + fn refund(id: Self::AssetId, who: AccountId) -> DispatchResult; +} + /// Trait for providing the ability to destroy existing fungible assets. pub trait Destroy: Inspect { /// Start the destruction an existing fungible asset. diff --git a/substrate/frame/support/src/traits/tokens/fungibles/mod.rs b/substrate/frame/support/src/traits/tokens/fungibles/mod.rs index 2122fdeaed3f28b937fa16a2230fa0f9a56d869a..8b4ea4d13cf9d108558ecf6461f83014148f35fd 100644 --- a/substrate/frame/support/src/traits/tokens/fungibles/mod.rs +++ b/substrate/frame/support/src/traits/tokens/fungibles/mod.rs @@ -44,7 +44,7 @@ pub use hold::{ Unbalanced as UnbalancedHold, }; pub use imbalance::{Credit, Debt, HandleImbalanceDrop, Imbalance}; -pub use lifetime::{Create, Destroy}; +pub use lifetime::{Create, Destroy, Refund}; pub use regular::{ Balanced, DecreaseIssuance, Dust, IncreaseIssuance, Inspect, Mutate, Unbalanced, }; diff --git a/substrate/frame/support/src/traits/tokens/fungibles/regular.rs b/substrate/frame/support/src/traits/tokens/fungibles/regular.rs index b30e0ae3a2a3657c1a2685fa413ff120803ae187..946c4756cff6035a7619cf859cb1d71d520b4298 100644 --- a/substrate/frame/support/src/traits/tokens/fungibles/regular.rs +++ b/substrate/frame/support/src/traits/tokens/fungibles/regular.rs @@ -283,16 +283,17 @@ where asset: Self::AssetId, who: &AccountId, amount: Self::Balance, + preservation: Preservation, precision: Precision, force: Fortitude, ) -> Result { - let actual = Self::reducible_balance(asset.clone(), who, Expendable, force).min(amount); + let actual = Self::reducible_balance(asset.clone(), who, preservation, force).min(amount); ensure!(actual == amount || precision == BestEffort, TokenError::FundsUnavailable); Self::total_issuance(asset.clone()) .checked_sub(&actual) .ok_or(ArithmeticError::Overflow)?; let actual = - Self::decrease_balance(asset.clone(), who, actual, BestEffort, Expendable, force)?; + Self::decrease_balance(asset.clone(), who, actual, BestEffort, preservation, force)?; Self::set_total_issuance( asset.clone(), Self::total_issuance(asset.clone()).saturating_sub(actual), @@ -392,7 +393,8 @@ where fn set_balance(asset: Self::AssetId, who: &AccountId, amount: Self::Balance) -> Self::Balance { let b = Self::balance(asset.clone(), who); if b > amount { - Self::burn_from(asset, who, b - amount, BestEffort, Force).map(|d| b.saturating_sub(d)) + Self::burn_from(asset, who, b - amount, Expendable, BestEffort, Force) + .map(|d| b.saturating_sub(d)) } else { Self::mint_into(asset, who, amount - b).map(|d| b.saturating_add(d)) } diff --git a/substrate/frame/support/src/traits/tokens/fungibles/roles.rs b/substrate/frame/support/src/traits/tokens/fungibles/roles.rs index 4f95ad8368c2c555e1a07f1f1b8b9ede7cf574cb..3e68d6b94518d36fd609b5e481bf5ed1702fde6a 100644 --- a/substrate/frame/support/src/traits/tokens/fungibles/roles.rs +++ b/substrate/frame/support/src/traits/tokens/fungibles/roles.rs @@ -19,6 +19,8 @@ //! //! See the [`crate::traits::fungibles`] doc for more information about fungibles traits. +use sp_runtime::DispatchResult; + pub trait Inspect: super::Inspect { // Get owner for an AssetId. fn owner(asset: Self::AssetId) -> Option; @@ -29,3 +31,22 @@ pub trait Inspect: super::Inspect { // Get freezer for an AssetId. fn freezer(asset: Self::AssetId) -> Option; } + +/// Trait for resetting the team configuration of an existing fungible asset. +pub trait ResetTeam: super::Inspect { + /// Reset the team for the asset with the given `id`. + /// + /// ### Parameters + /// - `id`: The identifier of the asset for which the team is being reset. + /// - `owner`: The new `owner` account for the asset. + /// - `admin`: The new `admin` account for the asset. + /// - `issuer`: The new `issuer` account for the asset. + /// - `freezer`: The new `freezer` account for the asset. + fn reset_team( + id: Self::AssetId, + owner: AccountId, + admin: AccountId, + issuer: AccountId, + freezer: AccountId, + ) -> DispatchResult; +} diff --git a/substrate/frame/support/src/traits/tokens/fungibles/union_of.rs b/substrate/frame/support/src/traits/tokens/fungibles/union_of.rs index c8a1ec37e78184f36342acefd65dd1815792b257..f4259a78f0a25ae15c7413be07df0bc299342122 100644 --- a/substrate/frame/support/src/traits/tokens/fungibles/union_of.rs +++ b/substrate/frame/support/src/traits/tokens/fungibles/union_of.rs @@ -389,14 +389,27 @@ impl< asset: Self::AssetId, who: &AccountId, amount: Self::Balance, + preservation: Preservation, precision: Precision, force: Fortitude, ) -> Result { match Criterion::convert(asset) { - Left(a) => - >::burn_from(a, who, amount, precision, force), - Right(a) => - >::burn_from(a, who, amount, precision, force), + Left(a) => >::burn_from( + a, + who, + amount, + preservation, + precision, + force, + ), + Right(a) => >::burn_from( + a, + who, + amount, + preservation, + precision, + force, + ), } } fn shelve( @@ -904,3 +917,35 @@ impl< } } } + +impl< + Left: fungibles::Inspect + fungibles::Refund, + Right: fungibles::Inspect + + fungibles::Refund>::Balance>, + Criterion: Convert< + AssetKind, + Either< + >::AssetId, + >::AssetId, + >, + >, + AssetKind: AssetId, + AccountId, + > fungibles::Refund for UnionOf +{ + type AssetId = AssetKind; + type Balance = >::Balance; + + fn deposit_held(asset: AssetKind, who: AccountId) -> Option<(AccountId, Self::Balance)> { + match Criterion::convert(asset) { + Left(a) => >::deposit_held(a, who), + Right(a) => >::deposit_held(a, who), + } + } + fn refund(asset: AssetKind, who: AccountId) -> DispatchResult { + match Criterion::convert(asset) { + Left(a) => >::refund(a, who), + Right(a) => >::refund(a, who), + } + } +} diff --git a/substrate/frame/support/src/traits/tokens/misc.rs b/substrate/frame/support/src/traits/tokens/misc.rs index a4dd5e4914283e6da028aac038cecee501a2228f..424acb1d550b15b69582d004e2e466e65e6a9b3f 100644 --- a/substrate/frame/support/src/traits/tokens/misc.rs +++ b/substrate/frame/support/src/traits/tokens/misc.rs @@ -17,6 +17,7 @@ //! Miscellaneous types. +use crate::traits::Contains; use codec::{Decode, Encode, FullCodec, MaxEncodedLen}; use sp_arithmetic::traits::{AtLeast32BitUnsigned, Zero}; use sp_core::RuntimeDebug; @@ -299,6 +300,33 @@ where fn ensure_successful(_: AssetId) {} } +/// Implements [`ConversionFromAssetBalance`], allowing for a 1:1 balance conversion of the asset +/// when it meets the conditions specified by `C`. If the conditions are not met, the conversion is +/// delegated to `O`. +pub struct UnityOrOuterConversion(core::marker::PhantomData<(C, O)>); +impl + ConversionFromAssetBalance for UnityOrOuterConversion +where + C: Contains, + O: ConversionFromAssetBalance, + AssetBalance: Into, +{ + type Error = O::Error; + fn from_asset_balance( + balance: AssetBalance, + asset_id: AssetId, + ) -> Result { + if C::contains(&asset_id) { + return Ok(balance.into()); + } + O::from_asset_balance(balance, asset_id) + } + #[cfg(feature = "runtime-benchmarks")] + fn ensure_successful(asset_id: AssetId) { + O::ensure_successful(asset_id) + } +} + /// Trait to handle NFT locking mechanism to ensure interactions with the asset can be implemented /// downstream to extend logic of Uniques/Nfts current functionality. pub trait Locker { diff --git a/substrate/frame/support/src/traits/try_runtime/mod.rs b/substrate/frame/support/src/traits/try_runtime/mod.rs index bec2dbf549a111b8b5caad19764fb827a619d194..c1bf1feb19e54fe3c94abfb242e9f2321d43d0df 100644 --- a/substrate/frame/support/src/traits/try_runtime/mod.rs +++ b/substrate/frame/support/src/traits/try_runtime/mod.rs @@ -161,22 +161,31 @@ impl TryState Ok(()), Select::All => { - let mut error_count = 0; + let mut errors = Vec::::new(); + for_tuples!(#( - if let Err(_) = Tuple::try_state(n.clone(), targets.clone()) { - error_count += 1; + if let Err(err) = Tuple::try_state(n.clone(), targets.clone()) { + errors.push(err); } )*); - if error_count > 0 { + if !errors.is_empty() { log::error!( target: "try-runtime", - "{} pallets exited with errors while executing try_state checks.", - error_count + "Detected errors while executing `try_state`:", ); + errors.iter().for_each(|err| { + log::error!( + target: "try-runtime", + "{:?}", + err + ); + }); + return Err( - "Detected errors while executing try_state checks. See logs for more info." + "Detected errors while executing `try_state` checks. See logs for more \ + info." .into(), ) } diff --git a/substrate/frame/support/test/Cargo.toml b/substrate/frame/support/test/Cargo.toml index 88124e0a43b9cc10438e01e44d98e9f9130ca56c..6e861ad769cf71d0c1200b2039f28217a558b335 100644 --- a/substrate/frame/support/test/Cargo.toml +++ b/substrate/frame/support/test/Cargo.toml @@ -17,7 +17,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] static_assertions = "1.1.0" serde = { features = ["derive"], workspace = true } -codec = { package = "parity-scale-codec", version = "3.6.1", default-features = false, features = ["derive"] } +codec = { package = "parity-scale-codec", version = "3.6.12", default-features = false, features = ["derive"] } scale-info = { version = "2.11.1", default-features = false, features = ["derive"] } frame-metadata = { version = "16.0.0", default-features = false, features = ["current"] } sp-api = { path = "../../../primitives/api", default-features = false } diff --git a/substrate/frame/support/test/compile_pass/Cargo.toml b/substrate/frame/support/test/compile_pass/Cargo.toml index 3f52b4664b187675afd7bd13c4c96db62523a73b..37c069247e1875b547baa047c71a7895c686abe6 100644 --- a/substrate/frame/support/test/compile_pass/Cargo.toml +++ b/substrate/frame/support/test/compile_pass/Cargo.toml @@ -15,7 +15,7 @@ workspace = true targets = ["x86_64-unknown-linux-gnu"] [dependencies] -codec = { package = "parity-scale-codec", version = "3.6.1", default-features = false, features = ["derive"] } +codec = { package = "parity-scale-codec", version = "3.6.12", default-features = false, features = ["derive"] } scale-info = { version = "2.11.1", default-features = false, features = ["derive"] } renamed-frame-support = { package = "frame-support", path = "../..", default-features = false } renamed-frame-system = { package = "frame-system", path = "../../../system", default-features = false } diff --git a/substrate/frame/support/test/pallet/Cargo.toml b/substrate/frame/support/test/pallet/Cargo.toml index 7a20c3f2730629e709eb78c650b0ca4ca0d3e964..8607339a2b054530404499c23a402c2a673e2b5a 100644 --- a/substrate/frame/support/test/pallet/Cargo.toml +++ b/substrate/frame/support/test/pallet/Cargo.toml @@ -15,7 +15,7 @@ workspace = true targets = ["x86_64-unknown-linux-gnu"] [dependencies] -codec = { package = "parity-scale-codec", version = "3.6.1", default-features = false, features = ["derive"] } +codec = { package = "parity-scale-codec", version = "3.6.12", default-features = false, features = ["derive"] } scale-info = { version = "2.11.1", default-features = false, features = ["derive"] } serde = { features = ["derive"], workspace = true } frame-support = { path = "../..", default-features = false } diff --git a/substrate/frame/support/test/stg_frame_crate/Cargo.toml b/substrate/frame/support/test/stg_frame_crate/Cargo.toml index 554c81ab43decf222b516bf8bbd7660cab399eaf..5b97db60c00bb7c8b5b40dfa9f823fcc27b73d95 100644 --- a/substrate/frame/support/test/stg_frame_crate/Cargo.toml +++ b/substrate/frame/support/test/stg_frame_crate/Cargo.toml @@ -15,7 +15,7 @@ workspace = true targets = ["x86_64-unknown-linux-gnu"] [dependencies] -codec = { package = "parity-scale-codec", version = "3.6.1", default-features = false, features = ["derive"] } +codec = { package = "parity-scale-codec", version = "3.6.12", default-features = false, features = ["derive"] } frame = { package = "polkadot-sdk-frame", path = "../../..", default-features = false, features = ["experimental", "runtime"] } scale-info = { version = "2.11.1", default-features = false, features = ["derive"] } diff --git a/substrate/frame/support/test/tests/benchmark_ui/invalid_origin.stderr b/substrate/frame/support/test/tests/benchmark_ui/invalid_origin.stderr index 87d4f476a60d1be358a31f965d9d01772082e450..30f1289767fc54ca55c5d64125eea402e84344c3 100644 --- a/substrate/frame/support/test/tests/benchmark_ui/invalid_origin.stderr +++ b/substrate/frame/support/test/tests/benchmark_ui/invalid_origin.stderr @@ -2,7 +2,7 @@ error[E0277]: the trait bound `::RuntimeOrigin: --> tests/benchmark_ui/invalid_origin.rs:23:1 | 23 | #[benchmarks] - | ^^^^^^^^^^^^^ the trait `From<{integer}>` is not implemented for `::RuntimeOrigin` + | ^^^^^^^^^^^^^ the trait `From<{integer}>` is not implemented for `::RuntimeOrigin`, which is required by `{integer}: Into<_>` | = note: required for `{integer}` to implement `Into<::RuntimeOrigin>` = note: this error originates in the attribute macro `benchmarks` (in Nightly builds, run with -Z macro-backtrace for more info) 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 09c4d290ef5c3d49d244648242e6324d4cf760e5..b28cae2ddefab062666fc6ba1334deb2b02ce9a8 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 @@ -23,133 +23,139 @@ error: use of deprecated constant `WhereSection::_w`: error[E0277]: the trait bound `Runtime: Config` is not satisfied --> tests/construct_runtime_ui/deprecated_where_block.rs:20:1 | -20 | // construct_runtime! { -21 | || pub struct Runtime where -22 | || Block = Block, -23 | || NodeBlock = Block, -... || -27 | || } -28 | || } - | ||_- in this macro invocation +20 | / construct_runtime! { +21 | | pub struct Runtime where +22 | | Block = Block, +23 | | NodeBlock = Block, ... | +27 | | } +28 | | } + | |_^ the trait `Config` is not implemented for `Runtime` + | + = note: this error originates in the macro `frame_support::construct_runtime` (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0277]: the trait bound `Runtime: Config` is not satisfied + --> tests/construct_runtime_ui/deprecated_where_block.rs:20:1 + | +20 | / construct_runtime! { +21 | | pub struct Runtime where +22 | | Block = Block, +23 | | NodeBlock = Block, +... | +27 | | } +28 | | } + | |_^ the trait `Config` is not implemented for `Runtime` | note: required by a bound in `frame_system::Event` --> $WORKSPACE/substrate/frame/system/src/lib.rs | | pub enum Event { | ^^^^^^ required by this bound in `Event` - = note: this error originates in the macro `frame_support::construct_runtime` which comes from the expansion of the macro `construct_runtime` (in Nightly builds, run with -Z macro-backtrace for more info) + = note: this error originates in the macro `frame_support::construct_runtime` (in Nightly builds, run with -Z macro-backtrace for more info) error[E0277]: the trait bound `Runtime: Config` is not satisfied in `RuntimeEvent` --> tests/construct_runtime_ui/deprecated_where_block.rs:20:1 | -20 | // construct_runtime! { -21 | || pub struct Runtime where -22 | || Block = Block, -23 | || NodeBlock = Block, -... || -27 | || } -28 | || } - | ||_- in this macro invocation +20 | / construct_runtime! { +21 | | pub struct Runtime where +22 | | Block = Block, +23 | | NodeBlock = Block, ... | +27 | | } +28 | | } + | |_^ within `RuntimeEvent`, the trait `Config` is not implemented for `Runtime`, which is required by `RuntimeEvent: Sized` | note: required because it appears within the type `RuntimeEvent` --> tests/construct_runtime_ui/deprecated_where_block.rs:20:1 | -20 | // construct_runtime! { -21 | || pub struct Runtime where -22 | || Block = Block, -23 | || NodeBlock = Block, -... || -27 | || } -28 | || } - | ||_- in this macro invocation +20 | / construct_runtime! { +21 | | pub struct Runtime where +22 | | Block = Block, +23 | | NodeBlock = Block, ... | +27 | | } +28 | | } + | |_^ note: required by a bound in `Clone` --> $RUST/core/src/clone.rs | | pub trait Clone: Sized { | ^^^^^ required by this bound in `Clone` - = note: this error originates in the derive macro `Clone` which comes from the expansion of the macro `construct_runtime` (in Nightly builds, run with -Z macro-backtrace for more info) + = note: this error originates in the derive macro `Clone` which comes from the expansion of the macro `frame_support::construct_runtime` (in Nightly builds, run with -Z macro-backtrace for more info) error[E0277]: the trait bound `Runtime: Config` is not satisfied in `RuntimeEvent` --> tests/construct_runtime_ui/deprecated_where_block.rs:20:1 | -20 | // construct_runtime! { -21 | || pub struct Runtime where -22 | || Block = Block, -23 | || NodeBlock = Block, -... || -27 | || } -28 | || } - | ||_- in this macro invocation +20 | / construct_runtime! { +21 | | pub struct Runtime where +22 | | Block = Block, +23 | | NodeBlock = Block, ... | +27 | | } +28 | | } + | |_^ within `RuntimeEvent`, the trait `Config` is not implemented for `Runtime`, which is required by `RuntimeEvent: Sized` | note: required because it appears within the type `RuntimeEvent` --> tests/construct_runtime_ui/deprecated_where_block.rs:20:1 | -20 | // construct_runtime! { -21 | || pub struct Runtime where -22 | || Block = Block, -23 | || NodeBlock = Block, -... || -27 | || } -28 | || } - | ||_- in this macro invocation +20 | / construct_runtime! { +21 | | pub struct Runtime where +22 | | Block = Block, +23 | | NodeBlock = Block, ... | +27 | | } +28 | | } + | |_^ note: required by a bound in `EncodeLike` - --> $CARGO/parity-scale-codec-3.6.5/src/encode_like.rs + --> $CARGO/parity-scale-codec-3.6.12/src/encode_like.rs | | pub trait EncodeLike: Sized + Encode {} | ^^^^^ required by this bound in `EncodeLike` - = note: this error originates in the macro `frame_support::construct_runtime` which comes from the expansion of the macro `construct_runtime` (in Nightly builds, run with -Z macro-backtrace for more info) + = note: this error originates in the macro `frame_support::construct_runtime` (in Nightly builds, run with -Z macro-backtrace for more info) error[E0277]: the trait bound `Runtime: Config` is not satisfied in `RuntimeEvent` --> tests/construct_runtime_ui/deprecated_where_block.rs:20:1 | -20 | // construct_runtime! { -21 | || pub struct Runtime where -22 | || Block = Block, -23 | || NodeBlock = Block, -... || -27 | || } -28 | || } - | ||_- in this macro invocation +20 | / construct_runtime! { +21 | | pub struct Runtime where +22 | | Block = Block, +23 | | NodeBlock = Block, ... | +27 | | } +28 | | } + | |_^ within `RuntimeEvent`, the trait `Config` is not implemented for `Runtime`, which is required by `RuntimeEvent: Sized` | note: required because it appears within the type `RuntimeEvent` --> tests/construct_runtime_ui/deprecated_where_block.rs:20:1 | -20 | // construct_runtime! { -21 | || pub struct Runtime where -22 | || Block = Block, -23 | || NodeBlock = Block, -... || -27 | || } -28 | || } - | ||_- in this macro invocation +20 | / construct_runtime! { +21 | | pub struct Runtime where +22 | | Block = Block, +23 | | NodeBlock = Block, ... | +27 | | } +28 | | } + | |_^ note: required by a bound in `Decode` - --> $CARGO/parity-scale-codec-3.6.5/src/codec.rs + --> $CARGO/parity-scale-codec-3.6.12/src/codec.rs | | pub trait Decode: Sized { | ^^^^^ required by this bound in `Decode` - = note: this error originates in the macro `frame_support::construct_runtime` which comes from the expansion of the macro `construct_runtime` (in Nightly builds, run with -Z macro-backtrace for more info) + = note: this error originates in the macro `frame_support::construct_runtime` (in Nightly builds, run with -Z macro-backtrace for more info) error[E0277]: the trait bound `Runtime: Config` is not satisfied in `frame_system::Event` --> tests/construct_runtime_ui/deprecated_where_block.rs:20:1 | -20 | // construct_runtime! { -21 | || pub struct Runtime where -22 | || Block = Block, -23 | || NodeBlock = Block, -... || -27 | || } -28 | || } - | ||_- in this macro invocation +20 | / construct_runtime! { +21 | | pub struct Runtime where +22 | | Block = Block, +23 | | NodeBlock = Block, ... | +27 | | } +28 | | } + | |_^ within `frame_system::Event`, the trait `Config` is not implemented for `Runtime`, which is required by `frame_system::Event: Sized` | -note: required because it appears within the type `Event` +note: required because it appears within the type `frame_system::Event` --> $WORKSPACE/substrate/frame/system/src/lib.rs | | pub enum Event { @@ -159,22 +165,21 @@ note: required by a bound in `From` | | pub trait From: Sized { | ^ required by this bound in `From` - = note: this error originates in the macro `frame_support::construct_runtime` which comes from the expansion of the macro `construct_runtime` (in Nightly builds, run with -Z macro-backtrace for more info) + = note: this error originates in the macro `frame_support::construct_runtime` (in Nightly builds, run with -Z macro-backtrace for more info) error[E0277]: the trait bound `Runtime: Config` is not satisfied in `frame_system::Event` --> tests/construct_runtime_ui/deprecated_where_block.rs:20:1 | -20 | // construct_runtime! { -21 | || pub struct Runtime where -22 | || Block = Block, -23 | || NodeBlock = Block, -... || -27 | || } -28 | || } - | ||_- in this macro invocation +20 | / construct_runtime! { +21 | | pub struct Runtime where +22 | | Block = Block, +23 | | NodeBlock = Block, ... | +27 | | } +28 | | } + | |_^ within `frame_system::Event`, the trait `Config` is not implemented for `Runtime`, which is required by `frame_system::Event: Sized` | -note: required because it appears within the type `Event` +note: required because it appears within the type `frame_system::Event` --> $WORKSPACE/substrate/frame/system/src/lib.rs | | pub enum Event { @@ -184,22 +189,7 @@ note: required by a bound in `TryInto` | | pub trait TryInto: Sized { | ^ required by this bound in `TryInto` - = note: this error originates in the macro `frame_support::construct_runtime` which comes from the expansion of the macro `construct_runtime` (in Nightly builds, run with -Z macro-backtrace for more info) - -error[E0277]: the trait bound `Runtime: Config` is not satisfied - --> tests/construct_runtime_ui/deprecated_where_block.rs:20:1 - | -20 | // construct_runtime! { -21 | || pub struct Runtime where -22 | || Block = Block, -23 | || NodeBlock = Block, -... || -27 | || } -28 | || } - | ||_- in this macro invocation -... | - | - = note: this error originates in the macro `frame_support::construct_runtime` which comes from the expansion of the macro `construct_runtime` (in Nightly builds, run with -Z macro-backtrace for more info) + = note: this error originates in the macro `frame_support::construct_runtime` (in Nightly builds, run with -Z macro-backtrace for more info) error[E0277]: the trait bound `Runtime: Config` is not satisfied --> tests/construct_runtime_ui/deprecated_where_block.rs:20:1 @@ -212,134 +202,157 @@ error[E0277]: the trait bound `Runtime: Config` is not satisfied error[E0277]: the trait bound `RawOrigin<_>: TryFrom` is not satisfied --> tests/construct_runtime_ui/deprecated_where_block.rs:20:1 | -20 | // construct_runtime! { -21 | || pub struct Runtime where -22 | || Block = Block, -23 | || NodeBlock = Block, -... || -27 | || } -28 | || } - | ||_- in this macro invocation +20 | / construct_runtime! { +21 | | pub struct Runtime where +22 | | Block = Block, +23 | | NodeBlock = Block, ... | +27 | | } +28 | | } + | |_^ the trait `TryFrom` is not implemented for `RawOrigin<_>` | = help: the trait `TryFrom` is implemented for `RawOrigin<::AccountId>` - = note: this error originates in the macro `frame_support::construct_runtime` which comes from the expansion of the macro `construct_runtime` (in Nightly builds, run with -Z macro-backtrace for more info) + = note: this error originates in the macro `frame_support::construct_runtime` (in Nightly builds, run with -Z macro-backtrace for more info) error[E0277]: the trait bound `Runtime: Config` is not satisfied --> tests/construct_runtime_ui/deprecated_where_block.rs:20:1 | -20 | // construct_runtime! { -21 | || pub struct Runtime where -22 | || Block = Block, -23 | || NodeBlock = Block, -... || -27 | || } -28 | || } - | ||_- in this macro invocation +20 | / construct_runtime! { +21 | | pub struct Runtime where +22 | | Block = Block, +23 | | NodeBlock = Block, ... | +27 | | } +28 | | } + | |_^ the trait `Config` is not implemented for `Runtime`, which is required by `Pallet: Callable` | = help: the trait `Callable` is implemented for `Pallet` = note: required for `Pallet` to implement `Callable` - = note: this error originates in the macro `frame_support::construct_runtime` which comes from the expansion of the macro `construct_runtime` (in Nightly builds, run with -Z macro-backtrace for more info) + = note: this error originates in the macro `frame_support::construct_runtime` (in Nightly builds, run with -Z macro-backtrace for more info) error[E0277]: the trait bound `Runtime: Config` is not satisfied --> tests/construct_runtime_ui/deprecated_where_block.rs:20:1 | -20 | // construct_runtime! { -21 | || pub struct Runtime where -22 | || Block = Block, -23 | || NodeBlock = Block, -... || -27 | || } -28 | || } - | ||_- in this macro invocation +20 | / construct_runtime! { +21 | | pub struct Runtime where +22 | | Block = Block, +23 | | NodeBlock = Block, ... | +27 | | } +28 | | } + | |_^ the trait `Config` is not implemented for `Runtime`, which is required by `RuntimeCall: Sized` | = note: required for `Pallet` to implement `Callable` note: required because it appears within the type `RuntimeCall` --> tests/construct_runtime_ui/deprecated_where_block.rs:20:1 | -20 | // construct_runtime! { -21 | || pub struct Runtime where -22 | || Block = Block, -23 | || NodeBlock = Block, -... || -27 | || } -28 | || } - | ||_- in this macro invocation +20 | / construct_runtime! { +21 | | pub struct Runtime where +22 | | Block = Block, +23 | | NodeBlock = Block, ... | +27 | | } +28 | | } + | |_^ note: required by a bound in `Clone` --> $RUST/core/src/clone.rs | | pub trait Clone: Sized { | ^^^^^ required by this bound in `Clone` - = note: this error originates in the derive macro `Clone` which comes from the expansion of the macro `construct_runtime` (in Nightly builds, run with -Z macro-backtrace for more info) + = note: this error originates in the derive macro `Clone` which comes from the expansion of the macro `frame_support::construct_runtime` (in Nightly builds, run with -Z macro-backtrace for more info) error[E0277]: the trait bound `Runtime: Config` is not satisfied --> tests/construct_runtime_ui/deprecated_where_block.rs:20:1 | -20 | // construct_runtime! { -21 | || pub struct Runtime where -22 | || Block = Block, -23 | || NodeBlock = Block, -... || -27 | || } -28 | || } - | ||_- in this macro invocation +20 | / construct_runtime! { +21 | | pub struct Runtime where +22 | | Block = Block, +23 | | NodeBlock = Block, ... | +27 | | } +28 | | } + | |_^ the trait `Config` is not implemented for `Runtime`, which is required by `RuntimeCall: Sized` | = note: required for `Pallet` to implement `Callable` note: required because it appears within the type `RuntimeCall` --> tests/construct_runtime_ui/deprecated_where_block.rs:20:1 | -20 | // construct_runtime! { -21 | || pub struct Runtime where -22 | || Block = Block, -23 | || NodeBlock = Block, -... || -27 | || } -28 | || } - | ||_- in this macro invocation +20 | / construct_runtime! { +21 | | pub struct Runtime where +22 | | Block = Block, +23 | | NodeBlock = Block, ... | +27 | | } +28 | | } + | |_^ note: required by a bound in `EncodeLike` - --> $CARGO/parity-scale-codec-3.6.5/src/encode_like.rs + --> $CARGO/parity-scale-codec-3.6.12/src/encode_like.rs | | pub trait EncodeLike: Sized + Encode {} | ^^^^^ required by this bound in `EncodeLike` - = note: this error originates in the macro `frame_support::construct_runtime` which comes from the expansion of the macro `construct_runtime` (in Nightly builds, run with -Z macro-backtrace for more info) + = note: this error originates in the macro `frame_support::construct_runtime` (in Nightly builds, run with -Z macro-backtrace for more info) error[E0277]: the trait bound `Runtime: Config` is not satisfied --> tests/construct_runtime_ui/deprecated_where_block.rs:20:1 | -20 | // construct_runtime! { -21 | || pub struct Runtime where -22 | || Block = Block, -23 | || NodeBlock = Block, -... || -27 | || } -28 | || } - | ||_- in this macro invocation +20 | / construct_runtime! { +21 | | pub struct Runtime where +22 | | Block = Block, +23 | | NodeBlock = Block, ... | +27 | | } +28 | | } + | |_^ the trait `Config` is not implemented for `Runtime`, which is required by `RuntimeCall: Sized` | = note: required for `Pallet` to implement `Callable` note: required because it appears within the type `RuntimeCall` --> tests/construct_runtime_ui/deprecated_where_block.rs:20:1 | -20 | // construct_runtime! { -21 | || pub struct Runtime where -22 | || Block = Block, -23 | || NodeBlock = Block, -... || -27 | || } -28 | || } - | ||_- in this macro invocation +20 | / construct_runtime! { +21 | | pub struct Runtime where +22 | | Block = Block, +23 | | NodeBlock = Block, ... | +27 | | } +28 | | } + | |_^ note: required by a bound in `Decode` - --> $CARGO/parity-scale-codec-3.6.5/src/codec.rs + --> $CARGO/parity-scale-codec-3.6.12/src/codec.rs | | pub trait Decode: Sized { | ^^^^^ required by this bound in `Decode` - = note: this error originates in the macro `frame_support::construct_runtime` which comes from the expansion of the macro `construct_runtime` (in Nightly builds, run with -Z macro-backtrace for more info) + = note: this error originates in the macro `frame_support::construct_runtime` (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0277]: the trait bound `Runtime: Config` is not satisfied + --> tests/construct_runtime_ui/deprecated_where_block.rs:20:1 + | +20 | / construct_runtime! { +21 | | pub struct Runtime where +22 | | Block = Block, +23 | | NodeBlock = Block, +... | +27 | | } +28 | | } + | |_^ the trait `Config` is not implemented for `Runtime`, which is required by `RuntimeCall: Sized` + | + = note: required for `Pallet` to implement `Callable` +note: required because it appears within the type `RuntimeCall` + --> tests/construct_runtime_ui/deprecated_where_block.rs:20:1 + | +20 | / construct_runtime! { +21 | | pub struct Runtime where +22 | | Block = Block, +23 | | NodeBlock = Block, +... | +27 | | } +28 | | } + | |_^ +note: required by a bound in `frame_support::sp_runtime::traits::Dispatchable::Config` + --> $WORKSPACE/substrate/primitives/runtime/src/traits.rs + | + | type Config; + | ^^^^^^^^^^^^ required by this bound in `Dispatchable::Config` + = note: this error originates in the macro `frame_support::construct_runtime` (in Nightly builds, run with -Z macro-backtrace for more info) error[E0277]: the trait bound `Runtime: Config` is not satisfied --> tests/construct_runtime_ui/deprecated_where_block.rs:26:3 @@ -353,165 +366,124 @@ note: required by a bound in `GenesisConfig` | pub struct GenesisConfig { | ^^^^^^ required by this bound in `GenesisConfig` +error[E0277]: the trait bound `Runtime: Config` is not satisfied + --> tests/construct_runtime_ui/deprecated_where_block.rs:20:1 + | +20 | / construct_runtime! { +21 | | pub struct Runtime where +22 | | Block = Block, +23 | | NodeBlock = Block, +... | +27 | | } +28 | | } + | |_^ the trait `Config` is not implemented for `Runtime`, which is required by `RuntimeCall: Sized` + | + = note: required for `Pallet` to implement `Callable` +note: required because it appears within the type `RuntimeCall` + --> tests/construct_runtime_ui/deprecated_where_block.rs:20:1 + | +20 | / construct_runtime! { +21 | | pub struct Runtime where +22 | | Block = Block, +23 | | NodeBlock = Block, +... | +27 | | } +28 | | } + | |_^ +note: required by a bound in `frame_support::pallet_prelude::ValidateUnsigned::Call` + --> $WORKSPACE/substrate/primitives/runtime/src/traits.rs + | + | type Call; + | ^^^^^^^^^^ required by this bound in `ValidateUnsigned::Call` + = note: this error originates in the macro `frame_support::construct_runtime` (in Nightly builds, run with -Z macro-backtrace for more info) + error[E0277]: the trait bound `Runtime: Config` is not satisfied in `RuntimeEvent` --> tests/construct_runtime_ui/deprecated_where_block.rs:20:1 | -20 | // construct_runtime! { -21 | || pub struct Runtime where -22 | || Block = Block, -23 | || NodeBlock = Block, -... || -27 | || } -28 | || } - | ||_- in this macro invocation +20 | / construct_runtime! { +21 | | pub struct Runtime where +22 | | Block = Block, +23 | | NodeBlock = Block, ... | +27 | | } +28 | | } + | |_^ within `RuntimeEvent`, the trait `Config` is not implemented for `Runtime`, which is required by `RuntimeEvent: Sized` | note: required because it appears within the type `RuntimeEvent` --> tests/construct_runtime_ui/deprecated_where_block.rs:20:1 | -20 | // construct_runtime! { -21 | || pub struct Runtime where -22 | || Block = Block, -23 | || NodeBlock = Block, -... || -27 | || } -28 | || } - | ||_- in this macro invocation +20 | / construct_runtime! { +21 | | pub struct Runtime where +22 | | Block = Block, +23 | | NodeBlock = Block, ... | +27 | | } +28 | | } + | |_^ note: required by a bound in `Result` --> $RUST/core/src/result.rs | | pub enum Result { | ^ required by this bound in `Result` - = note: this error originates in the derive macro `self::sp_api_hidden_includes_construct_runtime::hidden_include::__private::codec::Decode` which comes from the expansion of the macro `construct_runtime` (in Nightly builds, run with -Z macro-backtrace for more info) + = note: this error originates in the derive macro `self::sp_api_hidden_includes_construct_runtime::hidden_include::__private::codec::Decode` which comes from the expansion of the macro `frame_support::construct_runtime` (in Nightly builds, run with -Z macro-backtrace for more info) error[E0277]: the trait bound `Runtime: Config` is not satisfied in `RuntimeEvent` --> tests/construct_runtime_ui/deprecated_where_block.rs:20:1 | -20 | // construct_runtime! { -21 | || pub struct Runtime where -22 | || Block = Block, -23 | || NodeBlock = Block, -... || -27 | || } -28 | || } - | ||_- in this macro invocation +20 | / construct_runtime! { +21 | | pub struct Runtime where +22 | | Block = Block, +23 | | NodeBlock = Block, ... | +27 | | } +28 | | } + | |_^ within `RuntimeEvent`, the trait `Config` is not implemented for `Runtime`, which is required by `RuntimeEvent: Sized` | note: required because it appears within the type `RuntimeEvent` --> tests/construct_runtime_ui/deprecated_where_block.rs:20:1 | -20 | // construct_runtime! { -21 | || pub struct Runtime where -22 | || Block = Block, -23 | || NodeBlock = Block, -... || -27 | || } -28 | || } - | ||_- in this macro invocation +20 | / construct_runtime! { +21 | | pub struct Runtime where +22 | | Block = Block, +23 | | NodeBlock = Block, ... | +27 | | } +28 | | } + | |_^ note: required by a bound in `TryInto` --> $RUST/core/src/convert/mod.rs | | pub trait TryInto: Sized { | ^^^^^ required by this bound in `TryInto` - = note: this error originates in the macro `frame_support::construct_runtime` which comes from the expansion of the macro `construct_runtime` (in Nightly builds, run with -Z macro-backtrace for more info) + = note: this error originates in the macro `frame_support::construct_runtime` (in Nightly builds, run with -Z macro-backtrace for more info) error[E0277]: the trait bound `Runtime: Config` is not satisfied --> tests/construct_runtime_ui/deprecated_where_block.rs:20:1 | -20 | // construct_runtime! { -21 | || pub struct Runtime where -22 | || Block = Block, -23 | || NodeBlock = Block, -... || -27 | || } -28 | || } - | ||_- in this macro invocation +20 | / construct_runtime! { +21 | | pub struct Runtime where +22 | | Block = Block, +23 | | NodeBlock = Block, ... | +27 | | } +28 | | } + | |_^ the trait `Config` is not implemented for `Runtime`, which is required by `RuntimeCall: Sized` | = note: required for `Pallet` to implement `Callable` note: required because it appears within the type `RuntimeCall` --> tests/construct_runtime_ui/deprecated_where_block.rs:20:1 | -20 | // construct_runtime! { -21 | || pub struct Runtime where -22 | || Block = Block, -23 | || NodeBlock = Block, -... || -27 | || } -28 | || } - | ||_- in this macro invocation +20 | / construct_runtime! { +21 | | pub struct Runtime where +22 | | Block = Block, +23 | | NodeBlock = Block, ... | +27 | | } +28 | | } + | |_^ note: required by a bound in `Result` --> $RUST/core/src/result.rs | | pub enum Result { | ^ required by this bound in `Result` - = note: this error originates in the derive macro `self::sp_api_hidden_includes_construct_runtime::hidden_include::__private::codec::Decode` which comes from the expansion of the macro `construct_runtime` (in Nightly builds, run with -Z macro-backtrace for more info) - -error[E0277]: the trait bound `Runtime: Config` is not satisfied - --> tests/construct_runtime_ui/deprecated_where_block.rs:20:1 - | -20 | // construct_runtime! { -21 | || pub struct Runtime where -22 | || Block = Block, -23 | || NodeBlock = Block, -... || -27 | || } -28 | || } - | ||_- in this macro invocation -... | - | - = note: required for `Pallet` to implement `Callable` -note: required because it appears within the type `RuntimeCall` - --> tests/construct_runtime_ui/deprecated_where_block.rs:20:1 - | -20 | // construct_runtime! { -21 | || pub struct Runtime where -22 | || Block = Block, -23 | || NodeBlock = Block, -... || -27 | || } -28 | || } - | ||_- in this macro invocation -... | -note: required by a bound in `frame_support::sp_runtime::traits::Dispatchable::Config` - --> $WORKSPACE/substrate/primitives/runtime/src/traits.rs - | - | type Config; - | ^^^^^^^^^^^^ required by this bound in `Dispatchable::Config` - = note: this error originates in the macro `frame_support::construct_runtime` which comes from the expansion of the macro `construct_runtime` (in Nightly builds, run with -Z macro-backtrace for more info) - -error[E0277]: the trait bound `Runtime: Config` is not satisfied - --> tests/construct_runtime_ui/deprecated_where_block.rs:20:1 - | -20 | // construct_runtime! { -21 | || pub struct Runtime where -22 | || Block = Block, -23 | || NodeBlock = Block, -... || -27 | || } -28 | || } - | ||_- in this macro invocation -... | - | - = note: required for `Pallet` to implement `Callable` -note: required because it appears within the type `RuntimeCall` - --> tests/construct_runtime_ui/deprecated_where_block.rs:20:1 - | -20 | // construct_runtime! { -21 | || pub struct Runtime where -22 | || Block = Block, -23 | || NodeBlock = Block, -... || -27 | || } -28 | || } - | ||_- in this macro invocation -... | -note: required by a bound in `frame_support::pallet_prelude::ValidateUnsigned::Call` - --> $WORKSPACE/substrate/primitives/runtime/src/traits.rs - | - | type Call; - | ^^^^^^^^^^ required by this bound in `ValidateUnsigned::Call` - = note: this error originates in the macro `frame_support::construct_runtime` which comes from the expansion of the macro `construct_runtime` (in Nightly builds, run with -Z macro-backtrace for more info) + = note: this error originates in the derive macro `self::sp_api_hidden_includes_construct_runtime::hidden_include::__private::codec::Decode` which comes from the expansion of the macro `frame_support::construct_runtime` (in Nightly builds, run with -Z macro-backtrace for more info) 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 6160f8234a350cc3ee0a0761cab0eed6ea022525..dde58ba6959bb1e1b166508d595d14e415be6857 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 @@ -5,23 +5,16 @@ error: The number of pallets exceeds the maximum number of tuple elements. To in | ^^^ error: recursion limit reached while expanding `frame_support::__private::tt_return!` - --> tests/construct_runtime_ui/number_of_pallets_exceeds_tuple_size.rs:22:1 + --> tests/construct_runtime_ui/number_of_pallets_exceeds_tuple_size.rs:66: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}, ... | -66 | |/ construct_runtime! { -67 | || pub struct Runtime -68 | || { -69 | || System: frame_system::{Pallet, Call, Storage, Config, Event}, -... || -180 | || } -181 | || } - | ||_^ - | |_| - | in this macro invocation +180 | | } +181 | | } + | |_^ | = 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/pallet_error_too_large.stderr b/substrate/frame/support/test/tests/construct_runtime_ui/pallet_error_too_large.stderr index ebbb9ffb0eb0a91b38ce37436a297260baef32c8..75116f71919500736a084cf8e0c854bcd2ac6f50 100644 --- a/substrate/frame/support/test/tests/construct_runtime_ui/pallet_error_too_large.stderr +++ b/substrate/frame/support/test/tests/construct_runtime_ui/pallet_error_too_large.stderr @@ -10,4 +10,4 @@ error[E0080]: evaluation of constant value failed 97 | | } | |_^ the evaluated program panicked at 'The maximum encoded size of the error type in the `Pallet` pallet exceeds `MAX_MODULE_ERROR_ENCODED_SIZE`', $DIR/tests/construct_runtime_ui/pallet_error_too_large.rs:91:1 | - = note: this error originates in the macro `$crate::panic::panic_2021` which comes from the expansion of the macro `construct_runtime` (in Nightly builds, run with -Z macro-backtrace for more info) + = note: this error originates in the macro `$crate::panic::panic_2021` which comes from the expansion of the macro `frame_support::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_call_part.stderr b/substrate/frame/support/test/tests/construct_runtime_ui/undefined_call_part.stderr index b9cf58542f20b549b694f12eb1dc0708649618f0..42e72bc90da7811f280af0aa755df4e3387eadf7 100644 --- a/substrate/frame/support/test/tests/construct_runtime_ui/undefined_call_part.stderr +++ b/substrate/frame/support/test/tests/construct_runtime_ui/undefined_call_part.stderr @@ -13,4 +13,4 @@ error: `Pallet` does not have #[pallet::call] defined, perhaps you should remove 72 | | } | |_- in this macro invocation | - = note: this error originates in the macro `pallet::__substrate_call_check::is_call_part_defined` which comes from the expansion of the macro `construct_runtime` (in Nightly builds, run with -Z macro-backtrace for more info) + = note: this error originates in the macro `pallet::__substrate_call_check::is_call_part_defined` which comes from the expansion of the macro `frame_support::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_validate_unsigned_part.stderr b/substrate/frame/support/test/tests/construct_runtime_ui/undefined_validate_unsigned_part.stderr index f527cc2ff773cb2bcd8e9f7f724cb42a20f667b8..add71c2197efa413393da2c6d4d050834a2f41fd 100644 --- a/substrate/frame/support/test/tests/construct_runtime_ui/undefined_validate_unsigned_part.stderr +++ b/substrate/frame/support/test/tests/construct_runtime_ui/undefined_validate_unsigned_part.stderr @@ -13,7 +13,7 @@ error: `Pallet` does not have #[pallet::validate_unsigned] defined, perhaps you 72 | | } | |_- in this macro invocation | - = note: this error originates in the macro `pallet::__substrate_validate_unsigned_check::is_validate_unsigned_part_defined` which comes from the expansion of the macro `construct_runtime` (in Nightly builds, run with -Z macro-backtrace for more info) + = note: this error originates in the macro `pallet::__substrate_validate_unsigned_check::is_validate_unsigned_part_defined` which comes from the expansion of the macro `frame_support::construct_runtime` (in Nightly builds, run with -Z macro-backtrace for more info) error[E0599]: no variant or associated item named `Pallet` found for enum `RuntimeCall` in the current scope --> tests/construct_runtime_ui/undefined_validate_unsigned_part.rs:70:3 @@ -26,54 +26,50 @@ error[E0599]: no variant or associated item named `Pallet` found for enum `Runti | || -^^^^^^ variant or associated item not found in `RuntimeCall` | ||________| | | -... | +71 | | } +72 | | } + | |__- variant or associated item `Pallet` not found for this enum error[E0599]: no function or associated item named `pre_dispatch` found for struct `pallet::Pallet` in the current scope --> tests/construct_runtime_ui/undefined_validate_unsigned_part.rs:66:1 | -28 | pub struct Pallet(_); - | -------------------- function or associated item `pre_dispatch` not found for this struct +28 | pub struct Pallet(_); + | -------------------- function or associated item `pre_dispatch` not found for this struct ... -66 | construct_runtime! { - | __^ - | | _| - | || -67 | || pub struct Runtime -68 | || { -69 | || System: frame_system::{Pallet, Call, Storage, Config, Event}, -70 | || Pallet: pallet::{Pallet, ValidateUnsigned}, -71 | || } -72 | || } - | ||_- in this macro invocation -... | +66 | construct_runtime! { + | _^ +67 | | pub struct Runtime +68 | | { +69 | | System: frame_system::{Pallet, Call, Storage, Config, Event}, +70 | | Pallet: pallet::{Pallet, ValidateUnsigned}, +71 | | } +72 | | } + | |_^ 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 traits define an item `pre_dispatch`, perhaps you need to implement one of them: candidate #1: `SignedExtension` candidate #2: `ValidateUnsigned` - = note: this error originates in the macro `frame_support::construct_runtime` which comes from the expansion of the macro `construct_runtime` (in Nightly builds, run with -Z macro-backtrace for more info) + = note: this error originates in the macro `frame_support::construct_runtime` (in Nightly builds, run with -Z macro-backtrace for more info) error[E0599]: no function or associated item named `validate_unsigned` found for struct `pallet::Pallet` in the current scope --> tests/construct_runtime_ui/undefined_validate_unsigned_part.rs:66:1 | -28 | pub struct Pallet(_); - | -------------------- function or associated item `validate_unsigned` not found for this struct +28 | pub struct Pallet(_); + | -------------------- function or associated item `validate_unsigned` not found for this struct ... -66 | construct_runtime! { - | __^ - | | _| - | || -67 | || pub struct Runtime -68 | || { -69 | || System: frame_system::{Pallet, Call, Storage, Config, Event}, -70 | || Pallet: pallet::{Pallet, ValidateUnsigned}, -71 | || } -72 | || } - | ||_- in this macro invocation -... | +66 | construct_runtime! { + | _^ +67 | | pub struct Runtime +68 | | { +69 | | System: frame_system::{Pallet, Call, Storage, Config, Event}, +70 | | Pallet: pallet::{Pallet, ValidateUnsigned}, +71 | | } +72 | | } + | |_^ 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 traits define an item `validate_unsigned`, perhaps you need to implement one of them: candidate #1: `SignedExtension` candidate #2: `ValidateUnsigned` - = note: this error originates in the macro `frame_support::construct_runtime` which comes from the expansion of the macro `construct_runtime` (in Nightly builds, run with -Z macro-backtrace for more info) + = note: this error originates in the macro `frame_support::construct_runtime` (in Nightly builds, run with -Z macro-backtrace for more info) diff --git a/substrate/frame/support/test/tests/derive_no_bound.rs b/substrate/frame/support/test/tests/derive_no_bound.rs index 48a6413c3ac508cad684500969f5be1cbeb01135..b191470780514617f23231c6a310ab570948a846 100644 --- a/substrate/frame/support/test/tests/derive_no_bound.rs +++ b/substrate/frame/support/test/tests/derive_no_bound.rs @@ -24,6 +24,7 @@ use frame_support::{ }; #[derive(RuntimeDebugNoBound)] +#[allow(dead_code)] struct Unnamed(u64); #[test] diff --git a/substrate/frame/support/test/tests/pallet_ui/call_argument_invalid_bound.stderr b/substrate/frame/support/test/tests/pallet_ui/call_argument_invalid_bound.stderr index 40f8f129830496df6d9b03c0ed505b9bbd4958cb..2a4ceecd8fa4b361241378e2fa6b71fa5b2ffda1 100644 --- a/substrate/frame/support/test/tests/pallet_ui/call_argument_invalid_bound.stderr +++ b/substrate/frame/support/test/tests/pallet_ui/call_argument_invalid_bound.stderr @@ -18,7 +18,7 @@ error[E0277]: `::Bar` doesn't implement `std::fmt::Debug` 38 | pub fn foo(origin: OriginFor, _bar: T::Bar) -> DispatchResultWithPostInfo { | ^^^^ `::Bar` cannot be formatted using `{:?}` because it doesn't implement `std::fmt::Debug` | - = help: the trait `std::fmt::Debug` is not implemented for `::Bar` + = help: the trait `std::fmt::Debug` is not implemented for `::Bar`, which is required by `&::Bar: std::fmt::Debug` = note: required for `&::Bar` to implement `std::fmt::Debug` = note: required for the cast from `&&::Bar` to `&dyn std::fmt::Debug` diff --git a/substrate/frame/support/test/tests/pallet_ui/call_argument_invalid_bound_2.stderr b/substrate/frame/support/test/tests/pallet_ui/call_argument_invalid_bound_2.stderr index 5744c636235081449f6f12767821016a70179f4e..fc993e9ff68f522d5bd29609ffadb22e06b4f20b 100644 --- a/substrate/frame/support/test/tests/pallet_ui/call_argument_invalid_bound_2.stderr +++ b/substrate/frame/support/test/tests/pallet_ui/call_argument_invalid_bound_2.stderr @@ -18,7 +18,7 @@ error[E0277]: `::Bar` doesn't implement `std::fmt::Debug` 38 | pub fn foo(origin: OriginFor, _bar: T::Bar) -> DispatchResultWithPostInfo { | ^^^^ `::Bar` cannot be formatted using `{:?}` because it doesn't implement `std::fmt::Debug` | - = help: the trait `std::fmt::Debug` is not implemented for `::Bar` + = help: the trait `std::fmt::Debug` is not implemented for `::Bar`, which is required by `&::Bar: std::fmt::Debug` = note: required for `&::Bar` to implement `std::fmt::Debug` = note: required for the cast from `&&::Bar` to `&dyn std::fmt::Debug` @@ -41,7 +41,7 @@ error[E0277]: the trait bound `::Bar: WrapperTypeEncode` is | ------------------------ required by a bound introduced by this call ... 38 | pub fn foo(origin: OriginFor, _bar: T::Bar) -> DispatchResultWithPostInfo { - | ^^^^ the trait `WrapperTypeEncode` is not implemented for `::Bar` + | ^^^^ the trait `WrapperTypeEncode` is not implemented for `::Bar`, which is required by `::Bar: Encode` | = note: required for `::Bar` to implement `Encode` @@ -49,6 +49,6 @@ error[E0277]: the trait bound `::Bar: WrapperTypeDecode` is --> tests/pallet_ui/call_argument_invalid_bound_2.rs:38:42 | 38 | pub fn foo(origin: OriginFor, _bar: T::Bar) -> DispatchResultWithPostInfo { - | ^^^^^^ the trait `WrapperTypeDecode` is not implemented for `::Bar` + | ^^^^^^ the trait `WrapperTypeDecode` is not implemented for `::Bar`, which is required by `::Bar: Decode` | = note: required for `::Bar` to implement `Decode` diff --git a/substrate/frame/support/test/tests/pallet_ui/call_argument_invalid_bound_3.stderr b/substrate/frame/support/test/tests/pallet_ui/call_argument_invalid_bound_3.stderr index b58e4516bceb975ea4937f90ac15acec796829cc..d6486a490794d51caf6fa38b9e90d596447a5dfb 100644 --- a/substrate/frame/support/test/tests/pallet_ui/call_argument_invalid_bound_3.stderr +++ b/substrate/frame/support/test/tests/pallet_ui/call_argument_invalid_bound_3.stderr @@ -18,7 +18,7 @@ error[E0277]: `Bar` doesn't implement `std::fmt::Debug` 40 | pub fn foo(origin: OriginFor, _bar: Bar) -> DispatchResultWithPostInfo { | ^^^^ `Bar` cannot be formatted using `{:?}` | - = help: the trait `std::fmt::Debug` is not implemented for `Bar` + = help: the trait `std::fmt::Debug` is not implemented for `Bar`, which is required by `&Bar: std::fmt::Debug` = note: add `#[derive(Debug)]` to `Bar` or manually `impl std::fmt::Debug for Bar` = note: required for `&Bar` to implement `std::fmt::Debug` = note: required for the cast from `&&Bar` to `&dyn std::fmt::Debug` diff --git a/substrate/frame/support/test/tests/pallet_ui/dev_mode_without_arg_max_encoded_len.stderr b/substrate/frame/support/test/tests/pallet_ui/dev_mode_without_arg_max_encoded_len.stderr index 02ead305dd81ad3d3dd0bdab9b74d2a255e8b61f..629fefebbe2c709147c29ad307ca58bea79b2440 100644 --- a/substrate/frame/support/test/tests/pallet_ui/dev_mode_without_arg_max_encoded_len.stderr +++ b/substrate/frame/support/test/tests/pallet_ui/dev_mode_without_arg_max_encoded_len.stderr @@ -35,7 +35,7 @@ error[E0277]: the trait bound `Vec: MaxEncodedLen` is not satisfied ... | 35 | | #[pallet::storage] 36 | | type MyStorage = StorageValue<_, Vec>; - | |__________________^ the trait `MaxEncodedLen` is not implemented for `Vec` + | |__________________^ the trait `MaxEncodedLen` is not implemented for `Vec`, which is required by `frame_support::pallet_prelude::StorageValue<_GeneratedPrefixForStorageMyStorage, Vec>: StorageInfoTrait` | = help: the following other types implement trait `MaxEncodedLen`: bool diff --git a/substrate/frame/support/test/tests/pallet_ui/event_field_not_member.stderr b/substrate/frame/support/test/tests/pallet_ui/event_field_not_member.stderr index 44660d269060386ab10d749e4a16cd4e65b97950..e9c2eae686baf43af57d5b54074869de57298723 100644 --- a/substrate/frame/support/test/tests/pallet_ui/event_field_not_member.stderr +++ b/substrate/frame/support/test/tests/pallet_ui/event_field_not_member.stderr @@ -16,6 +16,6 @@ error[E0277]: `::Bar` doesn't implement `std::fmt::Debug` 41 | B { b: T::Bar }, | ^ `::Bar` cannot be formatted using `{:?}` because it doesn't implement `std::fmt::Debug` | - = help: the trait `std::fmt::Debug` is not implemented for `::Bar` + = help: the trait `std::fmt::Debug` is not implemented for `::Bar`, which is required by `&::Bar: std::fmt::Debug` = note: required for `&::Bar` to implement `std::fmt::Debug` = note: required for the cast from `&&::Bar` to `&dyn std::fmt::Debug` diff --git a/substrate/frame/support/test/tests/pallet_ui/storage_ensure_span_are_ok_on_wrong_gen.stderr b/substrate/frame/support/test/tests/pallet_ui/storage_ensure_span_are_ok_on_wrong_gen.stderr index d269e6d2726d793277a90334686ac11745f4d1c0..c8c41e8050145be714e53394e95d5fdda0b7dcbd 100644 --- a/substrate/frame/support/test/tests/pallet_ui/storage_ensure_span_are_ok_on_wrong_gen.stderr +++ b/substrate/frame/support/test/tests/pallet_ui/storage_ensure_span_are_ok_on_wrong_gen.stderr @@ -9,7 +9,7 @@ error[E0277]: the trait bound `Bar: WrapperTypeDecode` is not satisfied ... | 38 | | #[pallet::storage] 39 | | type Foo = StorageValue; - | |____________^ the trait `WrapperTypeDecode` is not implemented for `Bar` + | |____________^ the trait `WrapperTypeDecode` is not implemented for `Bar`, which is required by `frame_support::pallet_prelude::StorageValue<_GeneratedPrefixForStorageFoo, Bar>: PartialStorageInfoTrait` | = help: the following other types implement trait `WrapperTypeDecode`: Box @@ -31,7 +31,7 @@ error[E0277]: the trait bound `Bar: EncodeLike` is not satisfied ... | 38 | | #[pallet::storage] 39 | | type Foo = StorageValue; - | |____________^ the trait `EncodeLike` is not implemented for `Bar` + | |____________^ the trait `EncodeLike` is not implemented for `Bar`, which is required by `frame_support::pallet_prelude::StorageValue<_GeneratedPrefixForStorageFoo, Bar>: PartialStorageInfoTrait` | = help: the following other types implement trait `EncodeLike`: @@ -58,7 +58,7 @@ error[E0277]: the trait bound `Bar: WrapperTypeEncode` is not satisfied ... | 38 | | #[pallet::storage] 39 | | type Foo = StorageValue; - | |____________^ the trait `WrapperTypeEncode` is not implemented for `Bar` + | |____________^ the trait `WrapperTypeEncode` is not implemented for `Bar`, which is required by `frame_support::pallet_prelude::StorageValue<_GeneratedPrefixForStorageFoo, Bar>: PartialStorageInfoTrait` | = help: the following other types implement trait `WrapperTypeEncode`: Box @@ -81,7 +81,7 @@ error[E0277]: the trait bound `Bar: TypeInfo` is not satisfied 38 | #[pallet::storage] | _______________^ 39 | | type Foo = StorageValue; - | |____________^ the trait `TypeInfo` is not implemented for `Bar` + | |____________^ the trait `TypeInfo` is not implemented for `Bar`, which is required by `frame_support::pallet_prelude::StorageValue<_GeneratedPrefixForStorageFoo, Bar>: StorageEntryMetadataBuilder` | = help: the following other types implement trait `TypeInfo`: bool @@ -102,7 +102,7 @@ error[E0277]: the trait bound `Bar: WrapperTypeDecode` is not satisfied 38 | #[pallet::storage] | _______________^ 39 | | type Foo = StorageValue; - | |____________^ the trait `WrapperTypeDecode` is not implemented for `Bar` + | |____________^ the trait `WrapperTypeDecode` is not implemented for `Bar`, which is required by `frame_support::pallet_prelude::StorageValue<_GeneratedPrefixForStorageFoo, Bar>: StorageEntryMetadataBuilder` | = help: the following other types implement trait `WrapperTypeDecode`: Box @@ -119,7 +119,7 @@ error[E0277]: the trait bound `Bar: EncodeLike` is not satisfied 38 | #[pallet::storage] | _______________^ 39 | | type Foo = StorageValue; - | |____________^ the trait `EncodeLike` is not implemented for `Bar` + | |____________^ the trait `EncodeLike` is not implemented for `Bar`, which is required by `frame_support::pallet_prelude::StorageValue<_GeneratedPrefixForStorageFoo, Bar>: StorageEntryMetadataBuilder` | = help: the following other types implement trait `EncodeLike`: @@ -141,7 +141,7 @@ error[E0277]: the trait bound `Bar: WrapperTypeEncode` is not satisfied 38 | #[pallet::storage] | _______________^ 39 | | type Foo = StorageValue; - | |____________^ the trait `WrapperTypeEncode` is not implemented for `Bar` + | |____________^ the trait `WrapperTypeEncode` is not implemented for `Bar`, which is required by `frame_support::pallet_prelude::StorageValue<_GeneratedPrefixForStorageFoo, Bar>: StorageEntryMetadataBuilder` | = help: the following other types implement trait `WrapperTypeEncode`: Box @@ -164,7 +164,7 @@ error[E0277]: the trait bound `Bar: WrapperTypeDecode` is not satisfied 38 | #[pallet::storage] | _______________^ 39 | | type Foo = StorageValue; - | |____________^ the trait `WrapperTypeDecode` is not implemented for `Bar` + | |____________^ the trait `WrapperTypeDecode` is not implemented for `Bar`, which is required by `frame_support::pallet_prelude::StorageValue<_GeneratedPrefixForStorageFoo, Bar>: TryDecodeEntireStorage` | = help: the following other types implement trait `WrapperTypeDecode`: Box @@ -181,7 +181,7 @@ error[E0277]: the trait bound `Bar: EncodeLike` is not satisfied 38 | #[pallet::storage] | _______________^ 39 | | type Foo = StorageValue; - | |____________^ the trait `EncodeLike` is not implemented for `Bar` + | |____________^ the trait `EncodeLike` is not implemented for `Bar`, which is required by `frame_support::pallet_prelude::StorageValue<_GeneratedPrefixForStorageFoo, Bar>: TryDecodeEntireStorage` | = help: the following other types implement trait `EncodeLike`: @@ -203,7 +203,7 @@ error[E0277]: the trait bound `Bar: WrapperTypeEncode` is not satisfied 38 | #[pallet::storage] | _______________^ 39 | | type Foo = StorageValue; - | |____________^ the trait `WrapperTypeEncode` is not implemented for `Bar` + | |____________^ the trait `WrapperTypeEncode` is not implemented for `Bar`, which is required by `frame_support::pallet_prelude::StorageValue<_GeneratedPrefixForStorageFoo, Bar>: TryDecodeEntireStorage` | = help: the following other types implement trait `WrapperTypeEncode`: Box diff --git a/substrate/frame/support/test/tests/pallet_ui/storage_ensure_span_are_ok_on_wrong_gen_unnamed.stderr b/substrate/frame/support/test/tests/pallet_ui/storage_ensure_span_are_ok_on_wrong_gen_unnamed.stderr index 13d761d65d2012d124279cdd857aac35fcec9ac0..08b35eb8ed1536d83678e5b438687cdef51cf91f 100644 --- a/substrate/frame/support/test/tests/pallet_ui/storage_ensure_span_are_ok_on_wrong_gen_unnamed.stderr +++ b/substrate/frame/support/test/tests/pallet_ui/storage_ensure_span_are_ok_on_wrong_gen_unnamed.stderr @@ -9,7 +9,7 @@ error[E0277]: the trait bound `Bar: WrapperTypeDecode` is not satisfied ... | 38 | | #[pallet::storage] 39 | | type Foo = StorageValue<_, Bar>; - | |____________^ the trait `WrapperTypeDecode` is not implemented for `Bar` + | |____________^ the trait `WrapperTypeDecode` is not implemented for `Bar`, which is required by `frame_support::pallet_prelude::StorageValue<_GeneratedPrefixForStorageFoo, Bar>: PartialStorageInfoTrait` | = help: the following other types implement trait `WrapperTypeDecode`: Box @@ -31,7 +31,7 @@ error[E0277]: the trait bound `Bar: EncodeLike` is not satisfied ... | 38 | | #[pallet::storage] 39 | | type Foo = StorageValue<_, Bar>; - | |____________^ the trait `EncodeLike` is not implemented for `Bar` + | |____________^ the trait `EncodeLike` is not implemented for `Bar`, which is required by `frame_support::pallet_prelude::StorageValue<_GeneratedPrefixForStorageFoo, Bar>: PartialStorageInfoTrait` | = help: the following other types implement trait `EncodeLike`: @@ -58,7 +58,7 @@ error[E0277]: the trait bound `Bar: WrapperTypeEncode` is not satisfied ... | 38 | | #[pallet::storage] 39 | | type Foo = StorageValue<_, Bar>; - | |____________^ the trait `WrapperTypeEncode` is not implemented for `Bar` + | |____________^ the trait `WrapperTypeEncode` is not implemented for `Bar`, which is required by `frame_support::pallet_prelude::StorageValue<_GeneratedPrefixForStorageFoo, Bar>: PartialStorageInfoTrait` | = help: the following other types implement trait `WrapperTypeEncode`: Box @@ -81,7 +81,7 @@ error[E0277]: the trait bound `Bar: TypeInfo` is not satisfied 38 | #[pallet::storage] | _______________^ 39 | | type Foo = StorageValue<_, Bar>; - | |____________^ the trait `TypeInfo` is not implemented for `Bar` + | |____________^ the trait `TypeInfo` is not implemented for `Bar`, which is required by `frame_support::pallet_prelude::StorageValue<_GeneratedPrefixForStorageFoo, Bar>: StorageEntryMetadataBuilder` | = help: the following other types implement trait `TypeInfo`: bool @@ -102,7 +102,7 @@ error[E0277]: the trait bound `Bar: WrapperTypeDecode` is not satisfied 38 | #[pallet::storage] | _______________^ 39 | | type Foo = StorageValue<_, Bar>; - | |____________^ the trait `WrapperTypeDecode` is not implemented for `Bar` + | |____________^ the trait `WrapperTypeDecode` is not implemented for `Bar`, which is required by `frame_support::pallet_prelude::StorageValue<_GeneratedPrefixForStorageFoo, Bar>: StorageEntryMetadataBuilder` | = help: the following other types implement trait `WrapperTypeDecode`: Box @@ -119,7 +119,7 @@ error[E0277]: the trait bound `Bar: EncodeLike` is not satisfied 38 | #[pallet::storage] | _______________^ 39 | | type Foo = StorageValue<_, Bar>; - | |____________^ the trait `EncodeLike` is not implemented for `Bar` + | |____________^ the trait `EncodeLike` is not implemented for `Bar`, which is required by `frame_support::pallet_prelude::StorageValue<_GeneratedPrefixForStorageFoo, Bar>: StorageEntryMetadataBuilder` | = help: the following other types implement trait `EncodeLike`: @@ -141,7 +141,7 @@ error[E0277]: the trait bound `Bar: WrapperTypeEncode` is not satisfied 38 | #[pallet::storage] | _______________^ 39 | | type Foo = StorageValue<_, Bar>; - | |____________^ the trait `WrapperTypeEncode` is not implemented for `Bar` + | |____________^ the trait `WrapperTypeEncode` is not implemented for `Bar`, which is required by `frame_support::pallet_prelude::StorageValue<_GeneratedPrefixForStorageFoo, Bar>: StorageEntryMetadataBuilder` | = help: the following other types implement trait `WrapperTypeEncode`: Box @@ -164,7 +164,7 @@ error[E0277]: the trait bound `Bar: WrapperTypeDecode` is not satisfied 38 | #[pallet::storage] | _______________^ 39 | | type Foo = StorageValue<_, Bar>; - | |____________^ the trait `WrapperTypeDecode` is not implemented for `Bar` + | |____________^ the trait `WrapperTypeDecode` is not implemented for `Bar`, which is required by `frame_support::pallet_prelude::StorageValue<_GeneratedPrefixForStorageFoo, Bar>: TryDecodeEntireStorage` | = help: the following other types implement trait `WrapperTypeDecode`: Box @@ -181,7 +181,7 @@ error[E0277]: the trait bound `Bar: EncodeLike` is not satisfied 38 | #[pallet::storage] | _______________^ 39 | | type Foo = StorageValue<_, Bar>; - | |____________^ the trait `EncodeLike` is not implemented for `Bar` + | |____________^ the trait `EncodeLike` is not implemented for `Bar`, which is required by `frame_support::pallet_prelude::StorageValue<_GeneratedPrefixForStorageFoo, Bar>: TryDecodeEntireStorage` | = help: the following other types implement trait `EncodeLike`: @@ -203,7 +203,7 @@ error[E0277]: the trait bound `Bar: WrapperTypeEncode` is not satisfied 38 | #[pallet::storage] | _______________^ 39 | | type Foo = StorageValue<_, Bar>; - | |____________^ the trait `WrapperTypeEncode` is not implemented for `Bar` + | |____________^ the trait `WrapperTypeEncode` is not implemented for `Bar`, which is required by `frame_support::pallet_prelude::StorageValue<_GeneratedPrefixForStorageFoo, Bar>: TryDecodeEntireStorage` | = help: the following other types implement trait `WrapperTypeEncode`: Box diff --git a/substrate/frame/support/test/tests/pallet_ui/storage_info_unsatisfied.stderr b/substrate/frame/support/test/tests/pallet_ui/storage_info_unsatisfied.stderr index 504db21feeb2b226da122e4a1719e935145d0c31..042a6f67fd316c27a802c14f2497d86f6c9bd5bc 100644 --- a/substrate/frame/support/test/tests/pallet_ui/storage_info_unsatisfied.stderr +++ b/substrate/frame/support/test/tests/pallet_ui/storage_info_unsatisfied.stderr @@ -9,7 +9,7 @@ error[E0277]: the trait bound `Bar: MaxEncodedLen` is not satisfied ... | 38 | | #[pallet::storage] 39 | | type Foo = StorageValue<_, Bar>; - | |____________^ the trait `MaxEncodedLen` is not implemented for `Bar` + | |____________^ the trait `MaxEncodedLen` is not implemented for `Bar`, which is required by `frame_support::pallet_prelude::StorageValue<_GeneratedPrefixForStorageFoo, Bar>: StorageInfoTrait` | = help: the following other types implement trait `MaxEncodedLen`: bool diff --git a/substrate/frame/support/test/tests/pallet_ui/storage_info_unsatisfied_nmap.stderr b/substrate/frame/support/test/tests/pallet_ui/storage_info_unsatisfied_nmap.stderr index 6fd0b1959c860affc94b56c63b76392a310f2eea..9f57b85f3a8a3ae0797efb618c1f8c1123da070d 100644 --- a/substrate/frame/support/test/tests/pallet_ui/storage_info_unsatisfied_nmap.stderr +++ b/substrate/frame/support/test/tests/pallet_ui/storage_info_unsatisfied_nmap.stderr @@ -9,7 +9,7 @@ error[E0277]: the trait bound `Bar: MaxEncodedLen` is not satisfied ... | 41 | | #[pallet::storage] 42 | | type Foo = StorageNMap<_, Key, u32>; - | |____________^ the trait `MaxEncodedLen` is not implemented for `Bar` + | |____________^ the trait `MaxEncodedLen` is not implemented for `Bar`, which is required by `frame_support::pallet_prelude::StorageNMap<_GeneratedPrefixForStorageFoo, NMapKey, u32>: StorageInfoTrait` | = help: the following other types implement trait `MaxEncodedLen`: bool diff --git a/substrate/frame/system/Cargo.toml b/substrate/frame/system/Cargo.toml index 16b3b946e22125e6d844020a4a94b788dc4aa270..a2a8970814b0a7c7c2c3f5ba9536371236c16bbd 100644 --- a/substrate/frame/system/Cargo.toml +++ b/substrate/frame/system/Cargo.toml @@ -17,7 +17,7 @@ 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"] } +codec = { package = "parity-scale-codec", version = "3.6.12", default-features = false, features = ["derive"] } log = { workspace = true } scale-info = { version = "2.11.1", default-features = false, features = ["derive", "serde"] } serde = { features = ["alloc", "derive"], workspace = true } @@ -31,7 +31,7 @@ sp-weights = { path = "../../primitives/weights", default-features = false, feat docify = "0.2.8" [dev-dependencies] -criterion = "0.4.0" +criterion = "0.5.1" sp-externalities = { path = "../../primitives/externalities" } substrate-test-runtime-client = { path = "../../test-utils/runtime/client" } diff --git a/substrate/frame/system/benchmarking/Cargo.toml b/substrate/frame/system/benchmarking/Cargo.toml index 473a6bb132d741cf9485868201f114234be9f5d8..022f0ffce6b5ee23168db0ccaad1da5ea767ddf3 100644 --- a/substrate/frame/system/benchmarking/Cargo.toml +++ b/substrate/frame/system/benchmarking/Cargo.toml @@ -16,7 +16,7 @@ workspace = true targets = ["x86_64-unknown-linux-gnu"] [dependencies] -codec = { package = "parity-scale-codec", version = "3.6.1", default-features = false } +codec = { package = "parity-scale-codec", version = "3.6.12", default-features = false } scale-info = { version = "2.11.1", default-features = false, features = ["derive"] } frame-benchmarking = { path = "../../benchmarking", default-features = false } frame-support = { path = "../../support", default-features = false } diff --git a/substrate/frame/system/benchmarking/src/inner.rs b/substrate/frame/system/benchmarking/src/inner.rs new file mode 100644 index 0000000000000000000000000000000000000000..c1631b0a2e334e985c9b0ab8a87f1a318548dab1 --- /dev/null +++ b/substrate/frame/system/benchmarking/src/inner.rs @@ -0,0 +1,230 @@ +// 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 System benchmarks. + +use codec::Encode; +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 struct Pallet(System); +pub trait Config: frame_system::Config { + /// Adds ability to the Runtime to test against their sample code. + /// + /// Default is `../res/kitchensink_runtime.compact.compressed.wasm`. + fn prepare_set_code_data() -> Vec { + include_bytes!("../res/kitchensink_runtime.compact.compressed.wasm").to_vec() + } + + /// Adds ability to the Runtime to prepare/initialize before running benchmark `set_code`. + fn setup_set_code_requirements(_code: &Vec) -> Result<(), BenchmarkError> { + Ok(()) + } + + /// Adds ability to the Runtime to do custom validation after benchmark. + /// + /// Default is checking for `CodeUpdated` event . + fn verify_set_code() { + System::::assert_last_event(frame_system::Event::::CodeUpdated.into()); + } +} + +#[benchmarks] +mod benchmarks { + use super::*; + + #[benchmark] + fn remark( + b: Linear<0, { *T::BlockLength::get().max.get(DispatchClass::Normal) as u32 }>, + ) -> Result<(), BenchmarkError> { + let remark_message = vec![1; b as usize]; + let caller = whitelisted_caller(); + + #[extrinsic_call] + remark(RawOrigin::Signed(caller), remark_message); + + Ok(()) + } + + #[benchmark] + fn remark_with_event( + b: Linear<0, { *T::BlockLength::get().max.get(DispatchClass::Normal) as u32 }>, + ) -> Result<(), BenchmarkError> { + let remark_message = vec![1; b as usize]; + let caller: T::AccountId = whitelisted_caller(); + let hash = T::Hashing::hash(&remark_message[..]); + + #[extrinsic_call] + remark_with_event(RawOrigin::Signed(caller.clone()), remark_message); + + System::::assert_last_event( + frame_system::Event::::Remarked { sender: caller, hash }.into(), + ); + Ok(()) + } + + #[benchmark] + fn set_heap_pages() -> Result<(), BenchmarkError> { + #[extrinsic_call] + set_heap_pages(RawOrigin::Root, Default::default()); + + Ok(()) + } + + #[benchmark] + fn set_code() -> Result<(), BenchmarkError> { + let runtime_blob = T::prepare_set_code_data(); + T::setup_set_code_requirements(&runtime_blob)?; + + #[extrinsic_call] + set_code(RawOrigin::Root, runtime_blob); + + T::verify_set_code(); + Ok(()) + } + + #[benchmark(extra)] + fn set_code_without_checks() -> Result<(), BenchmarkError> { + // Assume Wasm ~4MB + let code = vec![1; 4_000_000 as usize]; + T::setup_set_code_requirements(&code)?; + + #[block] + { + System::::set_code_without_checks(RawOrigin::Root.into(), code)?; + } + + let current_code = + storage::unhashed::get_raw(well_known_keys::CODE).ok_or("Code not stored.")?; + assert_eq!(current_code.len(), 4_000_000 as usize); + Ok(()) + } + + #[benchmark(skip_meta)] + fn set_storage(i: Linear<0, { 1_000 }>) -> Result<(), BenchmarkError> { + // Set up i items to add + let mut items = Vec::new(); + for j in 0..i { + let hash = (i, j).using_encoded(T::Hashing::hash).as_ref().to_vec(); + items.push((hash.clone(), hash.clone())); + } + + let items_to_verify = items.clone(); + + #[extrinsic_call] + set_storage(RawOrigin::Root, items); + + // Verify that they're actually in the storage. + for (item, _) in items_to_verify { + let value = storage::unhashed::get_raw(&item).ok_or("No value stored")?; + assert_eq!(value, *item); + } + Ok(()) + } + + #[benchmark(skip_meta)] + fn kill_storage(i: Linear<0, { 1_000 }>) -> Result<(), BenchmarkError> { + // Add i items to storage + let mut items = Vec::with_capacity(i as usize); + for j in 0..i { + let hash = (i, j).using_encoded(T::Hashing::hash).as_ref().to_vec(); + storage::unhashed::put_raw(&hash, &hash); + items.push(hash); + } + + // Verify that they're actually in the storage. + for item in &items { + let value = storage::unhashed::get_raw(item).ok_or("No value stored")?; + assert_eq!(value, *item); + } + + let items_to_verify = items.clone(); + + #[extrinsic_call] + kill_storage(RawOrigin::Root, items); + + // Verify that they're not in the storage anymore. + for item in items_to_verify { + assert!(storage::unhashed::get_raw(&item).is_none()); + } + Ok(()) + } + + #[benchmark(skip_meta)] + fn kill_prefix(p: Linear<0, { 1_000 }>) -> Result<(), BenchmarkError> { + let prefix = p.using_encoded(T::Hashing::hash).as_ref().to_vec(); + let mut items = Vec::with_capacity(p as usize); + // add p items that share a prefix + for i in 0..p { + let hash = (p, i).using_encoded(T::Hashing::hash).as_ref().to_vec(); + let key = [&prefix[..], &hash[..]].concat(); + storage::unhashed::put_raw(&key, &key); + items.push(key); + } + + // Verify that they're actually in the storage. + for item in &items { + let value = storage::unhashed::get_raw(item).ok_or("No value stored")?; + assert_eq!(value, *item); + } + + #[extrinsic_call] + kill_prefix(RawOrigin::Root, prefix, p); + + // Verify that they're not in the storage anymore. + for item in items { + assert!(storage::unhashed::get_raw(&item).is_none()); + } + Ok(()) + } + + #[benchmark] + fn authorize_upgrade() -> Result<(), BenchmarkError> { + let runtime_blob = T::prepare_set_code_data(); + T::setup_set_code_requirements(&runtime_blob)?; + let hash = T::Hashing::hash(&runtime_blob); + + #[extrinsic_call] + authorize_upgrade(RawOrigin::Root, hash); + + assert!(System::::authorized_upgrade().is_some()); + Ok(()) + } + + #[benchmark] + fn apply_authorized_upgrade() -> Result<(), BenchmarkError> { + let runtime_blob = T::prepare_set_code_data(); + T::setup_set_code_requirements(&runtime_blob)?; + let hash = T::Hashing::hash(&runtime_blob); + // Will be heavier when it needs to do verification (i.e. don't use `...without_checks`). + System::::authorize_upgrade(RawOrigin::Root.into(), hash)?; + + #[extrinsic_call] + apply_authorized_upgrade(RawOrigin::Root, runtime_blob); + + // Can't check for `CodeUpdated` in parachain upgrades. Just check that the authorization is + // gone. + assert!(System::::authorized_upgrade().is_none()); + 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 29100faa75142a8b945bf15f1870e9c3d685d35e..e55038aeb9551f1bbee2f38371b1e0c63371cce5 100644 --- a/substrate/frame/system/benchmarking/src/lib.rs +++ b/substrate/frame/system/benchmarking/src/lib.rs @@ -15,221 +15,15 @@ // See the License for the specific language governing permissions and // limitations under the License. -// Benchmarks for Utility Pallet +//! Frame System benchmarks. #![cfg_attr(not(feature = "std"), no_std)] -#![cfg(feature = "runtime-benchmarks")] -use codec::Encode; -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}; +#[cfg(feature = "runtime-benchmarks")] +pub mod inner; -mod mock; +#[cfg(feature = "runtime-benchmarks")] +pub use inner::*; -pub struct Pallet(System); -pub trait Config: frame_system::Config { - /// Adds ability to the Runtime to test against their sample code. - /// - /// Default is `../res/kitchensink_runtime.compact.compressed.wasm`. - fn prepare_set_code_data() -> Vec { - include_bytes!("../res/kitchensink_runtime.compact.compressed.wasm").to_vec() - } - - /// Adds ability to the Runtime to prepare/initialize before running benchmark `set_code`. - fn setup_set_code_requirements(_code: &Vec) -> Result<(), BenchmarkError> { - Ok(()) - } - - /// Adds ability to the Runtime to do custom validation after benchmark. - /// - /// Default is checking for `CodeUpdated` event . - fn verify_set_code() { - System::::assert_last_event(frame_system::Event::::CodeUpdated.into()); - } -} - -#[benchmarks] -mod benchmarks { - use super::*; - - #[benchmark] - fn remark( - b: Linear<0, { *T::BlockLength::get().max.get(DispatchClass::Normal) as u32 }>, - ) -> Result<(), BenchmarkError> { - let remark_message = vec![1; b as usize]; - let caller = whitelisted_caller(); - - #[extrinsic_call] - remark(RawOrigin::Signed(caller), remark_message); - - Ok(()) - } - - #[benchmark] - fn remark_with_event( - b: Linear<0, { *T::BlockLength::get().max.get(DispatchClass::Normal) as u32 }>, - ) -> Result<(), BenchmarkError> { - let remark_message = vec![1; b as usize]; - let caller: T::AccountId = whitelisted_caller(); - let hash = T::Hashing::hash(&remark_message[..]); - - #[extrinsic_call] - remark_with_event(RawOrigin::Signed(caller.clone()), remark_message); - - System::::assert_last_event( - frame_system::Event::::Remarked { sender: caller, hash }.into(), - ); - Ok(()) - } - - #[benchmark] - fn set_heap_pages() -> Result<(), BenchmarkError> { - #[extrinsic_call] - set_heap_pages(RawOrigin::Root, Default::default()); - - Ok(()) - } - - #[benchmark] - fn set_code() -> Result<(), BenchmarkError> { - let runtime_blob = T::prepare_set_code_data(); - T::setup_set_code_requirements(&runtime_blob)?; - - #[extrinsic_call] - set_code(RawOrigin::Root, runtime_blob); - - T::verify_set_code(); - Ok(()) - } - - #[benchmark(extra)] - fn set_code_without_checks() -> Result<(), BenchmarkError> { - // Assume Wasm ~4MB - let code = vec![1; 4_000_000 as usize]; - T::setup_set_code_requirements(&code)?; - - #[block] - { - System::::set_code_without_checks(RawOrigin::Root.into(), code)?; - } - - let current_code = - storage::unhashed::get_raw(well_known_keys::CODE).ok_or("Code not stored.")?; - assert_eq!(current_code.len(), 4_000_000 as usize); - Ok(()) - } - - #[benchmark(skip_meta)] - fn set_storage(i: Linear<0, { 1_000 }>) -> Result<(), BenchmarkError> { - // Set up i items to add - let mut items = Vec::new(); - for j in 0..i { - let hash = (i, j).using_encoded(T::Hashing::hash).as_ref().to_vec(); - items.push((hash.clone(), hash.clone())); - } - - let items_to_verify = items.clone(); - - #[extrinsic_call] - set_storage(RawOrigin::Root, items); - - // Verify that they're actually in the storage. - for (item, _) in items_to_verify { - let value = storage::unhashed::get_raw(&item).ok_or("No value stored")?; - assert_eq!(value, *item); - } - Ok(()) - } - - #[benchmark(skip_meta)] - fn kill_storage(i: Linear<0, { 1_000 }>) -> Result<(), BenchmarkError> { - // Add i items to storage - let mut items = Vec::with_capacity(i as usize); - for j in 0..i { - let hash = (i, j).using_encoded(T::Hashing::hash).as_ref().to_vec(); - storage::unhashed::put_raw(&hash, &hash); - items.push(hash); - } - - // Verify that they're actually in the storage. - for item in &items { - let value = storage::unhashed::get_raw(item).ok_or("No value stored")?; - assert_eq!(value, *item); - } - - let items_to_verify = items.clone(); - - #[extrinsic_call] - kill_storage(RawOrigin::Root, items); - - // Verify that they're not in the storage anymore. - for item in items_to_verify { - assert!(storage::unhashed::get_raw(&item).is_none()); - } - Ok(()) - } - - #[benchmark(skip_meta)] - fn kill_prefix(p: Linear<0, { 1_000 }>) -> Result<(), BenchmarkError> { - let prefix = p.using_encoded(T::Hashing::hash).as_ref().to_vec(); - let mut items = Vec::with_capacity(p as usize); - // add p items that share a prefix - for i in 0..p { - let hash = (p, i).using_encoded(T::Hashing::hash).as_ref().to_vec(); - let key = [&prefix[..], &hash[..]].concat(); - storage::unhashed::put_raw(&key, &key); - items.push(key); - } - - // Verify that they're actually in the storage. - for item in &items { - let value = storage::unhashed::get_raw(item).ok_or("No value stored")?; - assert_eq!(value, *item); - } - - #[extrinsic_call] - kill_prefix(RawOrigin::Root, prefix, p); - - // Verify that they're not in the storage anymore. - for item in items { - assert!(storage::unhashed::get_raw(&item).is_none()); - } - Ok(()) - } - - #[benchmark] - fn authorize_upgrade() -> Result<(), BenchmarkError> { - let runtime_blob = T::prepare_set_code_data(); - T::setup_set_code_requirements(&runtime_blob)?; - let hash = T::Hashing::hash(&runtime_blob); - - #[extrinsic_call] - authorize_upgrade(RawOrigin::Root, hash); - - assert!(System::::authorized_upgrade().is_some()); - Ok(()) - } - - #[benchmark] - fn apply_authorized_upgrade() -> Result<(), BenchmarkError> { - let runtime_blob = T::prepare_set_code_data(); - T::setup_set_code_requirements(&runtime_blob)?; - let hash = T::Hashing::hash(&runtime_blob); - // Will be heavier when it needs to do verification (i.e. don't use `...without_checks`). - System::::authorize_upgrade(RawOrigin::Root.into(), hash)?; - - #[extrinsic_call] - apply_authorized_upgrade(RawOrigin::Root, runtime_blob); - - // Can't check for `CodeUpdated` in parachain upgrades. Just check that the authorization is - // gone. - assert!(System::::authorized_upgrade().is_none()); - Ok(()) - } - - impl_benchmark_test_suite!(Pallet, crate::mock::new_test_ext(), crate::mock::Test); -} +#[cfg(all(feature = "runtime-benchmarks", test))] +pub(crate) mod mock; diff --git a/substrate/frame/system/rpc/runtime-api/Cargo.toml b/substrate/frame/system/rpc/runtime-api/Cargo.toml index 70e66769a8b3de7c87e2350367ea4477d10d3776..b134cc3b617308265222d9dec6669dbbacf7f566 100644 --- a/substrate/frame/system/rpc/runtime-api/Cargo.toml +++ b/substrate/frame/system/rpc/runtime-api/Cargo.toml @@ -16,7 +16,7 @@ workspace = true targets = ["x86_64-unknown-linux-gnu"] [dependencies] -codec = { package = "parity-scale-codec", version = "3.6.1", default-features = false } +codec = { package = "parity-scale-codec", version = "3.6.12", default-features = false } sp-api = { path = "../../../../primitives/api", default-features = false } [features] diff --git a/substrate/frame/system/src/extensions/check_nonce.rs b/substrate/frame/system/src/extensions/check_nonce.rs index 7504a814aef13b0230e1067c0d95e0104ad74275..894ab72eb593b02324e5fabc37a4035efecaac5e 100644 --- a/substrate/frame/system/src/extensions/check_nonce.rs +++ b/substrate/frame/system/src/extensions/check_nonce.rs @@ -142,7 +142,7 @@ mod tests { crate::Account::::insert( 1, crate::AccountInfo { - nonce: 1, + nonce: 1u64.into(), consumers: 0, providers: 1, sufficients: 0, @@ -153,20 +153,20 @@ mod tests { let len = 0_usize; // stale assert_noop!( - CheckNonce::(0).validate(&1, CALL, &info, len), + CheckNonce::(0u64.into()).validate(&1, CALL, &info, len), InvalidTransaction::Stale ); assert_noop!( - CheckNonce::(0).pre_dispatch(&1, CALL, &info, len), + CheckNonce::(0u64.into()).pre_dispatch(&1, CALL, &info, len), InvalidTransaction::Stale ); // correct - assert_ok!(CheckNonce::(1).validate(&1, CALL, &info, len)); - assert_ok!(CheckNonce::(1).pre_dispatch(&1, CALL, &info, len)); + assert_ok!(CheckNonce::(1u64.into()).validate(&1, CALL, &info, len)); + assert_ok!(CheckNonce::(1u64.into()).pre_dispatch(&1, CALL, &info, len)); // future - assert_ok!(CheckNonce::(5).validate(&1, CALL, &info, len)); + assert_ok!(CheckNonce::(5u64.into()).validate(&1, CALL, &info, len)); assert_noop!( - CheckNonce::(5).pre_dispatch(&1, CALL, &info, len), + CheckNonce::(5u64.into()).pre_dispatch(&1, CALL, &info, len), InvalidTransaction::Future ); }) @@ -178,7 +178,7 @@ mod tests { crate::Account::::insert( 2, crate::AccountInfo { - nonce: 1, + nonce: 1u64.into(), consumers: 0, providers: 1, sufficients: 0, @@ -188,7 +188,7 @@ mod tests { crate::Account::::insert( 3, crate::AccountInfo { - nonce: 1, + nonce: 1u64.into(), consumers: 0, providers: 0, sufficients: 1, @@ -199,19 +199,19 @@ mod tests { let len = 0_usize; // Both providers and sufficients zero assert_noop!( - CheckNonce::(1).validate(&1, CALL, &info, len), + CheckNonce::(1u64.into()).validate(&1, CALL, &info, len), InvalidTransaction::Payment ); assert_noop!( - CheckNonce::(1).pre_dispatch(&1, CALL, &info, len), + CheckNonce::(1u64.into()).pre_dispatch(&1, CALL, &info, len), 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::(1u64.into()).validate(&2, CALL, &info, len)); + assert_ok!(CheckNonce::(1u64.into()).pre_dispatch(&2, 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::(1u64.into()).validate(&3, CALL, &info, len)); + assert_ok!(CheckNonce::(1u64.into()).pre_dispatch(&3, CALL, &info, len)); }) } } diff --git a/substrate/frame/system/src/extensions/check_weight.rs b/substrate/frame/system/src/extensions/check_weight.rs index 70d1e75633278c665f4c06ca22f02a96668ef964..061d543f8c311140ac692c183d08c462d0452d89 100644 --- a/substrate/frame/system/src/extensions/check_weight.rs +++ b/substrate/frame/system/src/extensions/check_weight.rs @@ -64,17 +64,6 @@ where } } - /// Checks if the current extrinsic can fit into the block with respect to block weight limits. - /// - /// Upon successes, it returns the new block weight as a `Result`. - fn check_block_weight( - info: &DispatchInfoOf, - ) -> Result { - let maximum_weight = T::BlockWeights::get(); - let all_weight = Pallet::::block_weight(); - calculate_consumed_weight::(maximum_weight, all_weight, info) - } - /// Checks if the current extrinsic can fit into the block with respect to block length limits. /// /// Upon successes, it returns the new block length as a `Result`. @@ -113,7 +102,12 @@ where len: usize, ) -> Result<(), TransactionValidityError> { let next_len = Self::check_block_length(info, len)?; - let next_weight = Self::check_block_weight(info)?; + + let all_weight = Pallet::::block_weight(); + let maximum_weight = T::BlockWeights::get(); + let next_weight = + calculate_consumed_weight::(&maximum_weight, all_weight, info)?; + check_combined_proof_size(&maximum_weight, next_len, &next_weight)?; Self::check_extrinsic_weight(info)?; crate::AllExtrinsicsLen::::put(next_len); @@ -136,8 +130,32 @@ where } } +/// Check that the combined extrinsic length and proof size together do not exceed the PoV limit. +pub fn check_combined_proof_size( + maximum_weight: &BlockWeights, + next_len: u32, + next_weight: &crate::ConsumedWeight, +) -> Result<(), TransactionValidityError> { + // This extra check ensures that the extrinsic length does not push the + // PoV over the limit. + let total_pov_size = next_weight.total().proof_size().saturating_add(next_len as u64); + if total_pov_size > maximum_weight.max_block.proof_size() { + log::debug!( + target: LOG_TARGET, + "Extrinsic exceeds total pov size: {}kb, limit: {}kb", + total_pov_size as f64/1024.0, + maximum_weight.max_block.proof_size() as f64/1024.0 + ); + return Err(InvalidTransaction::ExhaustsResources.into()) + } + Ok(()) +} + +/// Checks if the current extrinsic can fit into the block with respect to block weight limits. +/// +/// Upon successes, it returns the new block weight as a `Result`. pub fn calculate_consumed_weight( - maximum_weight: BlockWeights, + maximum_weight: &BlockWeights, mut all_weight: crate::ConsumedWeight, info: &DispatchInfoOf, ) -> Result @@ -742,17 +760,90 @@ mod tests { // when assert_ok!(calculate_consumed_weight::<::RuntimeCall>( - maximum_weight.clone(), + &maximum_weight, all_weight.clone(), - &mandatory1 + &mandatory1, )); assert_err!( calculate_consumed_weight::<::RuntimeCall>( - maximum_weight, + &maximum_weight, all_weight, - &mandatory2 + &mandatory2, ), InvalidTransaction::ExhaustsResources ); } + + #[test] + fn maximum_proof_size_includes_length() { + let maximum_weight = BlockWeights::builder() + .base_block(Weight::zero()) + .for_class(DispatchClass::non_mandatory(), |w| { + w.base_extrinsic = Weight::zero(); + w.max_total = Some(Weight::from_parts(20, 10)); + }) + .for_class(DispatchClass::Mandatory, |w| { + w.base_extrinsic = Weight::zero(); + w.reserved = Some(Weight::from_parts(5, 10)); + w.max_total = None; + }) + .build_or_panic(); + + assert_eq!(maximum_weight.max_block, Weight::from_parts(20, 10)); + + // We have 10 reftime and 5 proof size left over. + let next_weight = crate::ConsumedWeight::new(|class| match class { + DispatchClass::Normal => Weight::from_parts(10, 5), + DispatchClass::Operational => Weight::from_parts(0, 0), + DispatchClass::Mandatory => Weight::zero(), + }); + + // Simple checks for the length + assert_ok!(check_combined_proof_size(&maximum_weight, 0, &next_weight)); + assert_ok!(check_combined_proof_size(&maximum_weight, 5, &next_weight)); + assert_err!( + check_combined_proof_size(&maximum_weight, 6, &next_weight), + InvalidTransaction::ExhaustsResources + ); + + // We have 10 reftime and 0 proof size left over. + let next_weight = crate::ConsumedWeight::new(|class| match class { + DispatchClass::Normal => Weight::from_parts(10, 10), + DispatchClass::Operational => Weight::from_parts(0, 0), + DispatchClass::Mandatory => Weight::zero(), + }); + assert_ok!(check_combined_proof_size(&maximum_weight, 0, &next_weight)); + assert_err!( + check_combined_proof_size(&maximum_weight, 1, &next_weight), + InvalidTransaction::ExhaustsResources + ); + + // We have 10 reftime and 2 proof size left over. + // Used weight is spread across dispatch classes this time. + let next_weight = crate::ConsumedWeight::new(|class| match class { + DispatchClass::Normal => Weight::from_parts(10, 5), + DispatchClass::Operational => Weight::from_parts(0, 3), + DispatchClass::Mandatory => Weight::zero(), + }); + assert_ok!(check_combined_proof_size(&maximum_weight, 0, &next_weight)); + assert_ok!(check_combined_proof_size(&maximum_weight, 2, &next_weight)); + assert_err!( + check_combined_proof_size(&maximum_weight, 3, &next_weight), + InvalidTransaction::ExhaustsResources + ); + + // Ref time is over the limit. Should not happen, but we should make sure that it is + // ignored. + let next_weight = crate::ConsumedWeight::new(|class| match class { + DispatchClass::Normal => Weight::from_parts(30, 5), + DispatchClass::Operational => Weight::from_parts(0, 0), + DispatchClass::Mandatory => Weight::zero(), + }); + assert_ok!(check_combined_proof_size(&maximum_weight, 0, &next_weight)); + assert_ok!(check_combined_proof_size(&maximum_weight, 5, &next_weight)); + assert_err!( + check_combined_proof_size(&maximum_weight, 6, &next_weight), + InvalidTransaction::ExhaustsResources + ); + } } diff --git a/substrate/frame/system/src/lib.rs b/substrate/frame/system/src/lib.rs index 184f27b61ed2a78fa298e4883db6d4eb39d8a184..7ed954d83aa814564f0c534951511ba23ce53b12 100644 --- a/substrate/frame/system/src/lib.rs +++ b/substrate/frame/system/src/lib.rs @@ -741,9 +741,7 @@ pub mod pallet { #[cfg(feature = "experimental")] #[pallet::call_index(8)] #[pallet::weight(task.weight())] - pub fn do_task(origin: OriginFor, task: T::RuntimeTask) -> DispatchResultWithPostInfo { - ensure_signed(origin)?; - + pub fn do_task(_origin: OriginFor, task: T::RuntimeTask) -> DispatchResultWithPostInfo { if !task.is_valid() { return Err(Error::::InvalidTask.into()) } @@ -1032,6 +1030,18 @@ pub mod pallet { }) } } + #[cfg(feature = "experimental")] + if let Call::do_task { ref task } = call { + if task.is_valid() { + return Ok(ValidTransaction { + priority: u64::max_value(), + requires: Vec::new(), + provides: vec![T::Hashing::hash_of(&task.encode()).as_ref().to_vec()], + longevity: TransactionLongevity::max_value(), + propagate: true, + }) + } + } Err(InvalidTransaction::Call.into()) } } @@ -1770,7 +1780,7 @@ impl Pallet { "[{:?}] {} extrinsics, length: {} (normal {}%, op: {}%, mandatory {}%) / normal weight:\ {} ({}%) op weight {} ({}%) / mandatory weight {} ({}%)", Self::block_number(), - Self::extrinsic_index().unwrap_or_default(), + Self::extrinsic_count(), Self::all_extrinsics_len(), sp_runtime::Percent::from_rational( Self::all_extrinsics_len(), diff --git a/substrate/frame/system/src/mock.rs b/substrate/frame/system/src/mock.rs index e1959e572e99cae45dcdf4960139298defbf81b2..fff848b3b0e50bde09527856f76c6ae3c84f6ea7 100644 --- a/substrate/frame/system/src/mock.rs +++ b/substrate/frame/system/src/mock.rs @@ -17,7 +17,7 @@ use crate::{self as frame_system, *}; use frame_support::{derive_impl, parameter_types}; -use sp_runtime::{BuildStorage, Perbill}; +use sp_runtime::{type_with_default::TypeWithDefault, BuildStorage, Perbill}; type Block = mocking::MockBlock; @@ -78,6 +78,14 @@ impl OnKilledAccount for RecordKilled { } } +#[derive(Debug, TypeInfo)] +pub struct DefaultNonceProvider; +impl Get for DefaultNonceProvider { + fn get() -> u64 { + System::block_number() + } +} + #[derive_impl(frame_system::config_preludes::TestDefaultConfig)] impl Config for Test { type BlockWeights = RuntimeBlockWeights; @@ -87,6 +95,7 @@ impl Config for Test { type AccountData = u32; type OnKilledAccount = RecordKilled; type MultiBlockMigrator = MockedMigrator; + type Nonce = TypeWithDefault; } parameter_types! { diff --git a/substrate/frame/system/src/tests.rs b/substrate/frame/system/src/tests.rs index b889b5ca046efe557e7706870c11febce8a358b2..b2cd017e1e206d9bf0f486bc964a4514789dcadc 100644 --- a/substrate/frame/system/src/tests.rs +++ b/substrate/frame/system/src/tests.rs @@ -21,14 +21,14 @@ use frame_support::{ dispatch::{Pays, PostDispatchInfo, WithPostDispatchInfo}, traits::{OnRuntimeUpgrade, WhitelistedStorageKeys}, }; -use std::collections::BTreeSet; - use mock::{RuntimeOrigin, *}; use sp_core::{hexdisplay::HexDisplay, H256}; use sp_runtime::{ traits::{BlakeTwo256, Header}, DispatchError, DispatchErrorWithPostInfo, }; +use std::collections::BTreeSet; +use substrate_test_runtime_client::WasmExecutor; #[test] fn check_whitelist() { @@ -102,7 +102,13 @@ fn stored_map_works() { assert_eq!( Account::::get(0), - AccountInfo { nonce: 0, providers: 1, consumers: 0, sufficients: 0, data: 42 } + AccountInfo { + nonce: 0u64.into(), + providers: 1, + consumers: 0, + sufficients: 0, + data: 42 + } ); assert_ok!(System::inc_consumers(&0)); @@ -126,26 +132,26 @@ fn provider_ref_handover_to_self_sufficient_ref_works() { new_test_ext().execute_with(|| { assert_eq!(System::inc_providers(&0), IncRefStatus::Created); System::inc_account_nonce(&0); - assert_eq!(System::account_nonce(&0), 1); + assert_eq!(System::account_nonce(&0), 1u64.into()); // a second reference coming and going doesn't change anything. assert_eq!(System::inc_sufficients(&0), IncRefStatus::Existed); assert_eq!(System::dec_sufficients(&0), DecRefStatus::Exists); - assert_eq!(System::account_nonce(&0), 1); + assert_eq!(System::account_nonce(&0), 1u64.into()); // a provider reference coming and going doesn't change anything. assert_eq!(System::inc_providers(&0), IncRefStatus::Existed); assert_eq!(System::dec_providers(&0).unwrap(), DecRefStatus::Exists); - assert_eq!(System::account_nonce(&0), 1); + assert_eq!(System::account_nonce(&0), 1u64.into()); // decreasing the providers with a self-sufficient present should not delete the account assert_eq!(System::inc_sufficients(&0), IncRefStatus::Existed); assert_eq!(System::dec_providers(&0).unwrap(), DecRefStatus::Exists); - assert_eq!(System::account_nonce(&0), 1); + assert_eq!(System::account_nonce(&0), 1u64.into()); // decreasing the sufficients should delete the account assert_eq!(System::dec_sufficients(&0), DecRefStatus::Reaped); - assert_eq!(System::account_nonce(&0), 0); + assert_eq!(System::account_nonce(&0), 0u64.into()); }); } @@ -154,26 +160,26 @@ fn self_sufficient_ref_handover_to_provider_ref_works() { new_test_ext().execute_with(|| { assert_eq!(System::inc_sufficients(&0), IncRefStatus::Created); System::inc_account_nonce(&0); - assert_eq!(System::account_nonce(&0), 1); + assert_eq!(System::account_nonce(&0), 1u64.into()); // a second reference coming and going doesn't change anything. assert_eq!(System::inc_providers(&0), IncRefStatus::Existed); assert_eq!(System::dec_providers(&0).unwrap(), DecRefStatus::Exists); - assert_eq!(System::account_nonce(&0), 1); + assert_eq!(System::account_nonce(&0), 1u64.into()); // a sufficient reference coming and going doesn't change anything. assert_eq!(System::inc_sufficients(&0), IncRefStatus::Existed); assert_eq!(System::dec_sufficients(&0), DecRefStatus::Exists); - assert_eq!(System::account_nonce(&0), 1); + assert_eq!(System::account_nonce(&0), 1u64.into()); // decreasing the sufficients with a provider present should not delete the account assert_eq!(System::inc_providers(&0), IncRefStatus::Existed); assert_eq!(System::dec_sufficients(&0), DecRefStatus::Exists); - assert_eq!(System::account_nonce(&0), 1); + assert_eq!(System::account_nonce(&0), 1u64.into()); // decreasing the providers should delete the account assert_eq!(System::dec_providers(&0).unwrap(), DecRefStatus::Reaped); - assert_eq!(System::account_nonce(&0), 0); + assert_eq!(System::account_nonce(&0), 0u64.into()); }); } @@ -182,7 +188,7 @@ fn sufficient_cannot_support_consumer() { new_test_ext().execute_with(|| { assert_eq!(System::inc_sufficients(&0), IncRefStatus::Created); System::inc_account_nonce(&0); - assert_eq!(System::account_nonce(&0), 1); + assert_eq!(System::account_nonce(&0), 1u64.into()); assert_noop!(System::inc_consumers(&0), DispatchError::NoProviders); assert_eq!(System::inc_providers(&0), IncRefStatus::Existed); @@ -198,18 +204,18 @@ fn provider_required_to_support_consumer() { assert_eq!(System::inc_providers(&0), IncRefStatus::Created); System::inc_account_nonce(&0); - assert_eq!(System::account_nonce(&0), 1); + assert_eq!(System::account_nonce(&0), 1u64.into()); assert_eq!(System::inc_providers(&0), IncRefStatus::Existed); assert_eq!(System::dec_providers(&0).unwrap(), DecRefStatus::Exists); - assert_eq!(System::account_nonce(&0), 1); + assert_eq!(System::account_nonce(&0), 1u64.into()); assert_ok!(System::inc_consumers(&0)); assert_noop!(System::dec_providers(&0), DispatchError::ConsumerRemaining); System::dec_consumers(&0); assert_eq!(System::dec_providers(&0).unwrap(), DecRefStatus::Reaped); - assert_eq!(System::account_nonce(&0), 0); + assert_eq!(System::account_nonce(&0), 0u64.into()); }); } @@ -653,7 +659,7 @@ fn assert_runtime_updated_digest(num: usize) { #[test] fn set_code_with_real_wasm_blob() { - let executor = substrate_test_runtime_client::new_native_or_wasm_executor(); + let executor = WasmExecutor::default(); let mut ext = new_test_ext(); ext.register_extension(sp_core::traits::ReadRuntimeVersionExt::new(executor)); ext.execute_with(|| { @@ -679,7 +685,7 @@ fn set_code_with_real_wasm_blob() { fn set_code_rejects_during_mbm() { Ongoing::set(true); - let executor = substrate_test_runtime_client::new_native_or_wasm_executor(); + let executor = substrate_test_runtime_client::WasmExecutor::default(); let mut ext = new_test_ext(); ext.register_extension(sp_core::traits::ReadRuntimeVersionExt::new(executor)); ext.execute_with(|| { @@ -699,7 +705,7 @@ fn set_code_rejects_during_mbm() { #[test] fn set_code_via_authorization_works() { - let executor = substrate_test_runtime_client::new_native_or_wasm_executor(); + let executor = substrate_test_runtime_client::WasmExecutor::default(); let mut ext = new_test_ext(); ext.register_extension(sp_core::traits::ReadRuntimeVersionExt::new(executor)); ext.execute_with(|| { @@ -739,7 +745,7 @@ fn set_code_via_authorization_works() { #[test] fn runtime_upgraded_with_set_storage() { - let executor = substrate_test_runtime_client::new_native_or_wasm_executor(); + let executor = substrate_test_runtime_client::WasmExecutor::default(); let mut ext = new_test_ext(); ext.register_extension(sp_core::traits::ReadRuntimeVersionExt::new(executor)); ext.execute_with(|| { @@ -858,3 +864,20 @@ fn last_runtime_upgrade_spec_version_usage() { } } } + +#[test] +fn test_default_account_nonce() { + new_test_ext().execute_with(|| { + System::set_block_number(2); + assert_eq!(System::account_nonce(&1), 2u64.into()); + + System::inc_account_nonce(&1); + assert_eq!(System::account_nonce(&1), 3u64.into()); + + System::set_block_number(5); + assert_eq!(System::account_nonce(&1), 3u64.into()); + + Account::::remove(&1); + assert_eq!(System::account_nonce(&1), 5u64.into()); + }); +} diff --git a/substrate/frame/timestamp/Cargo.toml b/substrate/frame/timestamp/Cargo.toml index da49b29c89b78f26b3f5eee35e81b7d2dacf8bb8..93ce09611b55dc49746ad5e99fa98b21cf25ea6d 100644 --- a/substrate/frame/timestamp/Cargo.toml +++ b/substrate/frame/timestamp/Cargo.toml @@ -17,7 +17,7 @@ workspace = true targets = ["x86_64-unknown-linux-gnu"] [dependencies] -codec = { package = "parity-scale-codec", version = "3.6.1", default-features = false, features = ["derive", "max-encoded-len"] } +codec = { package = "parity-scale-codec", version = "3.6.12", default-features = false, features = ["derive", "max-encoded-len"] } log = { workspace = true } scale-info = { version = "2.11.1", default-features = false, features = ["derive"] } frame-benchmarking = { path = "../benchmarking", default-features = false, optional = true } diff --git a/substrate/frame/tips/Cargo.toml b/substrate/frame/tips/Cargo.toml index a2acf0638ffb0717ece5c132009b983c86ef2072..bcd54461406ead0f1bd67ab427c023d91b63fa0e 100644 --- a/substrate/frame/tips/Cargo.toml +++ b/substrate/frame/tips/Cargo.toml @@ -16,7 +16,7 @@ workspace = true targets = ["x86_64-unknown-linux-gnu"] [dependencies] -codec = { package = "parity-scale-codec", version = "3.6.1", default-features = false, features = ["derive"] } +codec = { package = "parity-scale-codec", version = "3.6.12", default-features = false, features = ["derive"] } log = { workspace = true } scale-info = { version = "2.11.1", default-features = false, features = ["derive"] } serde = { features = ["derive"], optional = true, workspace = true, default-features = true } diff --git a/substrate/frame/transaction-payment/Cargo.toml b/substrate/frame/transaction-payment/Cargo.toml index 24e5a714f0fe3aee0a5c2d74d3d837e8b969cdb1..4f7da9ae46fabe7b4dcb92bd40eab2ea339175a8 100644 --- a/substrate/frame/transaction-payment/Cargo.toml +++ b/substrate/frame/transaction-payment/Cargo.toml @@ -16,7 +16,7 @@ workspace = true targets = ["x86_64-unknown-linux-gnu"] [dependencies] -codec = { package = "parity-scale-codec", version = "3.6.1", default-features = false, features = [ +codec = { package = "parity-scale-codec", version = "3.6.12", default-features = false, features = [ "derive", ] } scale-info = { version = "2.11.1", default-features = false, features = ["derive"] } 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 fef9afdee05f37cbd2999b1bbfecb07f2601d3bd..177621d9adbd102369fe0466cf962441f7591e42 100644 --- a/substrate/frame/transaction-payment/asset-conversion-tx-payment/Cargo.toml +++ b/substrate/frame/transaction-payment/asset-conversion-tx-payment/Cargo.toml @@ -23,7 +23,7 @@ frame-support = { path = "../../support", default-features = false } frame-system = { path = "../../system", default-features = false } pallet-asset-conversion = { path = "../../asset-conversion", default-features = false } pallet-transaction-payment = { path = "..", default-features = false } -codec = { package = "parity-scale-codec", version = "3.2.2", default-features = false, features = ["derive"] } +codec = { package = "parity-scale-codec", version = "3.6.12", default-features = false, features = ["derive"] } scale-info = { version = "2.11.1", default-features = false, features = ["derive"] } [dev-dependencies] 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 d61558cf536362bbaa5abd4a451fa5f4589a85bd..9a2b22b817096916193db338df62269415ec7a52 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 @@ -244,6 +244,11 @@ ord_parameter_types! { pub const AssetConversionOrigin: u64 = AccountIdConversion::::into_account_truncating(&AssetConversionPalletId::get()); } +pub type PoolIdToAccountId = pallet_asset_conversion::AccountIdConverter< + AssetConversionPalletId, + (NativeOrWithId, NativeOrWithId), +>; + impl pallet_asset_conversion::Config for Runtime { type RuntimeEvent = RuntimeEvent; type Balance = Balance; @@ -252,8 +257,8 @@ impl pallet_asset_conversion::Config for Runtime { type Assets = UnionOf, AccountId>; type PoolId = (Self::AssetKind, Self::AssetKind); type PoolLocator = Chain< - WithFirstAsset>, - Ascending>, + WithFirstAsset, PoolIdToAccountId>, + Ascending, PoolIdToAccountId>, >; type PoolAssetId = u32; type PoolAssets = PoolAssets; 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..aa2f26f3a6a8d5ce0edc45e1694c51a2c12da44c 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 @@ -201,6 +201,8 @@ fn transaction_payment_in_asset_possible() { .base_weight(Weight::from_parts(base_weight, 0)) .build() .execute_with(|| { + System::set_block_number(1); + // create the asset let asset_id = 1; let min_balance = 2; @@ -246,6 +248,12 @@ fn transaction_payment_in_asset_possible() { // check that fee was charged in the given asset assert_eq!(Assets::balance(asset_id, caller), balance - fee_in_asset); + System::assert_has_event(RuntimeEvent::Assets(pallet_assets::Event::Withdrawn { + asset_id, + who: caller, + amount: fee_in_asset, + })); + assert_ok!(ChargeAssetTxPayment::::post_dispatch( Some(pre), &info_from_weight(WEIGHT_5), // estimated tx weight @@ -385,6 +393,8 @@ fn asset_transaction_payment_with_tip_and_refund() { .base_weight(Weight::from_parts(base_weight, 0)) .build() .execute_with(|| { + System::set_block_number(1); + // create the asset let asset_id = 1; let min_balance = 2; @@ -434,6 +444,12 @@ fn asset_transaction_payment_with_tip_and_refund() { ) .unwrap(); + System::assert_has_event(RuntimeEvent::Assets(pallet_assets::Event::Withdrawn { + asset_id, + who: caller, + amount: fee_in_asset, + })); + assert_ok!(ChargeAssetTxPayment::::post_dispatch( Some(pre), &info_from_weight(WEIGHT_100), @@ -451,6 +467,12 @@ fn asset_transaction_payment_with_tip_and_refund() { balance - fee_in_asset + expected_token_refund ); assert_eq!(Balances::free_balance(caller), 20 * balance_factor); + + System::assert_has_event(RuntimeEvent::Assets(pallet_assets::Event::Deposited { + asset_id, + who: caller, + amount: expected_token_refund, + })); }); } diff --git a/substrate/frame/transaction-payment/asset-tx-payment/Cargo.toml b/substrate/frame/transaction-payment/asset-tx-payment/Cargo.toml index fc4f1aecc15ee910ef90ffd18b39173d5de096e9..a4a8efad869c84ef9fe8b905ae5c38a9ed94b614 100644 --- a/substrate/frame/transaction-payment/asset-tx-payment/Cargo.toml +++ b/substrate/frame/transaction-payment/asset-tx-payment/Cargo.toml @@ -28,7 +28,7 @@ pallet-transaction-payment = { path = "..", default-features = false } frame-benchmarking = { path = "../../benchmarking", default-features = false, optional = true } # Other dependencies -codec = { package = "parity-scale-codec", version = "3.6.1", default-features = false, features = ["derive"] } +codec = { package = "parity-scale-codec", version = "3.6.12", default-features = false, features = ["derive"] } scale-info = { version = "2.11.1", default-features = false, features = ["derive"] } serde = { optional = true, workspace = true, default-features = true } 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..098ecf11dd92fd41cf1ad3bcddaa679da1d6c0fb 100644 --- a/substrate/frame/transaction-payment/asset-tx-payment/src/tests.rs +++ b/substrate/frame/transaction-payment/asset-tx-payment/src/tests.rs @@ -157,6 +157,8 @@ fn transaction_payment_in_asset_possible() { .base_weight(Weight::from_parts(base_weight, 0)) .build() .execute_with(|| { + System::set_block_number(1); + // create the asset let asset_id = 1; let min_balance = 2; @@ -188,6 +190,12 @@ fn transaction_payment_in_asset_possible() { assert_eq!(Assets::balance(asset_id, caller), balance - fee); assert_eq!(Assets::balance(asset_id, BLOCK_AUTHOR), 0); + System::assert_has_event(RuntimeEvent::Assets(pallet_assets::Event::Withdrawn { + asset_id, + who: caller, + amount: fee, + })); + assert_ok!(ChargeAssetTxPayment::::post_dispatch( Some(pre), &info_from_weight(Weight::from_parts(weight, 0)), @@ -198,6 +206,12 @@ fn transaction_payment_in_asset_possible() { assert_eq!(Assets::balance(asset_id, caller), balance - fee); // check that the block author gets rewarded assert_eq!(Assets::balance(asset_id, BLOCK_AUTHOR), fee); + + System::assert_has_event(RuntimeEvent::Assets(pallet_assets::Event::Deposited { + asset_id, + who: BLOCK_AUTHOR, + amount: fee, + })); }); } @@ -263,6 +277,8 @@ fn asset_transaction_payment_with_tip_and_refund() { .base_weight(Weight::from_parts(base_weight, 0)) .build() .execute_with(|| { + System::set_block_number(1); + // create the asset let asset_id = 1; let min_balance = 2; @@ -292,6 +308,12 @@ fn asset_transaction_payment_with_tip_and_refund() { .unwrap(); assert_eq!(Assets::balance(asset_id, caller), balance - fee_with_tip); + System::assert_has_event(RuntimeEvent::Assets(pallet_assets::Event::Withdrawn { + asset_id, + who: caller, + amount: fee_with_tip, + })); + let final_weight = 50; assert_ok!(ChargeAssetTxPayment::::post_dispatch( Some(pre), @@ -304,6 +326,12 @@ fn asset_transaction_payment_with_tip_and_refund() { fee_with_tip - (weight - final_weight) * min_balance / ExistentialDeposit::get(); assert_eq!(Assets::balance(asset_id, caller), balance - (final_fee)); assert_eq!(Assets::balance(asset_id, BLOCK_AUTHOR), final_fee); + + System::assert_has_event(RuntimeEvent::Assets(pallet_assets::Event::Deposited { + asset_id, + who: caller, + amount: fee_with_tip - final_fee, + })); }); } diff --git a/substrate/frame/transaction-payment/rpc/Cargo.toml b/substrate/frame/transaction-payment/rpc/Cargo.toml index 6d7f632af82813050d4c0523dcd61dc27ea512f1..2c9f814460f7cd1502779cc1645c0379611dc3d5 100644 --- a/substrate/frame/transaction-payment/rpc/Cargo.toml +++ b/substrate/frame/transaction-payment/rpc/Cargo.toml @@ -16,8 +16,8 @@ workspace = true targets = ["x86_64-unknown-linux-gnu"] [dependencies] -codec = { package = "parity-scale-codec", version = "3.6.1" } -jsonrpsee = { version = "0.22", features = ["client-core", "macros", "server"] } +codec = { package = "parity-scale-codec", version = "3.6.12" } +jsonrpsee = { version = "0.22.5", features = ["client-core", "macros", "server-core"] } 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/rpc/runtime-api/Cargo.toml b/substrate/frame/transaction-payment/rpc/runtime-api/Cargo.toml index 913dccc05c496807a7698dd3445eaaba5431002a..6c0241ec5c03c4ceb757620d6ae4f528e379c74e 100644 --- a/substrate/frame/transaction-payment/rpc/runtime-api/Cargo.toml +++ b/substrate/frame/transaction-payment/rpc/runtime-api/Cargo.toml @@ -16,7 +16,7 @@ workspace = true targets = ["x86_64-unknown-linux-gnu"] [dependencies] -codec = { package = "parity-scale-codec", version = "3.6.1", default-features = false, features = ["derive"] } +codec = { package = "parity-scale-codec", version = "3.6.12", default-features = false, features = ["derive"] } pallet-transaction-payment = { path = "../..", default-features = false } sp-api = { path = "../../../../primitives/api", default-features = false } sp-runtime = { path = "../../../../primitives/runtime", default-features = false } diff --git a/substrate/frame/transaction-payment/rpc/src/lib.rs b/substrate/frame/transaction-payment/rpc/src/lib.rs index f5323cf852e97df015aaaebac7a36f1d7525397d..050c7fb8915ec71d77fbfa9005f75f130c72be92 100644 --- a/substrate/frame/transaction-payment/rpc/src/lib.rs +++ b/substrate/frame/transaction-payment/rpc/src/lib.rs @@ -17,7 +17,7 @@ //! RPC interface for the transaction payment pallet. -use std::{convert::TryInto, sync::Arc}; +use std::sync::Arc; use codec::{Codec, Decode}; use jsonrpsee::{ diff --git a/substrate/frame/transaction-payment/skip-feeless-payment/Cargo.toml b/substrate/frame/transaction-payment/skip-feeless-payment/Cargo.toml index 8a6ee09f8dd0a4d17566ef573f242e9762cf6b1e..4d32a5123cf3fc0ef1322cedca7d2c8ef65ba51a 100644 --- a/substrate/frame/transaction-payment/skip-feeless-payment/Cargo.toml +++ b/substrate/frame/transaction-payment/skip-feeless-payment/Cargo.toml @@ -22,7 +22,7 @@ frame-support = { path = "../../support", default-features = false } frame-system = { path = "../../system", default-features = false } # Other dependencies -codec = { package = "parity-scale-codec", version = "3.6.1", default-features = false, features = ["derive"] } +codec = { package = "parity-scale-codec", version = "3.6.12", default-features = false, features = ["derive"] } scale-info = { version = "2.5.0", default-features = false, features = ["derive"] } [features] diff --git a/substrate/frame/transaction-storage/Cargo.toml b/substrate/frame/transaction-storage/Cargo.toml index 31741cf32d83edfeaa10d06060c79df07f2b50c9..bf647ca13ec1cf355e35bc9307239979ba8c8460 100644 --- a/substrate/frame/transaction-storage/Cargo.toml +++ b/substrate/frame/transaction-storage/Cargo.toml @@ -16,8 +16,8 @@ workspace = true targets = ["x86_64-unknown-linux-gnu"] [dependencies] -array-bytes = { version = "6.1", optional = true } -codec = { package = "parity-scale-codec", version = "3.6.1", default-features = false } +array-bytes = { version = "6.2.2", optional = true } +codec = { package = "parity-scale-codec", version = "3.6.12", default-features = false } scale-info = { version = "2.11.1", default-features = false, features = ["derive"] } serde = { optional = true, workspace = true, default-features = true } frame-benchmarking = { path = "../benchmarking", default-features = false, optional = true } diff --git a/substrate/frame/treasury/Cargo.toml b/substrate/frame/treasury/Cargo.toml index 34037338a52bac4d18130e6a3c88b3c3a5d3dc60..c93272af11d4664495cac40984f99fbc60b23f11 100644 --- a/substrate/frame/treasury/Cargo.toml +++ b/substrate/frame/treasury/Cargo.toml @@ -16,7 +16,7 @@ workspace = true targets = ["x86_64-unknown-linux-gnu"] [dependencies] -codec = { package = "parity-scale-codec", version = "3.6.1", default-features = false, features = [ +codec = { package = "parity-scale-codec", version = "3.6.12", default-features = false, features = [ "derive", "max-encoded-len", ] } diff --git a/substrate/frame/try-runtime/Cargo.toml b/substrate/frame/try-runtime/Cargo.toml index 15c8ca5d27a71f9d4172d5d8bd31808d7badcc3b..e4e5f1940b25b67a97ef6026daa13a83cab791a4 100644 --- a/substrate/frame/try-runtime/Cargo.toml +++ b/substrate/frame/try-runtime/Cargo.toml @@ -15,7 +15,7 @@ workspace = true targets = ["x86_64-unknown-linux-gnu"] [dependencies] -codec = { package = "parity-scale-codec", version = "3.6.1", default-features = false, features = ["derive"] } +codec = { package = "parity-scale-codec", version = "3.6.12", default-features = false, features = ["derive"] } frame-support = { path = "../support", default-features = false } sp-api = { path = "../../primitives/api", default-features = false } sp-runtime = { path = "../../primitives/runtime", default-features = false } diff --git a/substrate/frame/try-runtime/src/inner.rs b/substrate/frame/try-runtime/src/inner.rs new file mode 100644 index 0000000000000000000000000000000000000000..591124e2ad9926d0104d270769ae77fddbe78997 --- /dev/null +++ b/substrate/frame/try-runtime/src/inner.rs @@ -0,0 +1,50 @@ +// This file is part of Substrate. + +// Copyright (C) Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +//! Supporting types for try-runtime, testing and dry-running commands. + +pub use frame_support::traits::{TryStateSelect, UpgradeCheckSelect}; +use frame_support::weights::Weight; + +sp_api::decl_runtime_apis! { + /// Runtime api for testing the execution of a runtime upgrade. + pub trait TryRuntime { + /// dry-run runtime upgrades, returning the total weight consumed. + /// + /// This should do EXACTLY the same operations as the runtime would have done in the case of + /// a runtime upgrade (e.g. pallet ordering must be the same) + /// + /// Returns the consumed weight of the migration in case of a successful one, combined with + /// the total allowed block weight of the runtime. + /// + /// If `checks` is `true`, `pre_migrate` and `post_migrate` of each migration and + /// `try_state` of all pallets will be executed. Else, no. If checks are executed, the PoV + /// tracking is likely inaccurate. + fn on_runtime_upgrade(checks: UpgradeCheckSelect) -> (Weight, Weight); + + /// Execute the given block, but optionally disable state-root and signature checks. + /// + /// Optionally, a number of `try_state` hooks can also be executed after the block + /// execution. + fn execute_block( + block: Block, + state_root_check: bool, + signature_check: bool, + try_state: TryStateSelect, + ) -> Weight; + } +} diff --git a/substrate/frame/try-runtime/src/lib.rs b/substrate/frame/try-runtime/src/lib.rs index 43292efe210428980321e247807e1fc5da2d3c86..9da2dd18ca2b63c93ceb6d5522955ee0e4a3bb3e 100644 --- a/substrate/frame/try-runtime/src/lib.rs +++ b/substrate/frame/try-runtime/src/lib.rs @@ -18,36 +18,9 @@ //! Supporting types for try-runtime, testing and dry-running commands. #![cfg_attr(not(feature = "std"), no_std)] -#![cfg(feature = "try-runtime")] -pub use frame_support::traits::{TryStateSelect, UpgradeCheckSelect}; -use frame_support::weights::Weight; +#[cfg(feature = "try-runtime")] +pub mod inner; -sp_api::decl_runtime_apis! { - /// Runtime api for testing the execution of a runtime upgrade. - pub trait TryRuntime { - /// dry-run runtime upgrades, returning the total weight consumed. - /// - /// This should do EXACTLY the same operations as the runtime would have done in the case of - /// a runtime upgrade (e.g. pallet ordering must be the same) - /// - /// Returns the consumed weight of the migration in case of a successful one, combined with - /// the total allowed block weight of the runtime. - /// - /// If `checks` is `true`, `pre_migrate` and `post_migrate` of each migration and - /// `try_state` of all pallets will be executed. Else, no. If checks are executed, the PoV - /// tracking is likely inaccurate. - fn on_runtime_upgrade(checks: UpgradeCheckSelect) -> (Weight, Weight); - - /// Execute the given block, but optionally disable state-root and signature checks. - /// - /// Optionally, a number of `try_state` hooks can also be executed after the block - /// execution. - fn execute_block( - block: Block, - state_root_check: bool, - signature_check: bool, - try_state: TryStateSelect, - ) -> Weight; - } -} +#[cfg(feature = "try-runtime")] +pub use inner::*; diff --git a/substrate/frame/tx-pause/Cargo.toml b/substrate/frame/tx-pause/Cargo.toml index 5f028179037d1214aadb460fa464b79f55c05a23..e44bb90dd7f8438673f7b5a23b1e7b1c15da03b5 100644 --- a/substrate/frame/tx-pause/Cargo.toml +++ b/substrate/frame/tx-pause/Cargo.toml @@ -15,7 +15,7 @@ workspace = true targets = ["x86_64-unknown-linux-gnu"] [dependencies] -codec = { package = "parity-scale-codec", version = "3.2.2", default-features = false, features = ["derive"] } +codec = { package = "parity-scale-codec", version = "3.6.12", default-features = false, features = ["derive"] } docify = "0.2.8" frame-benchmarking = { path = "../benchmarking", default-features = false, optional = true } frame-support = { path = "../support", default-features = false } diff --git a/substrate/frame/tx-pause/src/lib.rs b/substrate/frame/tx-pause/src/lib.rs index 31be575fba7cb9e6d5335d9e1bbec3b4f9d4e723..5904b5ed316285c38526bdab47b9cb53048faec7 100644 --- a/substrate/frame/tx-pause/src/lib.rs +++ b/substrate/frame/tx-pause/src/lib.rs @@ -87,7 +87,7 @@ use frame_support::{ }; use frame_system::pallet_prelude::*; use sp_runtime::{traits::Dispatchable, DispatchResult}; -use sp_std::{convert::TryInto, prelude::*}; +use sp_std::prelude::*; pub use pallet::*; pub use weights::*; diff --git a/substrate/frame/uniques/Cargo.toml b/substrate/frame/uniques/Cargo.toml index ee6af191d33f31142a109ad7b11b6d2ff1104759..65b727b40b254567d46bff7704b4f124b78820f0 100644 --- a/substrate/frame/uniques/Cargo.toml +++ b/substrate/frame/uniques/Cargo.toml @@ -16,7 +16,7 @@ workspace = true targets = ["x86_64-unknown-linux-gnu"] [dependencies] -codec = { package = "parity-scale-codec", version = "3.6.1", default-features = false } +codec = { package = "parity-scale-codec", version = "3.6.12", default-features = false } log = { workspace = true } scale-info = { version = "2.11.1", default-features = false, features = ["derive"] } frame-benchmarking = { path = "../benchmarking", default-features = false, optional = true } diff --git a/substrate/frame/utility/Cargo.toml b/substrate/frame/utility/Cargo.toml index 2ad575ed51ffe708b9369a81ea0a4aa5d50e600b..00e8be75a3de600eada40f33afd4af94156dd554 100644 --- a/substrate/frame/utility/Cargo.toml +++ b/substrate/frame/utility/Cargo.toml @@ -16,7 +16,7 @@ workspace = true targets = ["x86_64-unknown-linux-gnu"] [dependencies] -codec = { package = "parity-scale-codec", version = "3.6.1", default-features = false } +codec = { package = "parity-scale-codec", version = "3.6.12", default-features = false } scale-info = { version = "2.11.1", 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/Cargo.toml b/substrate/frame/vesting/Cargo.toml index e71731e397788a956bd72a74e93b9ac10d0fd7a6..7372b84240364aff99bf4ecbe35929b219f8b50e 100644 --- a/substrate/frame/vesting/Cargo.toml +++ b/substrate/frame/vesting/Cargo.toml @@ -16,7 +16,7 @@ workspace = true targets = ["x86_64-unknown-linux-gnu"] [dependencies] -codec = { package = "parity-scale-codec", version = "3.6.1", default-features = false, features = [ +codec = { package = "parity-scale-codec", version = "3.6.12", default-features = false, features = [ "derive", ] } log = { workspace = true } diff --git a/substrate/frame/whitelist/Cargo.toml b/substrate/frame/whitelist/Cargo.toml index 5c28fe29142c786621eee8fc4355983e990a8981..61bbb278019de8b4c012c460ab4d836cdf8a556d 100644 --- a/substrate/frame/whitelist/Cargo.toml +++ b/substrate/frame/whitelist/Cargo.toml @@ -15,7 +15,7 @@ workspace = true targets = ["x86_64-unknown-linux-gnu"] [dependencies] -codec = { package = "parity-scale-codec", version = "3.6.1", default-features = false, features = ["derive", "max-encoded-len"] } +codec = { package = "parity-scale-codec", version = "3.6.12", default-features = false, features = ["derive", "max-encoded-len"] } scale-info = { version = "2.11.1", 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/primitives/api/Cargo.toml b/substrate/primitives/api/Cargo.toml index 2f553819b1bc09b911ad3664aa555c661863a40b..f48480f398d00729a5fb10e0c9bcfba5d62f9776 100644 --- a/substrate/primitives/api/Cargo.toml +++ b/substrate/primitives/api/Cargo.toml @@ -16,7 +16,7 @@ workspace = true targets = ["x86_64-unknown-linux-gnu"] [dependencies] -codec = { package = "parity-scale-codec", version = "3.6.1", default-features = false } +codec = { package = "parity-scale-codec", version = "3.6.12", default-features = false } sp-api-proc-macro = { path = "proc-macro", default-features = false } sp-core = { path = "../core", default-features = false } sp-std = { path = "../std", default-features = false } diff --git a/substrate/primitives/api/test/Cargo.toml b/substrate/primitives/api/test/Cargo.toml index 52a4bd7bda30b30978e15fa1277621fcdff14f59..b49f774161fd3f593872452a54e4f186a6743f6c 100644 --- a/substrate/primitives/api/test/Cargo.toml +++ b/substrate/primitives/api/test/Cargo.toml @@ -22,14 +22,14 @@ sp-tracing = { path = "../../tracing" } sp-runtime = { path = "../../runtime" } sp-consensus = { path = "../../consensus/common" } sc-block-builder = { path = "../../../client/block-builder" } -codec = { package = "parity-scale-codec", version = "3.6.1" } +codec = { package = "parity-scale-codec", version = "3.6.12" } sp-state-machine = { path = "../../state-machine" } trybuild = "1.0.88" rustversion = "1.0.6" scale-info = { version = "2.11.1", default-features = false, features = ["derive"] } [dev-dependencies] -criterion = "0.4.0" +criterion = "0.5.1" futures = "0.3.30" log = { workspace = true, default-features = true } sp-core = { path = "../../core" } diff --git a/substrate/primitives/api/test/tests/runtime_calls.rs b/substrate/primitives/api/test/tests/runtime_calls.rs index e66be7f9bf1a4b8ecb6619fe74035278e54ba7dc..5a524d1c7f4d3c6e31b2fee19e2af57e1c6365f8 100644 --- a/substrate/primitives/api/test/tests/runtime_calls.rs +++ b/substrate/primitives/api/test/tests/runtime_calls.rs @@ -122,9 +122,7 @@ fn record_proof_works() { // Use the proof backend to execute `execute_block`. let mut overlay = Default::default(); - let executor = NativeElseWasmExecutor::::new_with_wasm_executor( - WasmExecutor::builder().build(), - ); + let executor: WasmExecutor = WasmExecutor::builder().build(); execution_proof_check_on_trie_backend( &backend, &mut overlay, diff --git a/substrate/primitives/api/test/tests/ui/impl_incorrect_method_signature.stderr b/substrate/primitives/api/test/tests/ui/impl_incorrect_method_signature.stderr index 788d1807f3ba2791c4593ebc7559cdf6d44078ca..535bbb178d5f961a629fe3a0e1951c49060f83a4 100644 --- a/substrate/primitives/api/test/tests/ui/impl_incorrect_method_signature.stderr +++ b/substrate/primitives/api/test/tests/ui/impl_incorrect_method_signature.stderr @@ -9,10 +9,12 @@ note: the struct `RuntimeVersion` is defined here | | use sp_version::RuntimeVersion; | ^^^^^^^^^^^^^^^^^^^^^^^^^^ -help: consider importing one of these items instead +help: consider importing this struct instead + | +37 | fn version() -> sp_version::RuntimeVersion { + | ~~~~~~~~~~~~~~~~~~~~~~~~~~ +help: import `RuntimeVersion` directly | -37 | fn version() -> sp_api::__private::RuntimeVersion { - | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 37 | fn version() -> sp_version::RuntimeVersion { | ~~~~~~~~~~~~~~~~~~~~~~~~~~ diff --git a/substrate/primitives/api/test/tests/ui/type_reference_in_impl_runtime_apis_call.stderr b/substrate/primitives/api/test/tests/ui/type_reference_in_impl_runtime_apis_call.stderr index b4df7c068768c9236e98b44c1c2fa878311942af..f4e0f3b0afb047c4c2c377c16daa38ec1238a67e 100644 --- a/substrate/primitives/api/test/tests/ui/type_reference_in_impl_runtime_apis_call.stderr +++ b/substrate/primitives/api/test/tests/ui/type_reference_in_impl_runtime_apis_call.stderr @@ -9,10 +9,12 @@ note: the struct `RuntimeVersion` is defined here | | use sp_version::RuntimeVersion; | ^^^^^^^^^^^^^^^^^^^^^^^^^^ -help: consider importing one of these items instead +help: consider importing this struct instead + | +39 | fn version() -> sp_version::RuntimeVersion { + | ~~~~~~~~~~~~~~~~~~~~~~~~~~ +help: import `RuntimeVersion` directly | -39 | fn version() -> sp_api::__private::RuntimeVersion { - | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 39 | fn version() -> sp_version::RuntimeVersion { | ~~~~~~~~~~~~~~~~~~~~~~~~~~ @@ -30,8 +32,8 @@ note: type in trait | 27 | fn test(data: u64); | ^^^ - = note: expected signature `fn(u64)` - found signature `fn(&u64)` + = note: expected signature `fn(_)` + found signature `fn(&_)` error[E0308]: mismatched types --> tests/ui/type_reference_in_impl_runtime_apis_call.rs:33:11 diff --git a/substrate/primitives/application-crypto/Cargo.toml b/substrate/primitives/application-crypto/Cargo.toml index 20e2be4d1552f4874dad7e0902ccd9c00a660976..cbb9f2133577b93234c052dba329ed1d5f453be7 100644 --- a/substrate/primitives/application-crypto/Cargo.toml +++ b/substrate/primitives/application-crypto/Cargo.toml @@ -19,7 +19,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] sp-core = { path = "../core", default-features = false } -codec = { package = "parity-scale-codec", version = "3.6.1", default-features = false, features = ["derive"] } +codec = { package = "parity-scale-codec", version = "3.6.12", default-features = false, features = ["derive"] } scale-info = { version = "2.11.1", default-features = false, features = ["derive"] } serde = { optional = true, features = ["alloc", "derive"], workspace = true } sp-std = { path = "../std", default-features = false } diff --git a/substrate/primitives/arithmetic/Cargo.toml b/substrate/primitives/arithmetic/Cargo.toml index 16eae43c73fa60da63dd249f7934c70e805dd8f2..a9f2b80156f5ec121eea75abb389e02bbf99884e 100644 --- a/substrate/primitives/arithmetic/Cargo.toml +++ b/substrate/primitives/arithmetic/Cargo.toml @@ -17,7 +17,7 @@ workspace = true targets = ["x86_64-unknown-linux-gnu"] [dependencies] -codec = { package = "parity-scale-codec", version = "3.6.1", default-features = false, features = [ +codec = { package = "parity-scale-codec", version = "3.6.12", default-features = false, features = [ "derive", "max-encoded-len", ] } @@ -30,7 +30,7 @@ sp-std = { path = "../std", default-features = false } docify = "0.2.8" [dev-dependencies] -criterion = "0.4.0" +criterion = "0.5.1" primitive-types = "0.12.0" sp-crypto-hashing = { path = "../crypto/hashing" } rand = "0.8.5" diff --git a/substrate/primitives/authority-discovery/Cargo.toml b/substrate/primitives/authority-discovery/Cargo.toml index 88d93f40059625dd271b734c23fd635113dcbac9..72a8bb7fc47d0f76a49de45a3828424eb7a0a240 100644 --- a/substrate/primitives/authority-discovery/Cargo.toml +++ b/substrate/primitives/authority-discovery/Cargo.toml @@ -16,7 +16,7 @@ workspace = true targets = ["x86_64-unknown-linux-gnu"] [dependencies] -codec = { package = "parity-scale-codec", version = "3.6.1", default-features = false } +codec = { package = "parity-scale-codec", version = "3.6.12", default-features = false } scale-info = { version = "2.11.1", default-features = false, features = ["derive"] } sp-api = { path = "../api", default-features = false } sp-application-crypto = { path = "../application-crypto", default-features = false } diff --git a/substrate/primitives/blockchain/Cargo.toml b/substrate/primitives/blockchain/Cargo.toml index e716b61bfeb1668a42434aed147fa0810a1b7dca..5e51a2d06ed7a8f1de6fda7b2b19bf49fa515e51 100644 --- a/substrate/primitives/blockchain/Cargo.toml +++ b/substrate/primitives/blockchain/Cargo.toml @@ -17,7 +17,7 @@ workspace = true targets = ["x86_64-unknown-linux-gnu"] [dependencies] -codec = { package = "parity-scale-codec", version = "3.6.1", default-features = false, features = ["derive"] } +codec = { package = "parity-scale-codec", version = "3.6.12", default-features = false, features = ["derive"] } futures = "0.3.30" log = { workspace = true, default-features = true } parking_lot = "0.12.1" diff --git a/substrate/primitives/blockchain/src/backend.rs b/substrate/primitives/blockchain/src/backend.rs index 7a09865f858d3faa4ec1ee1fd5a2beb84e9267d7..06e5b682964a4e7672575c9e8b5460d7acb2de96 100644 --- a/substrate/primitives/blockchain/src/backend.rs +++ b/substrate/primitives/blockchain/src/backend.rs @@ -21,14 +21,17 @@ use log::warn; use parking_lot::RwLock; use sp_runtime::{ generic::BlockId, - traits::{Block as BlockT, Header as HeaderT, NumberFor, Saturating}, + traits::{Block as BlockT, Header as HeaderT, NumberFor, Zero}, Justifications, }; -use std::collections::btree_set::BTreeSet; +use std::collections::{btree_map::BTreeMap, btree_set::BTreeSet}; use crate::header_metadata::HeaderMetadata; -use crate::error::{Error, Result}; +use crate::{ + error::{Error, Result}, + tree_route, TreeRoute, +}; /// Blockchain database header backend. Does not perform any validation. pub trait HeaderBackend: Send + Sync { @@ -89,62 +92,32 @@ pub trait HeaderBackend: Send + Sync { pub trait ForkBackend: HeaderMetadata + HeaderBackend + Send + Sync { - /// Best effort to get all the header hashes that are part of the provided forks - /// starting only from the fork heads. + /// Returns block hashes for provided fork heads. It skips the fork if when blocks are missing + /// (e.g. warp-sync) and internal `tree_route` function fails. /// - /// The function tries to reconstruct the route from the fork head to the canonical chain. - /// If any of the hashes on the route can't be found in the db, the function won't be able - /// to reconstruct the route anymore. In this case it will give up expanding the current fork, - /// move on to the next ones and at the end it will return an error that also contains - /// the partially expanded forks. + /// Example: + /// G --- A1 --- A2 --- A3 --- A4 ( < fork1 ) + /// \-----C4 --- C5 ( < fork2 ) + /// We finalize A3 and call expand_fork(C5). Result = (C5,C4). fn expand_forks( &self, fork_heads: &[Block::Hash], - ) -> std::result::Result, (BTreeSet, Error)> { - let mut missing_blocks = vec![]; + ) -> std::result::Result, Error> { let mut expanded_forks = BTreeSet::new(); for fork_head in fork_heads { - let mut route_head = *fork_head; - // Insert stale blocks hashes until canonical chain is reached. - // If we reach a block that is already part of the `expanded_forks` we can stop - // processing the fork. - while expanded_forks.insert(route_head) { - match self.header_metadata(route_head) { - Ok(meta) => { - // If the parent is part of the canonical chain or there doesn't exist a - // block hash for the parent number (bug?!), we can abort adding blocks. - let parent_number = meta.number.saturating_sub(1u32.into()); - match self.hash(parent_number) { - Ok(Some(parent_hash)) => - if parent_hash == meta.parent { - break - }, - Ok(None) | Err(_) => { - missing_blocks.push(BlockId::::Number(parent_number)); - break - }, - } - - route_head = meta.parent; - }, - Err(_e) => { - missing_blocks.push(BlockId::::Hash(route_head)); - break - }, - } + match tree_route(self, *fork_head, self.info().finalized_hash) { + Ok(tree_route) => { + for block in tree_route.retracted() { + expanded_forks.insert(block.hash); + } + continue + }, + Err(_) => { + // There are cases when blocks are missing (e.g. warp-sync). + }, } } - if !missing_blocks.is_empty() { - return Err(( - expanded_forks, - Error::UnknownBlocks(format!( - "Missing stale headers {:?} while expanding forks {:?}.", - fork_heads, missing_blocks - )), - )) - } - Ok(expanded_forks) } } @@ -172,14 +145,6 @@ pub trait Backend: /// Results must be ordered best (longest, highest) chain first. fn leaves(&self) -> Result>; - /// Returns displaced leaves after the given block would be finalized. - /// - /// The returned leaves do not contain the leaves from the same height as `block_number`. - fn displaced_leaves_after_finalizing( - &self, - block_number: NumberFor, - ) -> Result>; - /// Return hashes of all blocks that are children of the block with `parent_hash`. fn children(&self, parent_hash: Block::Hash) -> Result>; @@ -255,6 +220,67 @@ pub trait Backend: } fn block_indexed_body(&self, hash: Block::Hash) -> Result>>>; + + /// Returns all leaves that will be displaced after the block finalization. + fn displaced_leaves_after_finalizing( + &self, + finalized_block_hash: Block::Hash, + finalized_block_number: NumberFor, + ) -> std::result::Result, Error> { + let mut result = DisplacedLeavesAfterFinalization::default(); + + if finalized_block_number == Zero::zero() { + return Ok(result) + } + + // For each leaf determine whether it belongs to a non-canonical branch. + for leaf_hash in self.leaves()? { + let leaf_block_header = self.expect_header(leaf_hash)?; + let leaf_number = *leaf_block_header.number(); + + let leaf_tree_route = match tree_route(self, leaf_hash, finalized_block_hash) { + Ok(tree_route) => tree_route, + Err(Error::UnknownBlock(_)) => { + // Sometimes routes can't be calculated. E.g. after warp sync. + continue; + }, + Err(e) => Err(e)?, + }; + + // Is it a stale fork? + let needs_pruning = leaf_tree_route.common_block().hash != finalized_block_hash; + + if needs_pruning { + result.displaced_leaves.insert(leaf_hash, leaf_number); + result.tree_routes.insert(leaf_hash, leaf_tree_route); + } + } + + Ok(result) + } +} + +/// Result of [`Backend::displaced_leaves_after_finalizing`]. +#[derive(Clone, Debug)] +pub struct DisplacedLeavesAfterFinalization { + /// A collection of hashes and block numbers for displaced leaves. + pub displaced_leaves: BTreeMap>, + + /// A collection of tree routes from the leaves to finalized block. + pub tree_routes: BTreeMap>, +} + +impl Default for DisplacedLeavesAfterFinalization { + fn default() -> Self { + Self { displaced_leaves: Default::default(), tree_routes: Default::default() } + } +} + +impl DisplacedLeavesAfterFinalization { + /// Returns a collection of hashes for the displaced leaves. + pub fn hashes(&self) -> impl Iterator + '_ { + self.displaced_leaves.keys().cloned() + } } /// Blockchain info diff --git a/substrate/primitives/blockchain/src/header_metadata.rs b/substrate/primitives/blockchain/src/header_metadata.rs index ccd640c0567afc6c9f9341fca754471a15a2829c..27caaae71add1a440b8a772db131329c951befbc 100644 --- a/substrate/primitives/blockchain/src/header_metadata.rs +++ b/substrate/primitives/blockchain/src/header_metadata.rs @@ -97,7 +97,7 @@ pub fn lowest_common_ancestor + ?Sized>( } /// Compute a tree-route between two blocks. See tree-route docs for more details. -pub fn tree_route>( +pub fn tree_route + ?Sized>( backend: &T, from: Block::Hash, to: Block::Hash, diff --git a/substrate/primitives/consensus/aura/Cargo.toml b/substrate/primitives/consensus/aura/Cargo.toml index b689c84f158c7bddc1e845449654056b67e78b6f..a54499178171dab260e953dd1082d512d48f6df0 100644 --- a/substrate/primitives/consensus/aura/Cargo.toml +++ b/substrate/primitives/consensus/aura/Cargo.toml @@ -17,7 +17,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] async-trait = { version = "0.1.79", optional = true } -codec = { package = "parity-scale-codec", version = "3.6.1", default-features = false } +codec = { package = "parity-scale-codec", version = "3.6.12", default-features = false } scale-info = { version = "2.11.1", default-features = false, features = ["derive"] } sp-api = { path = "../../api", default-features = false } sp-application-crypto = { path = "../../application-crypto", default-features = false } diff --git a/substrate/primitives/consensus/babe/Cargo.toml b/substrate/primitives/consensus/babe/Cargo.toml index 2420f48b1f4aa97923a556de37a06a6611ba8e05..46c032ba61a6067bd7cfa9f786706701c7e429c3 100644 --- a/substrate/primitives/consensus/babe/Cargo.toml +++ b/substrate/primitives/consensus/babe/Cargo.toml @@ -17,7 +17,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] async-trait = { version = "0.1.79", optional = true } -codec = { package = "parity-scale-codec", version = "3.6.1", default-features = false } +codec = { package = "parity-scale-codec", version = "3.6.12", default-features = false } scale-info = { version = "2.11.1", default-features = false, features = ["derive"] } serde = { features = ["alloc", "derive"], optional = true, workspace = true } sp-api = { path = "../../api", default-features = false } @@ -26,7 +26,7 @@ sp-consensus-slots = { path = "../slots", default-features = false } sp-core = { path = "../../core", default-features = false } sp-inherents = { path = "../../inherents", default-features = false } sp-runtime = { path = "../../runtime", default-features = false } -sp-timestamp = { path = "../../timestamp", optional = true } +sp-timestamp = { path = "../../timestamp", optional = true, default-features = false } [features] default = ["std"] diff --git a/substrate/primitives/consensus/beefy/Cargo.toml b/substrate/primitives/consensus/beefy/Cargo.toml index a16d943b91469d0d24ba6453e6b08a6385ec2f36..a682939a02f95064f8fed2fe7f6be0a9ad228ede 100644 --- a/substrate/primitives/consensus/beefy/Cargo.toml +++ b/substrate/primitives/consensus/beefy/Cargo.toml @@ -15,7 +15,7 @@ workspace = true targets = ["x86_64-unknown-linux-gnu"] [dependencies] -codec = { package = "parity-scale-codec", version = "3.6.1", default-features = false, features = ["derive"] } +codec = { package = "parity-scale-codec", version = "3.6.12", default-features = false, features = ["derive"] } scale-info = { version = "2.11.1", default-features = false, features = ["derive"] } serde = { optional = true, features = ["alloc", "derive"], workspace = true } sp-api = { path = "../../api", default-features = false } @@ -30,7 +30,7 @@ strum = { version = "0.26.2", features = ["derive"], default-features = false } lazy_static = { version = "1.4.0", optional = true } [dev-dependencies] -array-bytes = "6.1" +array-bytes = "6.2.2" w3f-bls = { version = "0.1.3", features = ["std"] } [features] diff --git a/substrate/primitives/consensus/beefy/src/commitment.rs b/substrate/primitives/consensus/beefy/src/commitment.rs index 4fd9e1b0a6ed14ea51ef30e5d4c6748a129d5249..8d3a6c6aa90f981ec64f5f549aaf7188d68b02f4 100644 --- a/substrate/primitives/consensus/beefy/src/commitment.rs +++ b/substrate/primitives/consensus/beefy/src/commitment.rs @@ -19,8 +19,30 @@ use alloc::{vec, vec::Vec}; use codec::{Decode, Encode, Error, Input}; use core::cmp; use scale_info::TypeInfo; +use sp_application_crypto::RuntimeAppPublic; +use sp_runtime::traits::Hash; + +use crate::{BeefyAuthorityId, Payload, ValidatorSet, ValidatorSetId}; + +/// A commitment signature, accompanied by the id of the validator that it belongs to. +#[derive(Debug)] +pub struct KnownSignature { + /// The signing validator. + pub validator_id: TAuthorityId, + /// The signature. + pub signature: TSignature, +} -use crate::{Payload, ValidatorSetId}; +impl KnownSignature<&TAuthorityId, &TSignature> { + /// Creates a `KnownSignature` from an + /// `KnownSignature<&TAuthorityId, &TSignature>`. + pub fn to_owned(&self) -> KnownSignature { + KnownSignature { + validator_id: self.validator_id.clone(), + signature: self.signature.clone(), + } + } +} /// A commitment signed by GRANDPA validators as part of BEEFY protocol. /// @@ -113,9 +135,49 @@ impl core::fmt::Display impl SignedCommitment { /// Return the number of collected signatures. - pub fn no_of_signatures(&self) -> usize { + pub fn signature_count(&self) -> usize { self.signatures.iter().filter(|x| x.is_some()).count() } + + /// Verify all the commitment signatures against the validator set that was active + /// at the block where the commitment was generated. + /// + /// Returns the valid validator-signature pairs if the commitment can be verified. + pub fn verify_signatures<'a, TAuthorityId, MsgHash>( + &'a self, + target_number: TBlockNumber, + validator_set: &'a ValidatorSet, + ) -> Result>, u32> + where + TBlockNumber: Clone + Encode + PartialEq, + TAuthorityId: RuntimeAppPublic + BeefyAuthorityId, + MsgHash: Hash, + { + if self.signatures.len() != validator_set.len() || + self.commitment.validator_set_id != validator_set.id() || + self.commitment.block_number != target_number + { + return Err(0) + } + + // Arrangement of signatures in the commitment should be in the same order + // as validators for that set. + let encoded_commitment = self.commitment.encode(); + let signatories: Vec<_> = validator_set + .validators() + .into_iter() + .zip(self.signatures.iter()) + .filter_map(|(id, maybe_signature)| { + let signature = maybe_signature.as_ref()?; + match BeefyAuthorityId::verify(id, signature, &encoded_commitment) { + true => Some(KnownSignature { validator_id: id, signature }), + false => None, + } + }) + .collect(); + + Ok(signatories) + } } /// Type to be used to denote placement of signatures @@ -439,13 +501,13 @@ mod tests { commitment, signatures: vec![None, None, Some(sigs.0), Some(sigs.1)], }; - assert_eq!(signed.no_of_signatures(), 2); + assert_eq!(signed.signature_count(), 2); // when signed.signatures[2] = None; // then - assert_eq!(signed.no_of_signatures(), 1); + assert_eq!(signed.signature_count(), 1); } #[test] diff --git a/substrate/primitives/consensus/beefy/src/lib.rs b/substrate/primitives/consensus/beefy/src/lib.rs index 70978ca559dd2b50041c45d9cab3c874e8bcc852..390c0ff71273ad4b9993a5a3e7be0265148a8c5b 100644 --- a/substrate/primitives/consensus/beefy/src/lib.rs +++ b/substrate/primitives/consensus/beefy/src/lib.rs @@ -43,7 +43,7 @@ pub mod witness; #[cfg(feature = "std")] pub mod test_utils; -pub use commitment::{Commitment, SignedCommitment, VersionedFinalityProof}; +pub use commitment::{Commitment, KnownSignature, SignedCommitment, VersionedFinalityProof}; pub use payload::{known_payloads, BeefyPayloadId, Payload, PayloadProvider}; use alloc::vec::Vec; @@ -306,14 +306,14 @@ pub struct VoteMessage { /// BEEFY happens when a voter votes on the same round/block for different payloads. /// Proving is achieved by collecting the signed commitments of conflicting votes. #[derive(Clone, Debug, Decode, Encode, PartialEq, TypeInfo)] -pub struct EquivocationProof { +pub struct DoubleVotingProof { /// The first vote in the equivocation. pub first: VoteMessage, /// The second vote in the equivocation. pub second: VoteMessage, } -impl EquivocationProof { +impl DoubleVotingProof { /// Returns the authority id of the equivocator. pub fn offender_id(&self) -> &Id { &self.first.id @@ -347,7 +347,7 @@ where /// Verifies the equivocation proof by making sure that both votes target /// different blocks and that its signatures are valid. pub fn check_equivocation_proof( - report: &EquivocationProof::Signature>, + report: &DoubleVotingProof::Signature>, ) -> bool where Id: BeefyAuthorityId + PartialEq, @@ -437,7 +437,7 @@ sp_api::decl_runtime_apis! { /// hardcoded to return `None`). Only useful in an offchain context. fn submit_report_equivocation_unsigned_extrinsic( equivocation_proof: - EquivocationProof, AuthorityId, ::Signature>, + DoubleVotingProof, AuthorityId, ::Signature>, key_owner_proof: OpaqueKeyOwnershipProof, ) -> Option<()>; diff --git a/substrate/primitives/consensus/beefy/src/test_utils.rs b/substrate/primitives/consensus/beefy/src/test_utils.rs index ec13c9c690046ae795fe50af3bfc775721dfb6ee..d7fd49214f12fe5e3f3b4174f23bb2a57e295deb 100644 --- a/substrate/primitives/consensus/beefy/src/test_utils.rs +++ b/substrate/primitives/consensus/beefy/src/test_utils.rs @@ -18,7 +18,7 @@ #[cfg(feature = "bls-experimental")] use crate::ecdsa_bls_crypto; use crate::{ - ecdsa_crypto, AuthorityIdBound, BeefySignatureHasher, Commitment, EquivocationProof, Payload, + ecdsa_crypto, AuthorityIdBound, BeefySignatureHasher, Commitment, DoubleVotingProof, Payload, ValidatorSetId, VoteMessage, }; use sp_application_crypto::{AppCrypto, AppPair, RuntimeAppPublic, Wraps}; @@ -140,7 +140,7 @@ impl From> for ecdsa_crypto::Public { pub fn generate_equivocation_proof( vote1: (u64, Payload, ValidatorSetId, &Keyring), vote2: (u64, Payload, ValidatorSetId, &Keyring), -) -> EquivocationProof { +) -> DoubleVotingProof { let signed_vote = |block_number: u64, payload: Payload, validator_set_id: ValidatorSetId, @@ -151,5 +151,5 @@ pub fn generate_equivocation_proof( }; let first = signed_vote(vote1.0, vote1.1, vote1.2, vote1.3); let second = signed_vote(vote2.0, vote2.1, vote2.2, vote2.3); - EquivocationProof { first, second } + DoubleVotingProof { first, second } } diff --git a/substrate/primitives/consensus/grandpa/Cargo.toml b/substrate/primitives/consensus/grandpa/Cargo.toml index 6c228383d003fbafa879a88577b37609ce9d0278..f63f5f3122f41f76640dcebb8dca592f31268577 100644 --- a/substrate/primitives/consensus/grandpa/Cargo.toml +++ b/substrate/primitives/consensus/grandpa/Cargo.toml @@ -17,7 +17,7 @@ workspace = true targets = ["x86_64-unknown-linux-gnu"] [dependencies] -codec = { package = "parity-scale-codec", version = "3.6.1", default-features = false, features = ["derive"] } +codec = { package = "parity-scale-codec", version = "3.6.12", default-features = false, features = ["derive"] } grandpa = { package = "finality-grandpa", version = "0.16.2", default-features = false, features = ["derive-codec"] } log = { workspace = true } scale-info = { version = "2.11.1", default-features = false, features = ["derive"] } diff --git a/substrate/primitives/consensus/pow/Cargo.toml b/substrate/primitives/consensus/pow/Cargo.toml index 7a884f865fbeea0d6e7c0fd6a6699e0a5b513769..0700e2c4f8b9f1595ca820ab0cc3fe5e963dec91 100644 --- a/substrate/primitives/consensus/pow/Cargo.toml +++ b/substrate/primitives/consensus/pow/Cargo.toml @@ -16,7 +16,7 @@ workspace = true targets = ["x86_64-unknown-linux-gnu"] [dependencies] -codec = { package = "parity-scale-codec", version = "3.6.1", default-features = false, features = ["derive"] } +codec = { package = "parity-scale-codec", version = "3.6.12", default-features = false, features = ["derive"] } sp-api = { path = "../../api", default-features = false } sp-core = { path = "../../core", default-features = false } sp-runtime = { path = "../../runtime", default-features = false } diff --git a/substrate/primitives/consensus/sassafras/Cargo.toml b/substrate/primitives/consensus/sassafras/Cargo.toml index 07304ed9b2401bfb40ac321ba476be0fd304d14e..c8eb9b76b93b0e65de11aa65116353d1e429cfb7 100644 --- a/substrate/primitives/consensus/sassafras/Cargo.toml +++ b/substrate/primitives/consensus/sassafras/Cargo.toml @@ -3,7 +3,7 @@ name = "sp-consensus-sassafras" version = "0.3.4-dev" authors.workspace = true description = "Primitives for Sassafras consensus" -edition = "2021" +edition.workspace = true license = "Apache-2.0" homepage = "https://substrate.io" repository = "https://github.com/paritytech/polkadot-sdk/" @@ -18,7 +18,7 @@ workspace = true targets = ["x86_64-unknown-linux-gnu"] [dependencies] -scale-codec = { package = "parity-scale-codec", version = "3.2.2", default-features = false } +scale-codec = { package = "parity-scale-codec", version = "3.6.12", default-features = false } scale-info = { version = "2.11.1", default-features = false, features = ["derive"] } serde = { features = ["derive"], optional = true, workspace = true } sp-api = { path = "../../api", default-features = false } diff --git a/substrate/primitives/consensus/slots/Cargo.toml b/substrate/primitives/consensus/slots/Cargo.toml index a8b12900617960f953726d1b4eac5bf585b1f6bf..dd519eab46475fb16f4768de2fab6138c5a059b4 100644 --- a/substrate/primitives/consensus/slots/Cargo.toml +++ b/substrate/primitives/consensus/slots/Cargo.toml @@ -16,7 +16,7 @@ workspace = true targets = ["x86_64-unknown-linux-gnu"] [dependencies] -codec = { package = "parity-scale-codec", version = "3.6.1", default-features = false, features = ["derive", "max-encoded-len"] } +codec = { package = "parity-scale-codec", version = "3.6.12", default-features = false, features = ["derive", "max-encoded-len"] } scale-info = { version = "2.11.1", default-features = false, features = ["derive"] } serde = { features = ["alloc", "derive"], optional = true, workspace = true } sp-timestamp = { path = "../../timestamp", default-features = false } diff --git a/substrate/primitives/core/Cargo.toml b/substrate/primitives/core/Cargo.toml index 833b2af95cd10c5b533f56affb7a50f237d54905..f931faf8bd043406d2d30943a594d94ad745ae05 100644 --- a/substrate/primitives/core/Cargo.toml +++ b/substrate/primitives/core/Cargo.toml @@ -16,7 +16,7 @@ workspace = true targets = ["x86_64-unknown-linux-gnu"] [dependencies] -codec = { package = "parity-scale-codec", version = "3.6.1", default-features = false, features = ["derive", "max-encoded-len"] } +codec = { package = "parity-scale-codec", version = "3.6.12", default-features = false, features = ["derive", "max-encoded-len"] } scale-info = { version = "2.5.0", default-features = false, features = ["derive"] } log = { workspace = true } serde = { optional = true, features = ["alloc", "derive"], workspace = true } @@ -37,18 +37,18 @@ ss58-registry = { version = "1.34.0", default-features = false } sp-std = { path = "../std", default-features = false } sp-debug-derive = { path = "../debug-derive", default-features = false } sp-storage = { path = "../storage", default-features = false } -sp-externalities = { path = "../externalities", optional = true } +sp-externalities = { path = "../externalities", optional = true, default-features = false } futures = { version = "0.3.30", optional = true } dyn-clonable = { version = "0.9.0", 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 } +itertools = { version = "0.11", optional = true } # full crypto -array-bytes = { version = "6.1" } -ed25519-zebra = { version = "3.1.0", default-features = false } +array-bytes = { version = "6.2.2" } +ed25519-zebra = { version = "4.0.3", default-features = false } blake2 = { version = "0.10.4", default-features = false, optional = true } libsecp256k1 = { version = "0.7", default-features = false, features = ["static-context"] } schnorrkel = { version = "0.11.4", features = ["preaudit_deprecated"], default-features = false } @@ -66,7 +66,7 @@ w3f-bls = { version = "0.1.3", default-features = false, optional = true } bandersnatch_vrfs = { git = "https://github.com/w3f/ring-vrf", rev = "e9782f9", default-features = false, features = ["substrate-curves"], optional = true } [dev-dependencies] -criterion = "0.4.0" +criterion = "0.5.1" serde_json = { workspace = true, default-features = true } lazy_static = "1.4.0" regex = "1.6.0" diff --git a/substrate/primitives/core/fuzz/Cargo.toml b/substrate/primitives/core/fuzz/Cargo.toml index c6b5a065b6dca7a389e6409fe623018df3cfc083..463eaea8ea30d827c6f39b7cc02e8947a085c88b 100644 --- a/substrate/primitives/core/fuzz/Cargo.toml +++ b/substrate/primitives/core/fuzz/Cargo.toml @@ -2,6 +2,7 @@ name = "sp-core-fuzz" version = "0.0.0" publish = false +edition.workspace = true [lints] workspace = true diff --git a/substrate/primitives/core/src/ed25519.rs b/substrate/primitives/core/src/ed25519.rs index a9494f2860b4c018d465eecb9eafe825e169292c..269b6bfcd8dcefc961aa10b1384d4cfe0bfdfd19 100644 --- a/substrate/primitives/core/src/ed25519.rs +++ b/substrate/primitives/core/src/ed25519.rs @@ -110,7 +110,9 @@ impl TraitPair for Pair { /// Returns true if the signature is good. fn verify>(sig: &Signature, message: M, public: &Public) -> bool { let Ok(public) = VerificationKey::try_from(public.as_slice()) else { return false }; - let Ok(signature) = ed25519_zebra::Signature::try_from(sig.as_ref()) else { return false }; + let Ok(signature) = ed25519_zebra::Signature::try_from(sig.as_slice()) else { + return false + }; public.verify(&signature, message.as_ref()).is_ok() } diff --git a/substrate/primitives/crypto/hashing/Cargo.toml b/substrate/primitives/crypto/hashing/Cargo.toml index 096650e231c8f218966883c503e21ba15e197d9b..1755164888bc9f846dd2ff587aaef5124dd8923d 100644 --- a/substrate/primitives/crypto/hashing/Cargo.toml +++ b/substrate/primitives/crypto/hashing/Cargo.toml @@ -24,7 +24,7 @@ sha3 = { version = "0.10.0", default-features = false } twox-hash = { version = "1.6.3", default-features = false, features = ["digest_0_10"] } [dev-dependencies] -criterion = "0.4.0" +criterion = "0.5.1" sp-crypto-hashing-proc-macro = { path = "proc-macro" } [[bench]] diff --git a/substrate/primitives/externalities/Cargo.toml b/substrate/primitives/externalities/Cargo.toml index 20fa3e3e397c23632a67ca86cecf1a593e48a0e2..3a0d0315e9178a0e54ba001064fb6feb65c1b731 100644 --- a/substrate/primitives/externalities/Cargo.toml +++ b/substrate/primitives/externalities/Cargo.toml @@ -17,7 +17,7 @@ workspace = true targets = ["x86_64-unknown-linux-gnu"] [dependencies] -codec = { package = "parity-scale-codec", version = "3.6.1", default-features = false } +codec = { package = "parity-scale-codec", version = "3.6.12", default-features = false } environmental = { version = "1.1.3", default-features = false } sp-storage = { path = "../storage", default-features = false } diff --git a/substrate/primitives/genesis-builder/Cargo.toml b/substrate/primitives/genesis-builder/Cargo.toml index 96e99553294120698ae69d70e9da609326fc3489..4fc8a0416fbe5f2ffdbd021dd42a3d072c61b241 100644 --- a/substrate/primitives/genesis-builder/Cargo.toml +++ b/substrate/primitives/genesis-builder/Cargo.toml @@ -16,7 +16,7 @@ workspace = true targets = ["x86_64-unknown-linux-gnu"] [dependencies] -codec = { package = "parity-scale-codec", version = "3.6.1", default-features = false, features = ["bytes"] } +codec = { package = "parity-scale-codec", version = "3.6.12", default-features = false, features = ["bytes"] } scale-info = { version = "2.10.0", default-features = false, features = ["derive"] } sp-api = { path = "../api", default-features = false } diff --git a/substrate/primitives/inherents/Cargo.toml b/substrate/primitives/inherents/Cargo.toml index c08ac459de530e55d0064561fe7171e811840c8f..c63aca801a0d7e513963b06d2ce4375f17194d3d 100644 --- a/substrate/primitives/inherents/Cargo.toml +++ b/substrate/primitives/inherents/Cargo.toml @@ -18,7 +18,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] async-trait = { version = "0.1.79", optional = true } -codec = { package = "parity-scale-codec", version = "3.6.1", default-features = false, features = ["derive"] } +codec = { package = "parity-scale-codec", version = "3.6.12", default-features = false, features = ["derive"] } scale-info = { version = "2.11.1", default-features = false, features = ["derive"] } impl-trait-for-tuples = "0.2.2" thiserror = { optional = true, workspace = true } diff --git a/substrate/primitives/io/Cargo.toml b/substrate/primitives/io/Cargo.toml index dddea4ffa232541023c91d354aa6fb2013332a98..abb16d163da060ae1d152276189157b77fb6970d 100644 --- a/substrate/primitives/io/Cargo.toml +++ b/substrate/primitives/io/Cargo.toml @@ -19,7 +19,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] bytes = { version = "1.1.0", default-features = false } -codec = { package = "parity-scale-codec", version = "3.6.1", default-features = false, features = ["bytes"] } +codec = { package = "parity-scale-codec", version = "3.6.12", default-features = false, features = ["bytes"] } sp-core = { path = "../core", default-features = false } sp-crypto-hashing = { path = "../crypto/hashing", default-features = false } sp-keystore = { path = "../keystore", default-features = false, optional = true } diff --git a/substrate/primitives/io/src/lib.rs b/substrate/primitives/io/src/lib.rs index ec32b7290330fc7a1fd76dc4d7ce86210bcceba0..c8675a9a90bd2ee16b9deca27457fafa88f8fec0 100644 --- a/substrate/primitives/io/src/lib.rs +++ b/substrate/primitives/io/src/lib.rs @@ -182,7 +182,7 @@ impl From for KillStorageResult { pub trait Storage { /// Returns the data for `key` in the storage or `None` if the key can not be found. fn get(&self, key: &[u8]) -> Option { - self.storage(key).map(|s| bytes::Bytes::from(s.to_vec())) + self.storage(key).map(bytes::Bytes::from) } /// Get `key` from storage, placing the value into `value_out` and return the number of diff --git a/substrate/primitives/keystore/Cargo.toml b/substrate/primitives/keystore/Cargo.toml index a34839358e18333154962f71e1957f9884a71a2f..313b9e1c0059cb86915ca6bfe60ddff21b2c2ffb 100644 --- a/substrate/primitives/keystore/Cargo.toml +++ b/substrate/primitives/keystore/Cargo.toml @@ -16,14 +16,14 @@ workspace = true targets = ["x86_64-unknown-linux-gnu"] [dependencies] -codec = { package = "parity-scale-codec", version = "3.6.1", default-features = false, features = ["derive"] } +codec = { package = "parity-scale-codec", version = "3.6.12", default-features = false, features = ["derive"] } 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 } [dev-dependencies] rand = "0.8.5" -rand_chacha = "0.2.2" +rand_chacha = "0.3.1" [features] default = ["std"] diff --git a/substrate/primitives/merkle-mountain-range/Cargo.toml b/substrate/primitives/merkle-mountain-range/Cargo.toml index 891f893a0c96e5d10cdb953190a1830b31ef56e4..23efc1b687c2b812be0bf1cd78e21b69941e9af8 100644 --- a/substrate/primitives/merkle-mountain-range/Cargo.toml +++ b/substrate/primitives/merkle-mountain-range/Cargo.toml @@ -15,10 +15,10 @@ workspace = true targets = ["x86_64-unknown-linux-gnu"] [dependencies] -codec = { package = "parity-scale-codec", version = "3.6.1", default-features = false } +codec = { package = "parity-scale-codec", version = "3.6.12", default-features = false } scale-info = { version = "2.11.1", default-features = false, features = ["derive"] } log = { workspace = true } -mmr-lib = { package = "ckb-merkle-mountain-range", version = "0.5.2", default-features = false } +mmr-lib = { package = "ckb-merkle-mountain-range", git = "https://github.com/paritytech/merkle-mountain-range.git", branch = "master", default-features = false } serde = { features = ["alloc", "derive"], optional = true, workspace = true } sp-api = { path = "../api", default-features = false } sp-core = { path = "../core", default-features = false } @@ -27,7 +27,7 @@ sp-runtime = { path = "../runtime", default-features = false } thiserror = { optional = true, workspace = true } [dev-dependencies] -array-bytes = "6.1" +array-bytes = "6.2.2" [features] default = ["std"] diff --git a/substrate/primitives/merkle-mountain-range/src/lib.rs b/substrate/primitives/merkle-mountain-range/src/lib.rs index c76d66bb08ea700bd6bcc1272d56310bda51881f..3740047e027829eb471a61244b460cdd58fe8cd5 100644 --- a/substrate/primitives/merkle-mountain-range/src/lib.rs +++ b/substrate/primitives/merkle-mountain-range/src/lib.rs @@ -352,15 +352,29 @@ impl_leaf_data_for_tuple!(A:0, B:1, C:2, D:3, E:4); /// An MMR proof data for a group of leaves. #[derive(codec::Encode, codec::Decode, RuntimeDebug, Clone, PartialEq, Eq, TypeInfo)] -pub struct Proof { +pub struct LeafProof { /// The indices of the leaves the proof is for. pub leaf_indices: Vec, /// Number of leaves in MMR, when the proof was generated. pub leaf_count: NodeIndex, - /// Proof elements (hashes of siblings of inner nodes on the path to the leaf). + /// Proof elements (hashes of siblings of inner nodes on the path to the leafs). pub items: Vec, } +/// An MMR ancestry proof for a prior mmr root. +#[derive(codec::Encode, codec::Decode, RuntimeDebug, Clone, PartialEq, Eq, TypeInfo)] +pub struct AncestryProof { + /// Peaks of the ancestor's mmr + pub prev_peaks: Vec, + /// Number of leaves in the ancestor's MMR. + pub prev_leaf_count: u64, + /// Number of leaves in MMR, when the proof was generated. + pub leaf_count: NodeIndex, + /// Proof elements + /// (positions and hashes of siblings of inner nodes on the path to the previous peaks). + pub items: Vec<(u64, Hash)>, +} + /// Merkle Mountain Range operation error. #[cfg_attr(feature = "std", derive(thiserror::Error))] #[derive(RuntimeDebug, codec::Encode, codec::Decode, PartialEq, Eq, TypeInfo)] @@ -437,14 +451,14 @@ sp_api::decl_runtime_apis! { fn generate_proof( block_numbers: Vec, best_known_block_number: Option - ) -> Result<(Vec, Proof), Error>; + ) -> Result<(Vec, LeafProof), Error>; /// Verify MMR proof against on-chain MMR for a batch of leaves. /// /// Note this function will use on-chain MMR root hash and check if the proof matches the hash. /// Note, the leaves should be sorted such that corresponding leaves and leaf indices have the - /// same position in both the `leaves` vector and the `leaf_indices` vector contained in the [Proof] - fn verify_proof(leaves: Vec, proof: Proof) -> Result<(), Error>; + /// same position in both the `leaves` vector and the `leaf_indices` vector contained in the [LeafProof] + fn verify_proof(leaves: Vec, proof: LeafProof) -> Result<(), Error>; /// Verify MMR proof against given root hash for a batch of leaves. /// @@ -452,8 +466,8 @@ sp_api::decl_runtime_apis! { /// proof is verified against given MMR root hash. /// /// Note, the leaves should be sorted such that corresponding leaves and leaf indices have the - /// same position in both the `leaves` vector and the `leaf_indices` vector contained in the [Proof] - fn verify_proof_stateless(root: Hash, leaves: Vec, proof: Proof) + /// same position in both the `leaves` vector and the `leaf_indices` vector contained in the [LeafProof] + fn verify_proof_stateless(root: Hash, leaves: Vec, proof: LeafProof) -> Result<(), Error>; } } @@ -472,12 +486,12 @@ mod tests { type Test = DataOrHash; type TestCompact = Compact; - type TestProof = Proof<::Output>; + type TestProof = LeafProof<::Output>; #[test] fn should_encode_decode_proof() { // given - let proof: TestProof = Proof { + let proof: TestProof = LeafProof { leaf_indices: vec![5], leaf_count: 10, items: vec![ diff --git a/substrate/primitives/metadata-ir/Cargo.toml b/substrate/primitives/metadata-ir/Cargo.toml index ca8408d0ad97c0c5b880b8b60b59d693e7652b2f..90ecd1dfb13df810abbfd0ff460fa798a58e0033 100644 --- a/substrate/primitives/metadata-ir/Cargo.toml +++ b/substrate/primitives/metadata-ir/Cargo.toml @@ -16,7 +16,7 @@ workspace = true targets = ["x86_64-unknown-linux-gnu"] [dependencies] -codec = { package = "parity-scale-codec", version = "3.6.1", default-features = false } +codec = { package = "parity-scale-codec", version = "3.6.12", default-features = false } frame-metadata = { version = "16.0.0", default-features = false, features = ["current"] } scale-info = { version = "2.11.1", default-features = false, features = ["derive"] } diff --git a/substrate/primitives/mixnet/Cargo.toml b/substrate/primitives/mixnet/Cargo.toml index 07840ca63cb2b8eeaa1773146cf34a74d889b4c8..ef32503000d95b2c3c2026c2bb8aeb1eedc573cc 100644 --- a/substrate/primitives/mixnet/Cargo.toml +++ b/substrate/primitives/mixnet/Cargo.toml @@ -4,7 +4,7 @@ name = "sp-mixnet" version = "0.4.0" license = "Apache-2.0" authors = ["Parity Technologies "] -edition = "2021" +edition.workspace = true homepage = "https://substrate.io" repository = "https://github.com/paritytech/substrate/" readme = "README.md" @@ -16,7 +16,7 @@ workspace = true targets = ["x86_64-unknown-linux-gnu"] [dependencies] -codec = { package = "parity-scale-codec", version = "3.6.1", default-features = false, features = ["derive"] } +codec = { package = "parity-scale-codec", version = "3.6.12", default-features = false, features = ["derive"] } scale-info = { version = "2.11.1", default-features = false, features = ["derive"] } sp-api = { default-features = false, path = "../api" } sp-application-crypto = { default-features = false, path = "../application-crypto" } diff --git a/substrate/primitives/npos-elections/Cargo.toml b/substrate/primitives/npos-elections/Cargo.toml index afa59af64d6d8599a9835f448f9a2031831dc694..2da74429a4813e8fd3d3834682a49acce5f950f3 100644 --- a/substrate/primitives/npos-elections/Cargo.toml +++ b/substrate/primitives/npos-elections/Cargo.toml @@ -16,7 +16,7 @@ workspace = true targets = ["x86_64-unknown-linux-gnu"] [dependencies] -codec = { package = "parity-scale-codec", version = "3.6.1", default-features = false, features = ["derive"] } +codec = { package = "parity-scale-codec", version = "3.6.12", default-features = false, features = ["derive"] } scale-info = { version = "2.11.1", default-features = false, features = ["derive"] } serde = { features = ["alloc", "derive"], optional = true, workspace = true } sp-arithmetic = { path = "../arithmetic", default-features = false } diff --git a/substrate/primitives/runtime-interface/Cargo.toml b/substrate/primitives/runtime-interface/Cargo.toml index b4fab17eeb7c1872404cbc9d03bc775be6736fe9..f853a532515bb2d2406fe00e82e5803d4e7a056e 100644 --- a/substrate/primitives/runtime-interface/Cargo.toml +++ b/substrate/primitives/runtime-interface/Cargo.toml @@ -23,7 +23,7 @@ sp-std = { path = "../std", default-features = false } sp-tracing = { path = "../tracing", default-features = false } sp-runtime-interface-proc-macro = { path = "proc-macro" } sp-externalities = { path = "../externalities", default-features = false } -codec = { package = "parity-scale-codec", version = "3.6.1", default-features = false, features = ["bytes"] } +codec = { package = "parity-scale-codec", version = "3.6.12", default-features = false, features = ["bytes"] } static_assertions = "1.0.0" primitive-types = { version = "0.12.0", default-features = false } sp-storage = { path = "../storage", default-features = false } diff --git a/substrate/primitives/runtime/Cargo.toml b/substrate/primitives/runtime/Cargo.toml index fb5fd60fbbfd90260127fc8ec9d3750badc4b5ba..4d298b7ce5e3df4169945092d6ca53e8b616a11a 100644 --- a/substrate/primitives/runtime/Cargo.toml +++ b/substrate/primitives/runtime/Cargo.toml @@ -17,11 +17,12 @@ workspace = true targets = ["x86_64-unknown-linux-gnu"] [dependencies] -codec = { package = "parity-scale-codec", version = "3.6.1", default-features = false, features = ["derive", "max-encoded-len"] } +codec = { package = "parity-scale-codec", version = "3.6.12", 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 = { workspace = true } +num-traits = { version = "0.2.17", default-features = false } paste = "1.0" rand = { version = "0.8.5", optional = true } scale-info = { version = "2.11.1", default-features = false, features = ["derive"] } @@ -54,6 +55,7 @@ std = [ "either/use_std", "hash256-std-hasher/std", "log/std", + "num-traits/std", "rand", "scale-info/std", "serde/std", diff --git a/substrate/primitives/runtime/src/lib.rs b/substrate/primitives/runtime/src/lib.rs index 44bf3c969e5441245d1547e779195cdb68a83599..e4e6b98ff77cf786ce9fb37958bdaeff9a36c76c 100644 --- a/substrate/primitives/runtime/src/lib.rs +++ b/substrate/primitives/runtime/src/lib.rs @@ -91,6 +91,7 @@ mod runtime_string; pub mod testing; pub mod traits; pub mod transaction_validity; +pub mod type_with_default; pub use crate::runtime_string::*; diff --git a/substrate/primitives/runtime/src/type_with_default.rs b/substrate/primitives/runtime/src/type_with_default.rs new file mode 100644 index 0000000000000000000000000000000000000000..1465393640dc103347f8687d3272402570a1903d --- /dev/null +++ b/substrate/primitives/runtime/src/type_with_default.rs @@ -0,0 +1,506 @@ +// 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. + +//! Provides a type that wraps another type and provides a default value. + +use crate::traits::{Bounded, One, Zero}; +use codec::{Compact, CompactAs, Decode, Encode, HasCompact, MaxEncodedLen}; +use core::{ + fmt::Display, + marker::PhantomData, + ops::{ + Add, AddAssign, BitAnd, BitOr, BitXor, Deref, Div, DivAssign, Mul, MulAssign, Not, Rem, + RemAssign, Shl, Shr, Sub, SubAssign, + }, +}; +use num_traits::{ + CheckedAdd, CheckedDiv, CheckedMul, CheckedNeg, CheckedRem, CheckedShl, CheckedShr, CheckedSub, + Num, NumCast, PrimInt, Saturating, ToPrimitive, +}; +use scale_info::TypeInfo; +use sp_core::Get; + +#[cfg(feature = "serde")] +use serde::{Deserialize, Serialize}; + +/// A type that wraps another type and provides a default value. +/// +/// Passes through arithmetical and many other operations to the inner value. +#[derive(Encode, Decode, TypeInfo, Debug, MaxEncodedLen)] +#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] +pub struct TypeWithDefault>(T, PhantomData); + +impl> TypeWithDefault { + fn new(value: T) -> Self { + Self(value, PhantomData) + } +} + +impl> Clone for TypeWithDefault { + fn clone(&self) -> Self { + Self(self.0.clone(), PhantomData) + } +} + +impl> Copy for TypeWithDefault {} + +impl> PartialEq for TypeWithDefault { + fn eq(&self, other: &Self) -> bool { + self.0 == other.0 + } +} + +impl> Eq for TypeWithDefault {} + +impl> PartialOrd for TypeWithDefault { + fn partial_cmp(&self, other: &Self) -> Option { + self.0.partial_cmp(&other.0) + } +} + +impl> Ord for TypeWithDefault { + fn cmp(&self, other: &Self) -> core::cmp::Ordering { + self.0.cmp(&other.0) + } +} + +impl> Deref for TypeWithDefault { + type Target = T; + fn deref(&self) -> &Self::Target { + &self.0 + } +} + +impl> Default for TypeWithDefault { + fn default() -> Self { + Self::new(D::get()) + } +} + +impl, D: Get> From for TypeWithDefault { + fn from(value: u16) -> Self { + Self::new(value.into()) + } +} + +impl, D: Get> From for TypeWithDefault { + fn from(value: u32) -> Self { + Self::new(value.into()) + } +} + +impl, D: Get> From for TypeWithDefault { + fn from(value: u64) -> Self { + Self::new(value.into()) + } +} + +impl> CheckedNeg for TypeWithDefault { + fn checked_neg(&self) -> Option { + self.0.checked_neg().map(Self::new) + } +} + +impl> CheckedRem for TypeWithDefault { + fn checked_rem(&self, rhs: &Self) -> Option { + self.0.checked_rem(&rhs.0).map(Self::new) + } +} + +impl> CheckedShr for TypeWithDefault { + fn checked_shr(&self, n: u32) -> Option { + self.0.checked_shr(n).map(Self::new) + } +} + +impl> CheckedShl for TypeWithDefault { + fn checked_shl(&self, n: u32) -> Option { + self.0.checked_shl(n).map(Self::new) + } +} + +impl, D: Get> Rem for TypeWithDefault { + type Output = Self; + fn rem(self, rhs: Self) -> Self { + Self::new(self.0 % rhs.0) + } +} + +impl, D: Get> Rem for TypeWithDefault { + type Output = Self; + fn rem(self, rhs: u32) -> Self { + Self::new(self.0 % (rhs.into())) + } +} + +impl, D: Get> Shr for TypeWithDefault { + type Output = Self; + fn shr(self, rhs: u32) -> Self { + Self::new(self.0 >> rhs) + } +} + +impl, D: Get> Shr for TypeWithDefault { + type Output = Self; + fn shr(self, rhs: usize) -> Self { + Self::new(self.0 >> rhs) + } +} + +impl, D: Get> Shl for TypeWithDefault { + type Output = Self; + fn shl(self, rhs: u32) -> Self { + Self::new(self.0 << rhs) + } +} + +impl, D: Get> Shl for TypeWithDefault { + type Output = Self; + fn shl(self, rhs: usize) -> Self { + Self::new(self.0 << rhs) + } +} + +impl> RemAssign for TypeWithDefault { + fn rem_assign(&mut self, rhs: Self) { + self.0 %= rhs.0 + } +} + +impl> DivAssign for TypeWithDefault { + fn div_assign(&mut self, rhs: Self) { + self.0 /= rhs.0 + } +} + +impl> MulAssign for TypeWithDefault { + fn mul_assign(&mut self, rhs: Self) { + self.0 *= rhs.0 + } +} + +impl> SubAssign for TypeWithDefault { + fn sub_assign(&mut self, rhs: Self) { + self.0 -= rhs.0 + } +} + +impl> AddAssign for TypeWithDefault { + fn add_assign(&mut self, rhs: Self) { + self.0 += rhs.0 + } +} + +impl, D: Get> From for TypeWithDefault { + fn from(value: u8) -> Self { + Self::new(value.into()) + } +} + +impl> Display for TypeWithDefault { + fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result { + write!(f, "{}", self.0) + } +} + +impl, D: Get> TryFrom for TypeWithDefault { + type Error = >::Error; + fn try_from(n: u128) -> Result, Self::Error> { + T::try_from(n).map(Self::new) + } +} + +impl, D: Get> TryFrom for TypeWithDefault { + type Error = >::Error; + fn try_from(n: usize) -> Result, Self::Error> { + T::try_from(n).map(Self::new) + } +} + +impl, D: Get> TryFrom> for u8 { + type Error = >::Error; + fn try_from(value: TypeWithDefault) -> Result { + value.0.try_into() + } +} + +impl, D: Get> TryFrom> for u16 { + type Error = >::Error; + fn try_from(value: TypeWithDefault) -> Result { + value.0.try_into() + } +} + +impl, D: Get> TryFrom> for u32 { + type Error = >::Error; + fn try_from(value: TypeWithDefault) -> Result { + value.0.try_into() + } +} + +impl, D: Get> TryFrom> for u64 { + type Error = >::Error; + fn try_from(value: TypeWithDefault) -> Result { + value.0.try_into() + } +} + +impl, D: Get> TryFrom> for u128 { + type Error = >::Error; + fn try_from(value: TypeWithDefault) -> Result { + value.0.try_into() + } +} + +impl, D: Get> TryFrom> for usize { + type Error = >::Error; + fn try_from(value: TypeWithDefault) -> Result { + value.0.try_into() + } +} + +impl> Zero for TypeWithDefault { + fn zero() -> Self { + Self::new(T::zero()) + } + + fn is_zero(&self) -> bool { + self.0 == T::zero() + } +} + +impl> Bounded for TypeWithDefault { + fn min_value() -> Self { + Self::new(T::min_value()) + } + + fn max_value() -> Self { + Self::new(T::max_value()) + } +} + +impl> PrimInt for TypeWithDefault { + fn count_ones(self) -> u32 { + self.0.count_ones() + } + + fn leading_zeros(self) -> u32 { + self.0.leading_zeros() + } + + fn trailing_zeros(self) -> u32 { + self.0.trailing_zeros() + } + + fn rotate_left(self, n: u32) -> Self { + Self::new(self.0.rotate_left(n)) + } + + fn rotate_right(self, n: u32) -> Self { + Self::new(self.0.rotate_right(n)) + } + + fn swap_bytes(self) -> Self { + Self::new(self.0.swap_bytes()) + } + + fn from_be(x: Self) -> Self { + Self::new(T::from_be(x.0)) + } + + fn from_le(x: Self) -> Self { + Self::new(T::from_le(x.0)) + } + + fn to_be(self) -> Self { + Self::new(self.0.to_be()) + } + + fn to_le(self) -> Self { + Self::new(self.0.to_le()) + } + + fn count_zeros(self) -> u32 { + self.0.count_zeros() + } + + fn signed_shl(self, n: u32) -> Self { + Self::new(self.0.signed_shl(n)) + } + + fn signed_shr(self, n: u32) -> Self { + Self::new(self.0.signed_shr(n)) + } + + fn unsigned_shl(self, n: u32) -> Self { + Self::new(self.0.unsigned_shl(n)) + } + + fn unsigned_shr(self, n: u32) -> Self { + Self::new(self.0.unsigned_shr(n)) + } + + fn pow(self, exp: u32) -> Self { + Self::new(self.0.pow(exp)) + } +} + +impl> Saturating for TypeWithDefault { + fn saturating_add(self, rhs: Self) -> Self { + Self::new(self.0.saturating_add(rhs.0)) + } + + fn saturating_sub(self, rhs: Self) -> Self { + Self::new(self.0.saturating_sub(rhs.0)) + } +} + +impl, D: Get> Div for TypeWithDefault { + type Output = Self; + fn div(self, rhs: Self) -> Self { + Self::new(self.0 / rhs.0) + } +} + +impl, D: Get> Mul for TypeWithDefault { + type Output = Self; + fn mul(self, rhs: Self) -> Self { + Self::new(self.0 * rhs.0) + } +} + +impl> CheckedDiv for TypeWithDefault { + fn checked_div(&self, rhs: &Self) -> Option { + self.0.checked_div(&rhs.0).map(Self::new) + } +} + +impl> CheckedMul for TypeWithDefault { + fn checked_mul(&self, rhs: &Self) -> Option { + self.0.checked_mul(&rhs.0).map(Self::new) + } +} + +impl, D: Get> Sub for TypeWithDefault { + type Output = Self; + fn sub(self, rhs: Self) -> Self { + Self::new(self.0 - rhs.0) + } +} + +impl> CheckedSub for TypeWithDefault { + fn checked_sub(&self, rhs: &Self) -> Option { + self.0.checked_sub(&rhs.0).map(Self::new) + } +} + +impl, D: Get> Add for TypeWithDefault { + type Output = Self; + fn add(self, rhs: Self) -> Self { + Self::new(self.0 + rhs.0) + } +} + +impl> CheckedAdd for TypeWithDefault { + fn checked_add(&self, rhs: &Self) -> Option { + self.0.checked_add(&rhs.0).map(Self::new) + } +} + +impl, D: Get> BitAnd for TypeWithDefault { + type Output = Self; + fn bitand(self, rhs: Self) -> Self { + Self::new(self.0 & rhs.0) + } +} + +impl, D: Get> BitOr for TypeWithDefault { + type Output = Self; + fn bitor(self, rhs: Self) -> Self { + Self::new(self.0 | rhs.0) + } +} + +impl, D: Get> BitXor for TypeWithDefault { + type Output = Self; + fn bitxor(self, rhs: Self) -> Self { + Self::new(self.0 ^ rhs.0) + } +} + +impl> One for TypeWithDefault { + fn one() -> Self { + Self::new(T::one()) + } +} + +impl, D: Get> Not for TypeWithDefault { + type Output = Self; + fn not(self) -> Self { + Self::new(self.0.not()) + } +} + +impl> NumCast for TypeWithDefault { + fn from(n: P) -> Option { + ::from(n).map_or(None, |n| Some(Self::new(n))) + } +} + +impl> Num for TypeWithDefault { + type FromStrRadixErr = ::FromStrRadixErr; + + fn from_str_radix(s: &str, radix: u32) -> Result { + T::from_str_radix(s, radix).map(Self::new) + } +} + +impl> ToPrimitive for TypeWithDefault { + fn to_i64(&self) -> Option { + self.0.to_i64() + } + + fn to_u64(&self) -> Option { + self.0.to_u64() + } + + fn to_i128(&self) -> Option { + self.0.to_i128() + } + + fn to_u128(&self) -> Option { + self.0.to_u128() + } +} + +impl> From>> for TypeWithDefault { + fn from(c: Compact>) -> Self { + c.0 + } +} + +impl> CompactAs for TypeWithDefault { + type As = T; + + fn encode_as(&self) -> &Self::As { + &self.0 + } + + fn decode_from(val: Self::As) -> Result { + Ok(Self::new(val)) + } +} diff --git a/substrate/primitives/session/Cargo.toml b/substrate/primitives/session/Cargo.toml index cdee4fb03e1254e04e0a068908a380ed28350bee..9355ab420107147883b545467b31fcbf95be6191 100644 --- a/substrate/primitives/session/Cargo.toml +++ b/substrate/primitives/session/Cargo.toml @@ -16,13 +16,13 @@ workspace = true targets = ["x86_64-unknown-linux-gnu"] [dependencies] -codec = { package = "parity-scale-codec", version = "3.6.1", default-features = false, features = ["derive"] } +codec = { package = "parity-scale-codec", version = "3.6.12", default-features = false, features = ["derive"] } scale-info = { version = "2.11.1", default-features = false, features = ["derive"] } sp-api = { path = "../api", default-features = false } sp-core = { path = "../core", default-features = false } -sp-runtime = { path = "../runtime", optional = true } +sp-runtime = { path = "../runtime", optional = true, default-features = false } sp-staking = { path = "../staking", default-features = false } -sp-keystore = { path = "../keystore", optional = true } +sp-keystore = { path = "../keystore", optional = true, default-features = false } [features] default = ["std"] diff --git a/substrate/primitives/staking/Cargo.toml b/substrate/primitives/staking/Cargo.toml index e380abb6a8c070a861b8a84db473a66173aeaacd..6e3ce4bca106fab44516780921d4f15ed34854cb 100644 --- a/substrate/primitives/staking/Cargo.toml +++ b/substrate/primitives/staking/Cargo.toml @@ -17,7 +17,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] serde = { features = ["alloc", "derive"], optional = true, workspace = true } -codec = { package = "parity-scale-codec", version = "3.6.1", default-features = false, features = ["derive"] } +codec = { package = "parity-scale-codec", version = "3.6.12", default-features = false, features = ["derive"] } scale-info = { version = "2.11.1", 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 11b7ef41b9a7b06e1b67d43abb58e9aacc33d8ab..c7045508cea3ff789e8a8910170f97dcca82c6d0 100644 --- a/substrate/primitives/staking/src/lib.rs +++ b/substrate/primitives/staking/src/lib.rs @@ -29,7 +29,7 @@ use core::ops::Sub; use scale_info::TypeInfo; use sp_runtime::{ traits::{AtLeast32BitUnsigned, Zero}, - DispatchError, DispatchResult, RuntimeDebug, Saturating, + DispatchError, DispatchResult, Perbill, RuntimeDebug, Saturating, }; pub mod offence; @@ -254,6 +254,9 @@ pub trait StakingInterface { /// schedules have reached their unlocking era should allow more calls to this function. fn unbond(stash: &Self::AccountId, value: Self::Balance) -> DispatchResult; + /// Update the reward destination for the ledger associated with the stash. + fn update_payee(stash: &Self::AccountId, reward_acc: &Self::AccountId) -> DispatchResult; + /// Unlock any funds schedule to unlock before or at the current era. /// /// Returns whether the stash was killed because of this withdraw or not. @@ -274,7 +277,7 @@ pub trait StakingInterface { /// Checks whether an account `staker` has been exposed in an era. fn is_exposed_in_era(who: &Self::AccountId, era: &EraIndex) -> bool; - /// Return the status of the given staker, `None` if not staked at all. + /// Return the status of the given staker, `Err` if not staked at all. fn status(who: &Self::AccountId) -> Result, DispatchError>; /// Checks whether or not this is a validator account. @@ -290,6 +293,9 @@ pub trait StakingInterface { } } + /// Returns the fraction of the slash to be rewarded to reporter. + fn slash_reward_fraction() -> Perbill; + #[cfg(feature = "runtime-benchmarks")] fn max_exposure_page_size() -> Page; @@ -304,6 +310,34 @@ pub trait StakingInterface { fn set_current_era(era: EraIndex); } +/// Set of low level apis to manipulate staking ledger. +/// +/// These apis bypass some or all safety checks and should only be used if you know what you are +/// doing. +pub trait StakingUnchecked: StakingInterface { + /// Migrate an existing staker to a virtual staker. + /// + /// It would release all funds held by the implementation pallet. + fn migrate_to_virtual_staker(who: &Self::AccountId); + + /// Book-keep a new bond for `keyless_who` without applying any locks (hence virtual). + /// + /// It is important that `keyless_who` is a keyless account and therefore cannot interact with + /// staking pallet directly. Caller is responsible for ensuring the passed amount is locked and + /// valid. + fn virtual_bond( + keyless_who: &Self::AccountId, + value: Self::Balance, + payee: &Self::AccountId, + ) -> DispatchResult; + + /// Migrate a virtual staker to a direct staker. + /// + /// Only used for testing. + #[cfg(feature = "runtime-benchmarks")] + fn migrate_to_direct_staker(who: &Self::AccountId); +} + /// The amount of exposure for an era that an individual nominator has (susceptible to slashing). #[derive(PartialEq, Eq, PartialOrd, Ord, Clone, Encode, Decode, RuntimeDebug, TypeInfo)] pub struct IndividualExposure { @@ -422,4 +456,123 @@ pub struct PagedExposureMetadata { pub page_count: Page, } +/// Trait to provide delegation functionality for stakers. +/// +/// Introduces two new terms to the staking system: +/// - `Delegator`: An account that delegates funds to an `Agent`. +/// - `Agent`: An account that receives delegated funds from `Delegators`. It can then use these +/// funds to participate in the staking system. It can never use its own funds to stake. They +/// (virtually bond)[`StakingUnchecked::virtual_bond`] into the staking system and can also be +/// termed as `Virtual Nominators`. +/// +/// The `Agent` is responsible for managing rewards and slashing for all the `Delegators` that +/// have delegated funds to it. +pub trait DelegationInterface { + /// Balance type used by the staking system. + type Balance: Sub + + Ord + + PartialEq + + Default + + Copy + + MaxEncodedLen + + FullCodec + + TypeInfo + + Saturating; + + /// AccountId type used by the staking system. + type AccountId: Clone + core::fmt::Debug; + + /// Effective balance of the `Agent` account. + /// + /// This takes into account any pending slashes to `Agent`. + fn agent_balance(agent: &Self::AccountId) -> Self::Balance; + + /// Returns the total amount of funds delegated by a `delegator`. + fn delegator_balance(delegator: &Self::AccountId) -> Self::Balance; + + /// Delegate funds to `Agent`. + /// + /// Only used for the initial delegation. Use [`Self::delegate_extra`] to add more delegation. + fn delegate( + delegator: &Self::AccountId, + agent: &Self::AccountId, + reward_account: &Self::AccountId, + amount: Self::Balance, + ) -> DispatchResult; + + /// Add more delegation to the `Agent`. + /// + /// If this is the first delegation, use [`Self::delegate`] instead. + fn delegate_extra( + delegator: &Self::AccountId, + agent: &Self::AccountId, + amount: Self::Balance, + ) -> DispatchResult; + + /// Withdraw or revoke delegation to `Agent`. + /// + /// If there are `Agent` funds upto `amount` available to withdraw, then those funds would + /// be released to the `delegator` + fn withdraw_delegation( + delegator: &Self::AccountId, + agent: &Self::AccountId, + amount: Self::Balance, + num_slashing_spans: u32, + ) -> DispatchResult; + + /// Returns true if there are pending slashes posted to the `Agent` account. + /// + /// Slashes to `Agent` account are not immediate and are applied lazily. Since `Agent` + /// has an unbounded number of delegators, immediate slashing is not possible. + fn has_pending_slash(agent: &Self::AccountId) -> bool; + + /// Apply a pending slash to an `Agent` by slashing `value` from `delegator`. + /// + /// A reporter may be provided (if one exists) in order for the implementor to reward them, + /// if applicable. + fn delegator_slash( + agent: &Self::AccountId, + delegator: &Self::AccountId, + value: Self::Balance, + maybe_reporter: Option, + ) -> DispatchResult; +} + +/// Trait to provide functionality for direct stakers to migrate to delegation agents. +/// See [`DelegationInterface`] for more details on delegation. +pub trait DelegationMigrator { + /// Balance type used by the staking system. + type Balance: Sub + + Ord + + PartialEq + + Default + + Copy + + MaxEncodedLen + + FullCodec + + TypeInfo + + Saturating; + + /// AccountId type used by the staking system. + type AccountId: Clone + core::fmt::Debug; + + /// Migrate an existing `Nominator` to `Agent` account. + /// + /// The implementation should ensure the `Nominator` account funds are moved to an escrow + /// from which `Agents` can later release funds to its `Delegators`. + fn migrate_nominator_to_agent( + agent: &Self::AccountId, + reward_account: &Self::AccountId, + ) -> DispatchResult; + + /// Migrate `value` of delegation to `delegator` from a migrating agent. + /// + /// When a direct `Nominator` migrates to `Agent`, the funds are kept in escrow. This function + /// allows the `Agent` to release the funds to the `delegator`. + fn migrate_delegation( + agent: &Self::AccountId, + delegator: &Self::AccountId, + value: Self::Balance, + ) -> DispatchResult; +} + sp_core::generate_feature_enabled_macro!(runtime_benchmarks_enabled, feature = "runtime-benchmarks", $); diff --git a/substrate/primitives/staking/src/offence.rs b/substrate/primitives/staking/src/offence.rs index 30d96d0cbafce9f0540ffbb49cf15c7375ea405f..2c2ebc1fc971f25cff94b0cef4913eca19551e69 100644 --- a/substrate/primitives/staking/src/offence.rs +++ b/substrate/primitives/staking/src/offence.rs @@ -37,29 +37,6 @@ pub type Kind = [u8; 16]; /// so that we can slash it accordingly. pub type OffenceCount = u32; -/// In case of an offence, which conditions get an offending validator disabled. -#[derive( - Clone, - Copy, - PartialEq, - Eq, - Hash, - PartialOrd, - Ord, - Encode, - Decode, - sp_runtime::RuntimeDebug, - scale_info::TypeInfo, -)] -pub enum DisableStrategy { - /// Independently of slashing, this offence will not disable the offender. - Never, - /// Only disable the offender if it is also slashed. - WhenSlashed, - /// Independently of slashing, this offence will always disable the offender. - Always, -} - /// A trait implemented by an offence report. /// /// This trait assumes that the offence is legitimate and was validated already. @@ -102,11 +79,6 @@ pub trait Offence { /// number. Note that for GRANDPA the round number is reset each epoch. fn time_slot(&self) -> Self::TimeSlot; - /// In which cases this offence needs to disable offenders until the next era starts. - fn disable_strategy(&self) -> DisableStrategy { - DisableStrategy::WhenSlashed - } - /// A slash fraction of the total exposure that should be slashed for this /// particular offence for the `offenders_count` that happened at a singular `TimeSlot`. /// @@ -177,15 +149,12 @@ pub trait OnOffenceHandler { /// /// The `session` parameter is the session index of the offence. /// - /// The `disable_strategy` parameter decides if the offenders need to be disabled immediately. - /// /// The receiver might decide to not accept this offence. In this case, the call site is /// responsible for queuing the report and re-submitting again. fn on_offence( offenders: &[OffenceDetails], slash_fraction: &[Perbill], session: SessionIndex, - disable_strategy: DisableStrategy, ) -> Res; } @@ -194,7 +163,6 @@ impl OnOffenceHandler _offenders: &[OffenceDetails], _slash_fraction: &[Perbill], _session: SessionIndex, - _disable_strategy: DisableStrategy, ) -> Res { Default::default() } diff --git a/substrate/primitives/state-machine/Cargo.toml b/substrate/primitives/state-machine/Cargo.toml index 63251bbd181d4b6ef63661e1b568d1929d619a3c..c383a17cb006e3c4433172aedde957465fbb569f 100644 --- a/substrate/primitives/state-machine/Cargo.toml +++ b/substrate/primitives/state-machine/Cargo.toml @@ -17,7 +17,7 @@ workspace = true targets = ["x86_64-unknown-linux-gnu"] [dependencies] -codec = { package = "parity-scale-codec", version = "3.6.1", default-features = false } +codec = { package = "parity-scale-codec", version = "3.6.12", default-features = false } hash-db = { version = "0.16.0", default-features = false } log = { workspace = true } parking_lot = { version = "0.12.1", optional = true } @@ -32,7 +32,7 @@ sp-trie = { path = "../trie", default-features = false } trie-db = { version = "0.29.0", default-features = false } [dev-dependencies] -array-bytes = "6.1" +array-bytes = "6.2.2" pretty_assertions = "1.2.1" rand = "0.8.5" sp-runtime = { path = "../runtime" } diff --git a/substrate/primitives/state-machine/src/basic.rs b/substrate/primitives/state-machine/src/basic.rs index ace88aee2628f556ebafffa56543a7400c9428aa..8b6f746eaba0af9438557dc7dbe118bfbc4cdf34 100644 --- a/substrate/primitives/state-machine/src/basic.rs +++ b/substrate/primitives/state-machine/src/basic.rs @@ -33,7 +33,6 @@ use sp_trie::{empty_child_trie_root, LayoutV0, LayoutV1, TrieConfiguration}; use std::{ any::{Any, TypeId}, collections::BTreeMap, - iter::FromIterator, }; /// Simple Map-based Externalities impl. diff --git a/substrate/primitives/statement-store/Cargo.toml b/substrate/primitives/statement-store/Cargo.toml index b36bff69a007c669724950ca94f2cebc859890ed..bb893b25dc443f617ab5c0dd3d0d22c94646b689 100644 --- a/substrate/primitives/statement-store/Cargo.toml +++ b/substrate/primitives/statement-store/Cargo.toml @@ -16,7 +16,7 @@ workspace = true targets = ["x86_64-unknown-linux-gnu"] [dependencies] -codec = { package = "parity-scale-codec", version = "3.6.1", default-features = false, features = ["derive"] } +codec = { package = "parity-scale-codec", version = "3.6.12", default-features = false, features = ["derive"] } scale-info = { version = "2.11.1", default-features = false, features = ["derive"] } sp-core = { path = "../core", default-features = false } sp-crypto-hashing = { path = "../crypto/hashing", default-features = false } diff --git a/substrate/primitives/storage/Cargo.toml b/substrate/primitives/storage/Cargo.toml index acedc8d0004970fc10f5771ba4b4e2cb87a55198..c3318943d0d481a430da46502cdcb3a3c8aa22a7 100644 --- a/substrate/primitives/storage/Cargo.toml +++ b/substrate/primitives/storage/Cargo.toml @@ -17,7 +17,7 @@ workspace = true targets = ["x86_64-unknown-linux-gnu"] [dependencies] -codec = { package = "parity-scale-codec", version = "3.6.1", default-features = false, features = ["derive"] } +codec = { package = "parity-scale-codec", version = "3.6.12", default-features = false, features = ["derive"] } impl-serde = { version = "0.4.0", optional = true, default-features = false } ref-cast = "1.0.0" serde = { features = ["alloc", "derive"], optional = true, workspace = true } diff --git a/substrate/primitives/test-primitives/Cargo.toml b/substrate/primitives/test-primitives/Cargo.toml index 0513555431561a4adb12f5e2b373859df1272af2..b7be614860910eb63f12eadaa3676f69b0e65ada 100644 --- a/substrate/primitives/test-primitives/Cargo.toml +++ b/substrate/primitives/test-primitives/Cargo.toml @@ -15,7 +15,7 @@ workspace = true targets = ["x86_64-unknown-linux-gnu"] [dependencies] -codec = { package = "parity-scale-codec", version = "3.6.1", default-features = false, features = ["derive"] } +codec = { package = "parity-scale-codec", version = "3.6.12", default-features = false, features = ["derive"] } scale-info = { version = "2.11.1", default-features = false, features = ["derive"] } serde = { features = ["derive"], optional = true, workspace = true } sp-application-crypto = { path = "../application-crypto", default-features = false } diff --git a/substrate/primitives/timestamp/Cargo.toml b/substrate/primitives/timestamp/Cargo.toml index 5a1d4fcc985c520eede135b59d8fe5311fd8feac..c1bf9b3255eab83dea9eb9f80b93aa5440e816e1 100644 --- a/substrate/primitives/timestamp/Cargo.toml +++ b/substrate/primitives/timestamp/Cargo.toml @@ -17,7 +17,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] async-trait = { version = "0.1.79", optional = true } -codec = { package = "parity-scale-codec", version = "3.6.1", default-features = false, features = ["derive"] } +codec = { package = "parity-scale-codec", version = "3.6.12", default-features = false, features = ["derive"] } thiserror = { optional = true, workspace = true } sp-inherents = { path = "../inherents", default-features = false } sp-runtime = { path = "../runtime", default-features = false } diff --git a/substrate/primitives/tracing/Cargo.toml b/substrate/primitives/tracing/Cargo.toml index ce30302d4bb0a7166ceb820e72bdc1de0b31cbc3..8adec1670dc2da99c315f58dbc37a92a3cf947f5 100644 --- a/substrate/primitives/tracing/Cargo.toml +++ b/substrate/primitives/tracing/Cargo.toml @@ -21,7 +21,7 @@ features = ["with-tracing"] targets = ["wasm32-unknown-unknown", "x86_64-unknown-linux-gnu"] [dependencies] -codec = { version = "3.6.1", package = "parity-scale-codec", default-features = false, features = [ +codec = { version = "3.6.12", package = "parity-scale-codec", default-features = false, features = [ "derive", ] } tracing = { version = "0.1.29", default-features = false } diff --git a/substrate/primitives/transaction-storage-proof/Cargo.toml b/substrate/primitives/transaction-storage-proof/Cargo.toml index 137a232fce73b9937158afba0059b05aefea10bc..1e874c3595acd4723e34c0cb8568256ae2444317 100644 --- a/substrate/primitives/transaction-storage-proof/Cargo.toml +++ b/substrate/primitives/transaction-storage-proof/Cargo.toml @@ -17,12 +17,12 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] async-trait = { version = "0.1.79", optional = true } -codec = { package = "parity-scale-codec", version = "3.6.1", default-features = false, features = ["derive"] } +codec = { package = "parity-scale-codec", version = "3.6.12", default-features = false, features = ["derive"] } scale-info = { version = "2.11.1", default-features = false, features = ["derive"] } -sp-core = { path = "../core", optional = true } +sp-core = { path = "../core", optional = true, default-features = false } sp-inherents = { path = "../inherents", default-features = false } sp-runtime = { path = "../runtime", default-features = false } -sp-trie = { path = "../trie", optional = true } +sp-trie = { path = "../trie", optional = true, default-features = false } [features] default = ["std"] diff --git a/substrate/primitives/trie/Cargo.toml b/substrate/primitives/trie/Cargo.toml index 6469a59e0d10b2f598dd423976136481688bea7d..45459c180d40d076b0d7b59232e9dc76cd0b2d27 100644 --- a/substrate/primitives/trie/Cargo.toml +++ b/substrate/primitives/trie/Cargo.toml @@ -22,7 +22,7 @@ harness = false [dependencies] ahash = { version = "0.8.2", optional = true } -codec = { package = "parity-scale-codec", version = "3.6.1", default-features = false } +codec = { package = "parity-scale-codec", version = "3.6.12", default-features = false } hash-db = { version = "0.16.0", default-features = false } lazy_static = { version = "1.4.0", optional = true } memory-db = { version = "0.32.0", default-features = false } @@ -39,7 +39,7 @@ sp-externalities = { path = "../externalities", default-features = false } schnellru = { version = "0.2.1", optional = true } [dev-dependencies] -array-bytes = "6.1" +array-bytes = "6.2.2" criterion = "0.5.1" trie-bench = "0.39.0" trie-standardmap = "0.16.0" diff --git a/substrate/primitives/version/Cargo.toml b/substrate/primitives/version/Cargo.toml index d686b0c75512dac9931c46ffb41c4e4a11522718..f8ef8f66c5355634dbb4a7e1f08adbdb2f035766 100644 --- a/substrate/primitives/version/Cargo.toml +++ b/substrate/primitives/version/Cargo.toml @@ -17,7 +17,7 @@ workspace = true targets = ["x86_64-unknown-linux-gnu"] [dependencies] -codec = { package = "parity-scale-codec", version = "3.6.1", default-features = false, features = ["derive"] } +codec = { package = "parity-scale-codec", version = "3.6.12", default-features = false, features = ["derive"] } impl-serde = { version = "0.4.0", default-features = false, optional = true } parity-wasm = { version = "0.45", optional = true } scale-info = { version = "2.11.1", default-features = false, features = ["derive"] } diff --git a/substrate/primitives/version/proc-macro/Cargo.toml b/substrate/primitives/version/proc-macro/Cargo.toml index f7abf88c9a67b7e3102d44254b520a9bbeb7a8a8..3abd5c0910694cf14a8885ecebf4cc855e9e8266 100644 --- a/substrate/primitives/version/proc-macro/Cargo.toml +++ b/substrate/primitives/version/proc-macro/Cargo.toml @@ -19,7 +19,7 @@ targets = ["x86_64-unknown-linux-gnu"] proc-macro = true [dependencies] -codec = { package = "parity-scale-codec", version = "3.6.1", features = ["derive"] } +codec = { package = "parity-scale-codec", version = "3.6.12", features = ["derive"] } proc-macro2 = "1.0.56" quote = { workspace = true } syn = { features = ["extra-traits", "fold", "full", "visit"], workspace = true } diff --git a/substrate/primitives/wasm-interface/Cargo.toml b/substrate/primitives/wasm-interface/Cargo.toml index 15a20fab5e5d83aa4635a38c43738a3007847481..a0c8342d2d3c5014527487faf187fc48fd5344e1 100644 --- a/substrate/primitives/wasm-interface/Cargo.toml +++ b/substrate/primitives/wasm-interface/Cargo.toml @@ -17,7 +17,7 @@ workspace = true targets = ["x86_64-unknown-linux-gnu"] [dependencies] -codec = { package = "parity-scale-codec", version = "3.6.1", default-features = false, features = ["derive"] } +codec = { package = "parity-scale-codec", version = "3.6.12", default-features = false, features = ["derive"] } impl-trait-for-tuples = "0.2.2" log = { optional = true, workspace = true, default-features = true } wasmtime = { version = "8.0.1", default-features = false, optional = true } diff --git a/substrate/primitives/weights/Cargo.toml b/substrate/primitives/weights/Cargo.toml index e73d4a702b42e4ac5b0cd0a37f1c15eb70bec5e2..d2d72a7cb019fa5ad5c8fd66a32e953f9076068f 100644 --- a/substrate/primitives/weights/Cargo.toml +++ b/substrate/primitives/weights/Cargo.toml @@ -17,7 +17,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] bounded-collections = { version = "0.2.0", default-features = false } -codec = { package = "parity-scale-codec", version = "3.6.1", default-features = false, features = ["derive"] } +codec = { package = "parity-scale-codec", version = "3.6.12", default-features = false, features = ["derive"] } scale-info = { version = "2.11.1", default-features = false, features = ["derive"] } serde = { optional = true, features = ["alloc", "derive"], workspace = true } smallvec = "1.11.0" diff --git a/substrate/scripts/ci/node-template-release/Cargo.toml b/substrate/scripts/ci/node-template-release/Cargo.toml index 4327b6857433f40482b21a91e116479ba05da121..8e3e6138b9a8dabdbd67589049e5273305d29a0a 100644 --- a/substrate/scripts/ci/node-template-release/Cargo.toml +++ b/substrate/scripts/ci/node-template-release/Cargo.toml @@ -21,4 +21,4 @@ glob = "0.3" tar = "0.4" tempfile = "3" toml_edit = "0.19" -itertools = "0.10" +itertools = "0.11" diff --git a/substrate/test-utils/cli/Cargo.toml b/substrate/test-utils/cli/Cargo.toml index d654a3aaa7258668c066657b27e3eb97deec6b19..87c595c66f3484cbbaa8d8a6d83ea09453ee99b9 100644 --- a/substrate/test-utils/cli/Cargo.toml +++ b/substrate/test-utils/cli/Cargo.toml @@ -19,7 +19,7 @@ targets = ["x86_64-unknown-linux-gnu"] substrate-rpc-client = { path = "../../utils/frame/rpc/client" } sp-rpc = { path = "../../primitives/rpc" } assert_cmd = "2.0.10" -nix = "0.26.2" +nix = { version = "0.28.0", features = ["signal"] } regex = "1.7.3" tokio = { version = "1.22.0", features = ["full"] } node-primitives = { path = "../../bin/node/primitives" } diff --git a/substrate/test-utils/client/Cargo.toml b/substrate/test-utils/client/Cargo.toml index 4e4e65314fc3d0d1b6af4f0645c81e2a25835c68..5871f1bf5b4d05ad35f0998e7b4ab9fb3b953d58 100644 --- a/substrate/test-utils/client/Cargo.toml +++ b/substrate/test-utils/client/Cargo.toml @@ -16,9 +16,9 @@ workspace = true targets = ["x86_64-unknown-linux-gnu"] [dependencies] -array-bytes = "6.1" +array-bytes = "6.2.2" async-trait = "0.1.79" -codec = { package = "parity-scale-codec", version = "3.6.1" } +codec = { package = "parity-scale-codec", version = "3.6.12" } futures = "0.3.30" serde = { workspace = true, default-features = true } serde_json = { workspace = true, default-features = true } diff --git a/substrate/test-utils/client/src/lib.rs b/substrate/test-utils/client/src/lib.rs index d283b24f286aed743ba613f095f2cd319caba263..c07640653d560b54658ced8dc466398b6f291f77 100644 --- a/substrate/test-utils/client/src/lib.rs +++ b/substrate/test-utils/client/src/lib.rs @@ -24,7 +24,7 @@ pub mod client_ext; pub use self::client_ext::{BlockOrigin, ClientBlockImportExt, ClientExt}; pub use sc_client_api::{execution_extensions::ExecutionExtensions, BadBlocks, ForkBlocks}; pub use sc_client_db::{self, Backend, BlocksPruning}; -pub use sc_executor::{self, NativeElseWasmExecutor, WasmExecutionMethod, WasmExecutor}; +pub use sc_executor::{self, WasmExecutionMethod, WasmExecutor}; pub use sc_service::{client, RpcHandlers}; pub use sp_consensus; pub use sp_keyring::{ @@ -245,14 +245,8 @@ impl } } -impl - TestClientBuilder< - Block, - client::LocalCallExecutor>, - Backend, - G, - > where - D: sc_executor::NativeExecutionDispatch, +impl + TestClientBuilder>, Backend, G> { /// Build the test client with the given native executor. pub fn build_with_native_executor( @@ -261,21 +255,18 @@ impl ) -> ( client::Client< Backend, - client::LocalCallExecutor>, + client::LocalCallExecutor>, Block, RuntimeApi, >, sc_consensus::LongestChain, ) where - I: Into>>, - D: sc_executor::NativeExecutionDispatch + 'static, + I: Into>>, Backend: sc_client_api::backend::Backend + 'static, + H: sc_executor::HostFunctions, { - let mut executor = executor.into().unwrap_or_else(|| { - NativeElseWasmExecutor::new_with_wasm_executor(WasmExecutor::builder().build()) - }); - executor.disable_use_native(); + let executor = executor.into().unwrap_or_else(|| WasmExecutor::::builder().build()); let executor = LocalCallExecutor::new( self.backend.clone(), executor.clone(), diff --git a/substrate/test-utils/runtime/Cargo.toml b/substrate/test-utils/runtime/Cargo.toml index 28c1b22f976b61e1ab287be5a2700a71be1de0f9..038076e10c5acbdaa49330c534a26ddb511ce307 100644 --- a/substrate/test-utils/runtime/Cargo.toml +++ b/substrate/test-utils/runtime/Cargo.toml @@ -21,7 +21,7 @@ sp-consensus-aura = { path = "../../primitives/consensus/aura", default-features sp-consensus-babe = { path = "../../primitives/consensus/babe", default-features = false, features = ["serde"] } sp-genesis-builder = { path = "../../primitives/genesis-builder", default-features = false } sp-block-builder = { path = "../../primitives/block-builder", default-features = false } -codec = { package = "parity-scale-codec", version = "3.6.1", default-features = false, features = ["derive"] } +codec = { package = "parity-scale-codec", version = "3.6.12", default-features = false, features = ["derive"] } scale-info = { version = "2.11.1", default-features = false, features = ["derive"] } sp-inherents = { path = "../../primitives/inherents", default-features = false } sp-keyring = { path = "../../primitives/keyring", default-features = false } @@ -49,7 +49,7 @@ sp-state-machine = { path = "../../primitives/state-machine", default-features = sp-externalities = { path = "../../primitives/externalities", default-features = false } # 3rd party -array-bytes = { version = "6.1", optional = true } +array-bytes = { version = "6.2.2", optional = true } serde_json = { workspace = true, features = ["alloc"] } log = { workspace = true } hex-literal = { version = "0.4.1" } diff --git a/substrate/test-utils/runtime/client/src/lib.rs b/substrate/test-utils/runtime/client/src/lib.rs index 7428a7de3a096f343d28b39b618f353578649c74..435f3f5ebacb245ded18b6c258220744619e6d94 100644 --- a/substrate/test-utils/runtime/client/src/lib.rs +++ b/substrate/test-utils/runtime/client/src/lib.rs @@ -42,38 +42,18 @@ pub mod prelude { }; // Client structs pub use super::{ - Backend, ExecutorDispatch, LocalExecutorDispatch, NativeElseWasmExecutor, TestClient, - TestClientBuilder, WasmExecutionMethod, + Backend, ExecutorDispatch, TestClient, TestClientBuilder, WasmExecutionMethod, }; // Keyring pub use super::{AccountKeyring, Sr25519Keyring}; } -/// A unit struct which implements `NativeExecutionDispatch` feeding in the -/// hard-coded runtime. -pub struct LocalExecutorDispatch; - -impl sc_executor::NativeExecutionDispatch for LocalExecutorDispatch { - type ExtendHostFunctions = (); - - fn dispatch(method: &str, data: &[u8]) -> Option> { - substrate_test_runtime::api::dispatch(method, data) - } - - fn native_version() -> sc_executor::NativeVersion { - substrate_test_runtime::native_version() - } -} - /// Test client database backend. pub type Backend = substrate_test_client::Backend; /// Test client executor. -pub type ExecutorDispatch = client::LocalCallExecutor< - substrate_test_runtime::Block, - Backend, - NativeElseWasmExecutor, ->; +pub type ExecutorDispatch = + client::LocalCallExecutor; /// Parameters of test-client builder with test-runtime. #[derive(Default)] @@ -113,14 +93,10 @@ pub type TestClientBuilder = substrate_test_client::TestClientBuilder< GenesisParameters, >; -/// Test client type with `LocalExecutorDispatch` and generic Backend. +/// Test client type with `WasmExecutor` and generic Backend. pub type Client = client::Client< B, - client::LocalCallExecutor< - substrate_test_runtime::Block, - B, - NativeElseWasmExecutor, - >, + client::LocalCallExecutor, substrate_test_runtime::Block, substrate_test_runtime::RuntimeApi, >; @@ -206,14 +182,8 @@ pub trait TestClientBuilderExt: Sized { } impl TestClientBuilderExt - for TestClientBuilder< - client::LocalCallExecutor< - substrate_test_runtime::Block, - B, - NativeElseWasmExecutor, - >, - B, - > where + for TestClientBuilder, B> +where B: sc_client_api::backend::Backend + 'static, { fn genesis_init_mut(&mut self) -> &mut GenesisParameters { @@ -238,6 +208,7 @@ pub fn new() -> Client { } /// Create a new native executor. -pub fn new_native_or_wasm_executor() -> NativeElseWasmExecutor { - NativeElseWasmExecutor::new_with_wasm_executor(WasmExecutor::builder().build()) +#[deprecated(note = "Switch to `WasmExecutor:default()`.")] +pub fn new_native_or_wasm_executor() -> WasmExecutor { + WasmExecutor::default() } diff --git a/substrate/test-utils/runtime/transaction-pool/Cargo.toml b/substrate/test-utils/runtime/transaction-pool/Cargo.toml index 9b52706c739915690c7f734c399a3071b30a3630..360e2b7b810d1f40d4ac4884eedb60266e41cc5c 100644 --- a/substrate/test-utils/runtime/transaction-pool/Cargo.toml +++ b/substrate/test-utils/runtime/transaction-pool/Cargo.toml @@ -15,7 +15,7 @@ workspace = true targets = ["x86_64-unknown-linux-gnu"] [dependencies] -codec = { package = "parity-scale-codec", version = "3.6.1" } +codec = { package = "parity-scale-codec", version = "3.6.12" } futures = "0.3.30" parking_lot = "0.12.1" thiserror = { workspace = true } diff --git a/substrate/utils/binary-merkle-tree/Cargo.toml b/substrate/utils/binary-merkle-tree/Cargo.toml index a89006d94dc199951ffd5381ff7f51446a21acd6..fd35e6b1e1a25ada0e3cbd7012708a66b3f940f5 100644 --- a/substrate/utils/binary-merkle-tree/Cargo.toml +++ b/substrate/utils/binary-merkle-tree/Cargo.toml @@ -12,12 +12,12 @@ homepage = "https://substrate.io" workspace = true [dependencies] -array-bytes = { version = "6.1", optional = true } +array-bytes = { version = "6.2.2", optional = true } log = { optional = true, workspace = true } hash-db = { version = "0.16.0", default-features = false } [dev-dependencies] -array-bytes = "6.1" +array-bytes = "6.2.2" env_logger = "0.11" sp-core = { path = "../../primitives/core" } sp-runtime = { path = "../../primitives/runtime" } diff --git a/substrate/utils/fork-tree/Cargo.toml b/substrate/utils/fork-tree/Cargo.toml index 87135ef2afb884249fd4dfb2683e453c2328180d..275f44623bd1455cb34caa544fbfa4a6e140111b 100644 --- a/substrate/utils/fork-tree/Cargo.toml +++ b/substrate/utils/fork-tree/Cargo.toml @@ -17,4 +17,4 @@ workspace = true targets = ["x86_64-unknown-linux-gnu"] [dependencies] -codec = { package = "parity-scale-codec", version = "3.6.1", features = ["derive"] } +codec = { package = "parity-scale-codec", version = "3.6.12", features = ["derive"] } diff --git a/substrate/utils/frame/benchmarking-cli/Cargo.toml b/substrate/utils/frame/benchmarking-cli/Cargo.toml index 92169484c928d88d28bf3fe85c177ec477d6eaab..7cfacdc2e5edea443de8742fbe23cf9245872f08 100644 --- a/substrate/utils/frame/benchmarking-cli/Cargo.toml +++ b/substrate/utils/frame/benchmarking-cli/Cargo.toml @@ -16,14 +16,14 @@ workspace = true targets = ["x86_64-unknown-linux-gnu"] [dependencies] -array-bytes = "6.1" +array-bytes = "6.2.2" chrono = "0.4" clap = { version = "4.5.3", features = ["derive"] } -codec = { package = "parity-scale-codec", version = "3.6.1" } +codec = { package = "parity-scale-codec", version = "3.6.12" } comfy-table = { version = "7.1.0", default-features = false } handlebars = "5.1.0" Inflector = "0.11.4" -itertools = "0.10.3" +itertools = "0.11" lazy_static = "1.4.0" linked-hash-map = "0.5.4" log = { workspace = true, default-features = true } diff --git a/substrate/utils/frame/frame-utilities-cli/Cargo.toml b/substrate/utils/frame/frame-utilities-cli/Cargo.toml deleted file mode 100644 index 3952c9fd219f495270c811f0f849eb4178a96a92..0000000000000000000000000000000000000000 --- a/substrate/utils/frame/frame-utilities-cli/Cargo.toml +++ /dev/null @@ -1,25 +0,0 @@ -[package] -name = "substrate-frame-cli" -version = "32.0.0" -authors.workspace = true -edition.workspace = true -license = "Apache-2.0" -homepage = "https://substrate.io" -repository.workspace = true -description = "cli interface for FRAME" -documentation = "https://docs.rs/substrate-frame-cli" -readme = "README.md" - -[lints] -workspace = true - -[dependencies] -clap = { version = "4.5.3", features = ["derive"] } -frame-support = { path = "../../../frame/support" } -frame-system = { path = "../../../frame/system" } -sc-cli = { path = "../../../client/cli" } -sp-core = { path = "../../../primitives/core" } -sp-runtime = { path = "../../../primitives/runtime" } - -[features] -default = [] diff --git a/substrate/utils/frame/frame-utilities-cli/README.md b/substrate/utils/frame/frame-utilities-cli/README.md deleted file mode 100644 index 54467a3ad7704451f4064f8334ea374b8c7f6bca..0000000000000000000000000000000000000000 --- a/substrate/utils/frame/frame-utilities-cli/README.md +++ /dev/null @@ -1,3 +0,0 @@ -frame-system CLI utilities - -License: Apache-2.0 diff --git a/substrate/utils/frame/frame-utilities-cli/src/pallet_id.rs b/substrate/utils/frame/frame-utilities-cli/src/pallet_id.rs deleted file mode 100644 index abc0cdb3ff52b355596e4b1cd25c67ee0508d951..0000000000000000000000000000000000000000 --- a/substrate/utils/frame/frame-utilities-cli/src/pallet_id.rs +++ /dev/null @@ -1,88 +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. - -//! Implementation of the `palletid` subcommand - -use clap::Parser; -use frame_support::PalletId; -use sc_cli::{ - utils::print_from_uri, with_crypto_scheme, CryptoSchemeFlag, Error, KeystoreParams, - OutputTypeFlag, -}; -use sp_core::crypto::{unwrap_or_default_ss58_version, Ss58AddressFormat, Ss58Codec}; -use sp_runtime::traits::AccountIdConversion; - -/// The `palletid` command -#[derive(Debug, Parser)] -#[command(name = "palletid", about = "Inspect a module ID address")] -pub struct PalletIdCmd { - /// The module ID used to derive the account - id: String, - - /// network address format - #[arg( - long, - value_name = "NETWORK", - value_parser = sc_cli::parse_ss58_address_format, - ignore_case = true, - )] - pub network: Option, - - #[allow(missing_docs)] - #[command(flatten)] - pub output_scheme: OutputTypeFlag, - - #[allow(missing_docs)] - #[command(flatten)] - pub crypto_scheme: CryptoSchemeFlag, - - #[allow(missing_docs)] - #[command(flatten)] - pub keystore_params: KeystoreParams, -} - -impl PalletIdCmd { - /// runs the command - pub fn run(&self) -> Result<(), Error> - where - R: frame_system::Config, - R::AccountId: Ss58Codec, - { - if self.id.len() != 8 { - return Err("a module id must be a string of 8 characters".into()) - } - let password = self.keystore_params.read_password()?; - - let id_fixed_array: [u8; 8] = self.id.as_bytes().try_into().map_err(|_| { - "Cannot convert argument to palletid: argument should be 8-character string" - })?; - - let account_id: R::AccountId = PalletId(id_fixed_array).into_account_truncating(); - - with_crypto_scheme!( - self.crypto_scheme.scheme, - print_from_uri( - &account_id.to_ss58check_with_version(unwrap_or_default_ss58_version(self.network)), - password, - self.network, - self.output_scheme.output_type - ) - ); - - Ok(()) - } -} diff --git a/substrate/utils/frame/remote-externalities/Cargo.toml b/substrate/utils/frame/remote-externalities/Cargo.toml index 82b019154832aee4202d60d3a1a2b9015b7b774a..2911d5eef65902af9a0bec6a679a89db9eb6fb7a 100644 --- a/substrate/utils/frame/remote-externalities/Cargo.toml +++ b/substrate/utils/frame/remote-externalities/Cargo.toml @@ -16,7 +16,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] jsonrpsee = { version = "0.22", features = ["http-client"] } -codec = { package = "parity-scale-codec", version = "3.6.1" } +codec = { package = "parity-scale-codec", version = "3.6.12" } log = { workspace = true, default-features = true } serde = { workspace = true, default-features = true } sp-core = { path = "../../../primitives/core" } diff --git a/substrate/utils/frame/remote-externalities/src/lib.rs b/substrate/utils/frame/remote-externalities/src/lib.rs index e429d39669f1b35f73e114df31e997f96c19945c..201b5e176f34bec0ed66ed53427424e904d2621a 100644 --- a/substrate/utils/frame/remote-externalities/src/lib.rs +++ b/substrate/utils/frame/remote-externalities/src/lib.rs @@ -36,7 +36,7 @@ use sp_core::{ }, }; use sp_runtime::{ - traits::{Block as BlockT, Hash, HashingFor}, + traits::{Block as BlockT, HashingFor}, StateVersion, }; use sp_state_machine::TestExternalities; @@ -58,37 +58,39 @@ type ChildKeyValues = Vec<(ChildInfo, Vec)>; type SnapshotVersion = Compact; const LOG_TARGET: &str = "remote-ext"; -const DEFAULT_HTTP_ENDPOINT: &str = "https://rpc.polkadot.io:443"; -const SNAPSHOT_VERSION: SnapshotVersion = Compact(3); +const DEFAULT_HTTP_ENDPOINT: &str = "https://polkadot-try-runtime-node.parity-chains.parity.io:443"; +const SNAPSHOT_VERSION: SnapshotVersion = Compact(4); /// The snapshot that we store on disk. #[derive(Decode, Encode)] -struct Snapshot { +struct Snapshot { snapshot_version: SnapshotVersion, state_version: StateVersion, - block_hash: H, // > raw_storage: Vec<(Vec, (Vec, i32))>, - storage_root: H, + // The storage root of the state. This may vary from the storage root in the header, if not the + // entire state was fetched. + storage_root: B::Hash, + header: B::Header, } -impl Snapshot { +impl Snapshot { pub fn new( state_version: StateVersion, - block_hash: H, raw_storage: Vec<(Vec, (Vec, i32))>, - storage_root: H, + storage_root: B::Hash, + header: B::Header, ) -> Self { Self { snapshot_version: SNAPSHOT_VERSION, state_version, - block_hash, raw_storage, storage_root, + header, } } - fn load(path: &PathBuf) -> Result, &'static str> { + fn load(path: &PathBuf) -> Result, &'static str> { let bytes = fs::read(path).map_err(|_| "fs::read failed.")?; // The first item in the SCALE encoded struct bytes is the snapshot version. We decode and // check that first, before proceeding to decode the rest of the snapshot. @@ -105,21 +107,21 @@ impl Snapshot { /// An externalities that acts exactly the same as [`sp_io::TestExternalities`] but has a few extra /// bits and pieces to it, and can be loaded remotely. -pub struct RemoteExternalities { +pub struct RemoteExternalities { /// The inner externalities. - pub inner_ext: TestExternalities, - /// The block hash with which we created this externality env. - pub block_hash: H::Out, + pub inner_ext: TestExternalities>, + /// The block header which we created this externality env. + pub header: B::Header, } -impl Deref for RemoteExternalities { - type Target = TestExternalities; +impl Deref for RemoteExternalities { + type Target = TestExternalities>; fn deref(&self) -> &Self::Target { &self.inner_ext } } -impl DerefMut for RemoteExternalities { +impl DerefMut for RemoteExternalities { fn deref_mut(&mut self) -> &mut Self::Target { &mut self.inner_ext } @@ -830,19 +832,22 @@ where child_prefix: StorageKey, at: B::Hash, ) -> Result, &'static str> { - // This is deprecated and will generate a warning which causes the CI to fail. - #[allow(warnings)] - let child_keys = substrate_rpc_client::ChildStateApi::storage_keys( - client, - PrefixedStorageKey::new(prefixed_top_key.as_ref().to_vec()), - child_prefix, - Some(at), - ) - .await - .map_err(|e| { - error!(target: LOG_TARGET, "Error = {:?}", e); - "rpc child_get_keys failed." - })?; + let retry_strategy = + FixedInterval::new(Self::KEYS_PAGE_RETRY_INTERVAL).take(Self::MAX_RETRIES); + let get_child_keys_closure = || { + #[allow(deprecated)] + substrate_rpc_client::ChildStateApi::storage_keys( + client, + PrefixedStorageKey::new(prefixed_top_key.as_ref().to_vec()), + child_prefix.clone(), + Some(at), + ) + }; + let child_keys = + Retry::spawn(retry_strategy, get_child_keys_closure).await.map_err(|e| { + error!(target: LOG_TARGET, "Error = {:?}", e); + "rpc child_get_keys failed." + })?; debug!( target: LOG_TARGET, @@ -856,7 +861,7 @@ where } } -impl Builder +impl Builder where B::Hash: DeserializeOwned, B::Header: DeserializeOwned, @@ -1027,6 +1032,21 @@ where Ok(()) } + async fn load_header(&self) -> Result { + let retry_strategy = + FixedInterval::new(Self::KEYS_PAGE_RETRY_INTERVAL).take(Self::MAX_RETRIES); + let get_header_closure = || { + ChainApi::<(), _, B::Header, ()>::header( + self.as_online().rpc_client(), + Some(self.as_online().at_expected()), + ) + }; + Retry::spawn(retry_strategy, get_header_closure) + .await + .map_err(|_| "Failed to fetch header for block from network")? + .ok_or("Network returned None block header") + } + /// Load the data from a remote server. The main code path is calling into `load_top_remote` and /// `load_child_remote`. /// @@ -1055,13 +1075,11 @@ where // If we need to save a snapshot, save the raw storage and root hash to the snapshot. if let Some(path) = self.as_online().state_snapshot.clone().map(|c| c.path) { let (raw_storage, storage_root) = pending_ext.into_raw_snapshot(); - let snapshot = Snapshot::::new( + let snapshot = Snapshot::::new( state_version, - self.as_online() - .at - .expect("set to `Some` in `init_remote_client`; must be called before; qed"), raw_storage.clone(), storage_root, + self.load_header().await?, ); let encoded = snapshot.encode(); log::info!( @@ -1083,22 +1101,21 @@ where Ok(pending_ext) } - async fn do_load_remote(&mut self) -> Result>, &'static str> { + async fn do_load_remote(&mut self) -> Result, &'static str> { self.init_remote_client().await?; - let block_hash = self.as_online().at_expected(); let inner_ext = self.load_remote_and_maybe_save().await?; - Ok(RemoteExternalities { block_hash, inner_ext }) + Ok(RemoteExternalities { header: self.load_header().await?, inner_ext }) } fn do_load_offline( &mut self, config: OfflineConfig, - ) -> Result>, &'static str> { + ) -> Result, &'static str> { let mut sp = Spinner::with_timer(Spinners::Dots, "Loading snapshot...".into()); let start = Instant::now(); info!(target: LOG_TARGET, "Loading snapshot from {:?}", &config.state_snapshot.path); - let Snapshot { snapshot_version: _, block_hash, state_version, raw_storage, storage_root } = - Snapshot::::load(&config.state_snapshot.path)?; + let Snapshot { snapshot_version: _, header, state_version, raw_storage, storage_root } = + Snapshot::::load(&config.state_snapshot.path)?; let inner_ext = TestExternalities::from_raw_snapshot( raw_storage, @@ -1107,12 +1124,10 @@ where ); sp.stop_with_message(format!("✅ Loaded snapshot ({:.2}s)", start.elapsed().as_secs_f32())); - Ok(RemoteExternalities { inner_ext, block_hash }) + Ok(RemoteExternalities { inner_ext, header }) } - pub(crate) async fn pre_build( - mut self, - ) -> Result>, &'static str> { + pub(crate) async fn pre_build(mut self) -> Result, &'static str> { let mut ext = match self.mode.clone() { Mode::Offline(config) => self.do_load_offline(config)?, Mode::Online(_) => self.do_load_remote().await?, @@ -1151,7 +1166,7 @@ where } // Public methods -impl Builder +impl Builder where B::Hash: DeserializeOwned, B::Header: DeserializeOwned, @@ -1188,7 +1203,7 @@ where self } - pub async fn build(self) -> Result>, &'static str> { + pub async fn build(self) -> Result, &'static str> { let mut ext = self.pre_build().await?; ext.commit_all().unwrap(); @@ -1223,7 +1238,7 @@ mod tests { init_logger(); Builder::::new() .mode(Mode::Offline(OfflineConfig { - state_snapshot: SnapshotConfig::new("test_data/proxy_test"), + state_snapshot: SnapshotConfig::new("test_data/test.snap"), })) .build() .await @@ -1238,7 +1253,7 @@ mod tests { // get the first key from the snapshot file. let some_key = Builder::::new() .mode(Mode::Offline(OfflineConfig { - state_snapshot: SnapshotConfig::new("test_data/proxy_test"), + state_snapshot: SnapshotConfig::new("test_data/test.snap"), })) .build() .await @@ -1252,7 +1267,7 @@ mod tests { Builder::::new() .mode(Mode::Offline(OfflineConfig { - state_snapshot: SnapshotConfig::new("test_data/proxy_test"), + state_snapshot: SnapshotConfig::new("test_data/test.snap"), })) .blacklist_hashed_key(&some_key) .build() @@ -1338,7 +1353,7 @@ mod remote_tests { .await .unwrap(); - assert_eq!(ext.block_hash, cached_ext.block_hash); + assert_eq!(ext.header.hash(), cached_ext.header.hash()); } #[tokio::test] diff --git a/substrate/utils/frame/remote-externalities/test_data/proxy_test b/substrate/utils/frame/remote-externalities/test_data/proxy_test deleted file mode 100644 index f0b1b4f5af40bc8a159c9ee250bee7849cababae..0000000000000000000000000000000000000000 Binary files a/substrate/utils/frame/remote-externalities/test_data/proxy_test and /dev/null differ diff --git a/substrate/utils/frame/remote-externalities/test_data/test.snap b/substrate/utils/frame/remote-externalities/test_data/test.snap new file mode 100644 index 0000000000000000000000000000000000000000..28f2012d0f2a1b6a63ee8825deaf70257625279a Binary files /dev/null and b/substrate/utils/frame/remote-externalities/test_data/test.snap differ 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 98a87b7d5b200f632cf599dd7fa741f3a804dd0b..ee3bf5eb68d716548a4a738f80254cfe811c651f 100644 --- a/substrate/utils/frame/rpc/state-trie-migration-rpc/Cargo.toml +++ b/substrate/utils/frame/rpc/state-trie-migration-rpc/Cargo.toml @@ -16,7 +16,7 @@ workspace = true targets = ["x86_64-unknown-linux-gnu"] [dependencies] -codec = { package = "parity-scale-codec", version = "3.6.1", default-features = false } +codec = { package = "parity-scale-codec", version = "3.6.12", default-features = false } serde = { features = ["derive"], workspace = true, default-features = true } sp-core = { path = "../../../../primitives/core" } @@ -24,7 +24,7 @@ sp-state-machine = { path = "../../../../primitives/state-machine" } sp-trie = { path = "../../../../primitives/trie" } trie-db = "0.29.0" -jsonrpsee = { version = "0.22", features = ["client-core", "macros", "server"] } +jsonrpsee = { version = "0.22.5", features = ["client-core", "macros", "server-core"] } # Substrate Dependencies sc-client-api = { path = "../../../../client/api" } diff --git a/substrate/utils/frame/rpc/support/Cargo.toml b/substrate/utils/frame/rpc/support/Cargo.toml index 84db06da7b0d26fa52f066dc7ef9f6d879bcc34c..bf566f909ecb712d8b00a26717739243adb06129 100644 --- a/substrate/utils/frame/rpc/support/Cargo.toml +++ b/substrate/utils/frame/rpc/support/Cargo.toml @@ -15,7 +15,7 @@ workspace = true targets = ["x86_64-unknown-linux-gnu"] [dependencies] -codec = { package = "parity-scale-codec", version = "3.6.1" } +codec = { package = "parity-scale-codec", version = "3.6.12" } jsonrpsee = { version = "0.22", features = ["jsonrpsee-types"] } serde = { workspace = true, default-features = true } frame-support = { path = "../../../../frame/support" } diff --git a/substrate/utils/frame/rpc/system/Cargo.toml b/substrate/utils/frame/rpc/system/Cargo.toml index 9e571bef9d04fd6025990755a2ecae79e180f335..6829d753ed71327dea8ad4e65d91af67c14285f1 100644 --- a/substrate/utils/frame/rpc/system/Cargo.toml +++ b/substrate/utils/frame/rpc/system/Cargo.toml @@ -16,8 +16,8 @@ workspace = true targets = ["x86_64-unknown-linux-gnu"] [dependencies] -codec = { package = "parity-scale-codec", version = "3.6.1" } -jsonrpsee = { version = "0.22", features = ["client-core", "macros", "server"] } +codec = { package = "parity-scale-codec", version = "3.6.12" } +jsonrpsee = { version = "0.22.5", features = ["client-core", "macros", "server-core"] } futures = "0.3.30" log = { workspace = true, default-features = true } frame-system-rpc-runtime-api = { path = "../../../../frame/system/rpc/runtime-api" } diff --git a/substrate/utils/wasm-builder/src/builder.rs b/substrate/utils/wasm-builder/src/builder.rs index d2aaff448bc5fdc2f2c1cb73774e0d7603ae90db..163703fbec628327c0ba3dc0683972285af71e30 100644 --- a/substrate/utils/wasm-builder/src/builder.rs +++ b/substrate/utils/wasm-builder/src/builder.rs @@ -116,6 +116,39 @@ impl WasmBuilder { WasmBuilderSelectProject { _ignore: () } } + /// Build the WASM binary using the recommended default values. + /// + /// This is the same as calling: + /// ```no_run + /// substrate_wasm_builder::WasmBuilder::new() + /// .with_current_project() + /// .import_memory() + /// .export_heap_base() + /// .build(); + /// ``` + pub fn build_using_defaults() { + WasmBuilder::new() + .with_current_project() + .import_memory() + .export_heap_base() + .build(); + } + + /// Init the wasm builder with the recommended default values. + /// + /// In contrast to [`Self::build_using_defaults`] it does not build the WASM binary directly. + /// + /// This is the same as calling: + /// ```no_run + /// substrate_wasm_builder::WasmBuilder::new() + /// .with_current_project() + /// .import_memory() + /// .export_heap_base(); + /// ``` + pub fn init_with_defaults() -> Self { + WasmBuilder::new().with_current_project().import_memory().export_heap_base() + } + /// Enable exporting `__heap_base` as global variable in the WASM binary. /// /// This adds `-Clink-arg=--export=__heap_base` to `RUST_FLAGS`. diff --git a/substrate/utils/wasm-builder/src/lib.rs b/substrate/utils/wasm-builder/src/lib.rs index 178e499e8f5bb6d7531d73004e2f37e1e9b1d146..9ebab38b9cb2f727594e310f1e6d27c221f528dc 100644 --- a/substrate/utils/wasm-builder/src/lib.rs +++ b/substrate/utils/wasm-builder/src/lib.rs @@ -33,15 +33,9 @@ //! use substrate_wasm_builder::WasmBuilder; //! //! fn main() { -//! WasmBuilder::new() -//! // Tell the builder to build the project (crate) this `build.rs` is part of. -//! .with_current_project() -//! // Make sure to export the `heap_base` global, this is required by Substrate -//! .export_heap_base() -//! // Build the Wasm file so that it imports the memory (need to be provided by at instantiation) -//! .import_memory() -//! // Build it. -//! .build() +//! // Builds the WASM binary using the recommended defaults. +//! // If you need more control, you can call `new` or `init_with_defaults`. +//! WasmBuilder::build_using_defaults(); //! } //! ``` //! diff --git a/templates/minimal/Cargo.toml b/templates/minimal/Cargo.toml new file mode 100644 index 0000000000000000000000000000000000000000..6cd28c5a49364a911c9b93fa1269456cf07527d5 --- /dev/null +++ b/templates/minimal/Cargo.toml @@ -0,0 +1,25 @@ +[package] +name = "minimal-template" +description = "A minimal 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] +minimal-template-node = { path = "./node" } +minimal-template-runtime = { path = "./runtime" } +pallet-minimal-template = { path = "./pallets/template" } +polkadot-sdk-docs = { path = "../../docs/sdk" } + +frame = { package = "polkadot-sdk-frame", path = "../../substrate/frame" } + +# How we build docs in rust-docs +simple-mermaid = "0.1.1" +docify = "0.2.7" diff --git a/templates/minimal/README.md b/templates/minimal/README.md index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..0541e393db93bd9a67ddfaefe208c7ef22627f44 100644 --- a/templates/minimal/README.md +++ b/templates/minimal/README.md @@ -0,0 +1,13 @@ +# Minimal Template + +This is a minimal template for creating a blockchain using the Polkadot SDK. + +# Docs + +You can generate and view the [Rust +Docs](https://doc.rust-lang.org/cargo/commands/cargo-doc.html) for this template +with this command: + +```sh +cargo doc -p minimal-template --open +``` diff --git a/templates/minimal/pallets/template/Cargo.toml b/templates/minimal/pallets/template/Cargo.toml index 909ba03445483e53fe108a096256d0df5d1cdc40..e6fe43abc0909a257648051f67f6ab489fe047c4 100644 --- a/templates/minimal/pallets/template/Cargo.toml +++ b/templates/minimal/pallets/template/Cargo.toml @@ -16,7 +16,7 @@ workspace = true targets = ["x86_64-unknown-linux-gnu"] [dependencies] -codec = { package = "parity-scale-codec", version = "3.0.0", features = [ +codec = { package = "parity-scale-codec", version = "3.6.12", features = [ "derive", ], default-features = false } scale-info = { version = "2.11.1", default-features = false, features = [ diff --git a/templates/minimal/runtime/Cargo.toml b/templates/minimal/runtime/Cargo.toml index ceac8a49853369a6a882e32f13cc4728aa3c29ad..99559308e5b8f8f553a8a64ca4afabdcec6f39f9 100644 --- a/templates/minimal/runtime/Cargo.toml +++ b/templates/minimal/runtime/Cargo.toml @@ -13,7 +13,7 @@ publish = false workspace = true [dependencies] -parity-scale-codec = { version = "3.0.0", default-features = false } +parity-scale-codec = { version = "3.6.12", 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. diff --git a/templates/minimal/runtime/build.rs b/templates/minimal/runtime/build.rs index b7676a70dfe843e2cd47fc600ef599bbe7bff591..e6f92757e225475ff744a4a0cf931787463d1544 100644 --- a/templates/minimal/runtime/build.rs +++ b/templates/minimal/runtime/build.rs @@ -18,10 +18,6 @@ fn main() { #[cfg(feature = "std")] { - substrate_wasm_builder::WasmBuilder::new() - .with_current_project() - .export_heap_base() - .import_memory() - .build(); + substrate_wasm_builder::WasmBuilder::build_using_defaults(); } } diff --git a/templates/minimal/runtime/src/lib.rs b/templates/minimal/runtime/src/lib.rs index 794f30a054a8e3ef9b50bd3f29e83dc572f62005..d2debbf5689fdf41b8436fb33eac52db5f573a3e 100644 --- a/templates/minimal/runtime/src/lib.rs +++ b/templates/minimal/runtime/src/lib.rs @@ -15,6 +15,8 @@ // See the License for the specific language governing permissions and // limitations under the License. +//! A minimal runtime that includes the template [`pallet`](`pallet_minimal_template`). + #![cfg_attr(not(feature = "std"), no_std)] // Make the WASM binary available. @@ -24,6 +26,7 @@ include!(concat!(env!("OUT_DIR"), "/wasm_binary.rs")); use frame::{ deps::frame_support::{ genesis_builder_helper::{build_state, get_preset}, + runtime, weights::{FixedFee, NoFee}, }, prelude::*, @@ -36,6 +39,7 @@ use frame::{ }, }; +/// The runtime version. #[runtime_version] pub const VERSION: RuntimeVersion = RuntimeVersion { spec_name: create_runtime_str!("minimal-template-runtime"), @@ -54,61 +58,108 @@ pub fn native_version() -> NativeVersion { NativeVersion { runtime_version: VERSION, can_author_with: Default::default() } } +/// The signed extensions that are added to the runtime. type SignedExtra = ( + // Checks that the sender is not the zero address. frame_system::CheckNonZeroSender, + // Checks that the runtime version is correct. frame_system::CheckSpecVersion, + // Checks that the transaction version is correct. frame_system::CheckTxVersion, + // Checks that the genesis hash is correct. frame_system::CheckGenesis, + // Checks that the era is valid. frame_system::CheckEra, + // Checks that the nonce is valid. frame_system::CheckNonce, + // Checks that the weight is valid. frame_system::CheckWeight, + // Ensures that the sender has enough funds to pay for the transaction + // and deducts the fee from the sender's account. pallet_transaction_payment::ChargeTransactionPayment, ); -construct_runtime!( - pub enum Runtime { - System: frame_system, - Timestamp: pallet_timestamp, - - Balances: pallet_balances, - Sudo: pallet_sudo, - TransactionPayment: pallet_transaction_payment, - - // our local pallet - Template: pallet_minimal_template, - } -); +// Composes the runtime by adding all the used pallets and deriving necessary types. +#[runtime] +mod runtime { + /// The main runtime type. + #[runtime::runtime] + #[runtime::derive( + RuntimeCall, + RuntimeEvent, + RuntimeError, + RuntimeOrigin, + RuntimeFreezeReason, + RuntimeHoldReason, + RuntimeSlashReason, + RuntimeLockId, + RuntimeTask + )] + pub struct Runtime; + + /// Mandatory system pallet that should always be included in a FRAME runtime. + #[runtime::pallet_index(0)] + pub type System = frame_system; + + /// Provides a way for consensus systems to set and check the onchain time. + #[runtime::pallet_index(1)] + pub type Timestamp = pallet_timestamp; + + /// Provides the ability to keep track of balances. + #[runtime::pallet_index(2)] + pub type Balances = pallet_balances; + + /// Provides a way to execute privileged functions. + #[runtime::pallet_index(3)] + pub type Sudo = pallet_sudo; + + /// Provides the ability to charge for extrinsic execution. + #[runtime::pallet_index(4)] + pub type TransactionPayment = pallet_transaction_payment; + + /// A minimal pallet template. + #[runtime::pallet_index(5)] + pub type Template = pallet_minimal_template; +} parameter_types! { pub const Version: RuntimeVersion = VERSION; } +/// Implements the types required for the system pallet. #[derive_impl(frame_system::config_preludes::SolochainDefaultConfig)] impl frame_system::Config for Runtime { type Block = Block; type Version = Version; - type BlockHashCount = ConstU32<1024>; + // Use the account data from the balances pallet type AccountData = pallet_balances::AccountData<::Balance>; } +// Implements the types required for the balances pallet. #[derive_impl(pallet_balances::config_preludes::TestDefaultConfig)] impl pallet_balances::Config for Runtime { type AccountStore = System; } +// Implements the types required for the sudo pallet. #[derive_impl(pallet_sudo::config_preludes::TestDefaultConfig)] impl pallet_sudo::Config for Runtime {} +// Implements the types required for the sudo pallet. #[derive_impl(pallet_timestamp::config_preludes::TestDefaultConfig)] impl pallet_timestamp::Config for Runtime {} +// Implements the types required for the transaction payment pallet. #[derive_impl(pallet_transaction_payment::config_preludes::TestDefaultConfig)] impl pallet_transaction_payment::Config for Runtime { type OnChargeTransaction = pallet_transaction_payment::FungibleAdapter; + // Setting fee as independent of the weight of the extrinsic for demo purposes type WeightToFee = NoFee<::Balance>; + // Setting fee as fixed for any length of the call data for demo purposes type LengthToFee = FixedFee<1, ::Balance>; } +// Implements the types required for the template pallet. impl pallet_minimal_template::Config for Runtime {} type Block = frame::runtime::types_common::BlockOf; diff --git a/templates/minimal/src/lib.rs b/templates/minimal/src/lib.rs new file mode 100644 index 0000000000000000000000000000000000000000..68825d190bb2c0d7862cd8552c0fe211615ec60a --- /dev/null +++ b/templates/minimal/src/lib.rs @@ -0,0 +1,75 @@ +//! # Minimal Template +//! +//! This is a minimal template for creating a blockchain using the Polkadot SDK. +//! +//! ## Components +//! +//! The template consists of the following components: +//! +//! ### Node +//! +//! A minimal blockchain [`node`](`minimal_template_node`) that is capable of running a +//! runtime. It uses a simple chain specification, provides an option to choose Manual or +//! InstantSeal for consensus and exposes a few commands to interact with the node. +//! +//! ### Runtime +//! +//! A minimal [`runtime`](`minimal_template_runtime`) (or a state transition function) that +//! is capable of being run on the node. It is built using the [`FRAME`](`frame`) framework +//! that enables the composition of the core logic via separate modules called "pallets". +//! FRAME defines a complete DSL for building such pallets and the runtime itself. +//! +//! #### Transaction Fees +//! +//! The runtime charges a transaction fee for every transaction that is executed. The fee is +//! calculated based on the weight of the transaction (accouting for the execution time) and +//! length of the call data. Please refer to +//! [`benchmarking docs`](`polkadot_sdk_docs::reference_docs::frame_benchmarking_weight`) for +//! more information on how the weight is calculated. +//! +//! This template sets the fee as independent of the weight of the extrinsic and fixed for any +//! length of the call data for demo purposes. +//! +//! ### Pallet +//! +//! A minimal [`pallet`](`pallet_minimal_template`) that is built using FRAME. It is a unit of +//! encapsulated logic that has a clearly defined responsibility and can be linked to other pallets. +//! +//! ## Getting Started +//! +//! To get started with the template, follow the steps below: +//! +//! ### Build the Node +//! +//! Build the node using the following command: +//! +//! ```bash +//! cargo build -p minimal-template-node --release +//! ``` +//! +//! ### Run the Node +//! +//! Run the node using the following command: +//! +//! ```bash +//! ./target/release/minimal-template-node --dev +//! ``` +//! +//! ### CLI Options +//! +//! The node exposes a few options that can be used to interact with the node. To see the list of +//! available options, run the following command: +//! +//! ```bash +//! ./target/release/minimal-template-node --help +//! ``` +//! +//! #### Consensus Algorithm +//! +//! In order to run the node with a specific consensus algorithm, use the `--consensus` flag. For +//! example, to run the node with ManualSeal consensus with a block time of 5000ms, use the +//! following command: +//! +//! ```bash +//! ./target/release/minimal-template-node --dev --consensus manual-seal-5000 +//! ``` diff --git a/templates/parachain/node/Cargo.toml b/templates/parachain/node/Cargo.toml index 63267acdbca83fb7035b51bd100a1fd13ee2d8e7..6f7150829829ac1f06ca1de91f69f99e61497f8a 100644 --- a/templates/parachain/node/Cargo.toml +++ b/templates/parachain/node/Cargo.toml @@ -19,11 +19,12 @@ workspace = true [dependencies] clap = { version = "4.5.3", features = ["derive"] } log = { workspace = true, default-features = true } -codec = { package = "parity-scale-codec", version = "3.0.0" } +codec = { package = "parity-scale-codec", version = "3.6.12" } serde = { features = ["derive"], workspace = true, default-features = true } jsonrpsee = { version = "0.22", features = ["server"] } futures = "0.3.28" serde_json = { workspace = true, default-features = true } +docify = "0.2.8" # Local parachain-template-runtime = { path = "../runtime" } diff --git a/templates/parachain/node/src/chain_spec.rs b/templates/parachain/node/src/chain_spec.rs index 16c91865cdb4aa9ae3c5882652100f5ef56a988c..51710f1199c35abbf0e2971758803462a8522f03 100644 --- a/templates/parachain/node/src/chain_spec.rs +++ b/templates/parachain/node/src/chain_spec.rs @@ -22,11 +22,12 @@ pub fn get_from_seed(seed: &str) -> ::Pu /// The extensions for the [`ChainSpec`]. #[derive(Debug, Clone, PartialEq, Serialize, Deserialize, ChainSpecGroup, ChainSpecExtension)] -#[serde(deny_unknown_fields)] pub struct Extensions { /// The relay chain of the Parachain. + #[serde(alias = "relayChain", alias = "RelayChain")] pub relay_chain: String, /// The id of the Parachain. + #[serde(alias = "paraId", alias = "ParaId")] pub para_id: u32, } diff --git a/templates/parachain/node/src/service.rs b/templates/parachain/node/src/service.rs index 373df01b0c435d0a79092bb18460c3051b1f9519..ad4689c6e55dc7d9bb96e0390182d7e7c8bf1591 100644 --- a/templates/parachain/node/src/service.rs +++ b/templates/parachain/node/src/service.rs @@ -12,6 +12,7 @@ use parachain_template_runtime::{ // Cumulus Imports use cumulus_client_collator::service::CollatorService; +use cumulus_client_consensus_aura::collators::lookahead::{self as aura, Params as AuraParams}; use cumulus_client_consensus_common::ParachainBlockImport as TParachainBlockImport; use cumulus_client_consensus_proposer::Proposer; use cumulus_client_service::{ @@ -19,7 +20,10 @@ use cumulus_client_service::{ BuildNetworkParams, CollatorSybilResistance, DARecoveryProfile, ParachainHostFunctions, StartRelayChainTasksParams, }; -use cumulus_primitives_core::{relay_chain::CollatorPair, ParaId}; +use cumulus_primitives_core::{ + relay_chain::{CollatorPair, ValidationCode}, + ParaId, +}; use cumulus_relay_chain_interface::{OverseerHandle, RelayChainInterface}; // Substrate Imports @@ -35,6 +39,7 @@ use sc_transaction_pool_api::OffchainTransactionPoolFactory; use sp_keystore::KeystorePtr; use substrate_prometheus_endpoint::Registry; +#[docify::export(wasm_executor)] type ParachainExecutor = WasmExecutor; type ParachainClient = TFullClient; @@ -57,6 +62,7 @@ pub type Service = PartialComponents< /// /// Use this macro if you don't actually need the full service, but just the builder in order to /// be able to perform chain operations. +#[docify::export(component_instantiation)] pub fn new_partial(config: &Configuration) -> Result { let telemetry = config .telemetry_endpoints @@ -156,6 +162,7 @@ fn build_import_queue( fn start_consensus( client: Arc, + backend: Arc, block_import: ParachainBlockImport, prometheus_registry: Option<&Registry>, telemetry: Option, @@ -170,10 +177,6 @@ fn start_consensus( overseer_handle: OverseerHandle, announce_block: Arc>) + Send + Sync>, ) -> Result<(), sc_service::Error> { - use cumulus_client_consensus_aura::collators::basic::{ - self as basic_aura, Params as BasicAuraParams, - }; - let proposer_factory = sc_basic_authorship::ProposerFactory::with_proof_recording( task_manager.spawn_handle(), client.clone(), @@ -191,11 +194,15 @@ fn start_consensus( client.clone(), ); - let params = BasicAuraParams { + let params = AuraParams { create_inherent_data_providers: move |_, ()| async move { Ok(()) }, block_import, - para_client: client, + 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, @@ -204,13 +211,12 @@ fn start_consensus( relay_chain_slot_duration, proposer, collator_service, - // Very limited proposal time. - authoring_duration: Duration::from_millis(500), - collation_request_receiver: None, + authoring_duration: Duration::from_millis(2000), + reinitialize: false, }; let fut = - basic_aura::run::( + aura::run::( params, ); task_manager.spawn_essential_handle().spawn("aura", None, fut); @@ -318,8 +324,8 @@ pub async fn start_parachain_node( task_manager: &mut task_manager, config: parachain_config, keystore: params.keystore_container.keystore(), - backend, - network: network.clone(), + backend: backend.clone(), + network, sync_service: sync_service.clone(), system_rpc_tx, tx_handler_controller, @@ -382,13 +388,14 @@ pub async fn start_parachain_node( if validator { start_consensus( client.clone(), + backend, block_import, prometheus_registry.as_ref(), telemetry.as_ref().map(|t| t.handle()), &task_manager, - relay_chain_interface.clone(), + relay_chain_interface, transaction_pool, - sync_service.clone(), + sync_service, params.keystore_container.keystore(), relay_chain_slot_duration, para_id, diff --git a/templates/parachain/pallets/template/Cargo.toml b/templates/parachain/pallets/template/Cargo.toml index 199da2f12d2c691ba6d51d009c6b20734b1c4c46..c5334e871fa4967bff0ae2259a7fe6a8066d9a33 100644 --- a/templates/parachain/pallets/template/Cargo.toml +++ b/templates/parachain/pallets/template/Cargo.toml @@ -16,7 +16,7 @@ workspace = true targets = ["x86_64-unknown-linux-gnu"] [dependencies] -codec = { package = "parity-scale-codec", version = "3.6.1", default-features = false, features = [ +codec = { package = "parity-scale-codec", version = "3.6.12", default-features = false, features = [ "derive", ] } scale-info = { version = "2.11.1", default-features = false, features = [ diff --git a/templates/parachain/runtime/Cargo.toml b/templates/parachain/runtime/Cargo.toml index 0d985796a11e880123f9b7ca71bf123fe1b48184..74b82f06e3ac0a2b9c125524ceade259eac1462e 100644 --- a/templates/parachain/runtime/Cargo.toml +++ b/templates/parachain/runtime/Cargo.toml @@ -19,7 +19,7 @@ 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 = [ +codec = { package = "parity-scale-codec", version = "3.6.12", default-features = false, features = [ "derive", ] } hex-literal = { version = "0.4.1", optional = true } @@ -28,6 +28,7 @@ scale-info = { version = "2.11.1", default-features = false, features = [ "derive", ] } smallvec = "1.11.0" +docify = "0.2.8" # Local pallet-parachain-template = { path = "../pallets/template", default-features = false } @@ -82,6 +83,7 @@ cumulus-pallet-parachain-system = { path = "../../../cumulus/pallets/parachain-s 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-aura = { path = "../../../cumulus/primitives/aura", 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 } @@ -98,6 +100,7 @@ std = [ "cumulus-pallet-session-benchmarking/std", "cumulus-pallet-xcm/std", "cumulus-pallet-xcmp-queue/std", + "cumulus-primitives-aura/std", "cumulus-primitives-core/std", "cumulus-primitives-storage-weight-reclaim/std", "cumulus-primitives-utility/std", diff --git a/templates/parachain/runtime/build.rs b/templates/parachain/runtime/build.rs index 02d6973f29cf4e48691247d8ee02b500d540c4f5..bb05afe02b1fc526d1c7a2c64514e7f25f33c7be 100644 --- a/templates/parachain/runtime/build.rs +++ b/templates/parachain/runtime/build.rs @@ -1,10 +1,6 @@ #[cfg(feature = "std")] fn main() { - substrate_wasm_builder::WasmBuilder::new() - .with_current_project() - .export_heap_base() - .import_memory() - .build() + substrate_wasm_builder::WasmBuilder::build_using_defaults(); } /// The wasm builder is deactivated when compiling diff --git a/templates/parachain/runtime/src/apis.rs b/templates/parachain/runtime/src/apis.rs index b13ba278fae607c9e585ad04618d1651293436e1..107956ded410464757c767b81d1ac88da9aba1a4 100644 --- a/templates/parachain/runtime/src/apis.rs +++ b/templates/parachain/runtime/src/apis.rs @@ -42,14 +42,15 @@ use sp_version::RuntimeVersion; // Local module imports use super::{ - AccountId, Aura, Balance, Block, Executive, InherentDataExt, Nonce, ParachainSystem, Runtime, - RuntimeCall, RuntimeGenesisConfig, SessionKeys, System, TransactionPayment, VERSION, + AccountId, Balance, Block, ConsensusHook, Executive, InherentDataExt, Nonce, ParachainSystem, + Runtime, RuntimeCall, RuntimeGenesisConfig, SessionKeys, System, TransactionPayment, + SLOT_DURATION, VERSION, }; impl_runtime_apis! { impl sp_consensus_aura::AuraApi for Runtime { fn slot_duration() -> sp_consensus_aura::SlotDuration { - sp_consensus_aura::SlotDuration::from_millis(Aura::slot_duration()) + sp_consensus_aura::SlotDuration::from_millis(SLOT_DURATION) } fn authorities() -> Vec { @@ -57,6 +58,15 @@ impl_runtime_apis! { } } + impl cumulus_primitives_aura::AuraUnincludedSegmentApi for Runtime { + fn can_build_upon( + included_hash: ::Hash, + slot: cumulus_primitives_aura::Slot, + ) -> bool { + ConsensusHook::can_build_upon(included_hash, slot) + } + } + impl sp_api::Core for Runtime { fn version() -> RuntimeVersion { VERSION diff --git a/templates/parachain/runtime/src/configs/mod.rs b/templates/parachain/runtime/src/configs/mod.rs index f1aea481ee277c5b753452bab315175cb4afb741..63e6a67a90638266820bce44e8aee75a544681bc 100644 --- a/templates/parachain/runtime/src/configs/mod.rs +++ b/templates/parachain/runtime/src/configs/mod.rs @@ -26,7 +26,7 @@ mod xcm_config; // Substrate and Polkadot dependencies -use cumulus_pallet_parachain_system::RelayNumberStrictlyIncreases; +use cumulus_pallet_parachain_system::RelayNumberMonotonicallyIncreases; use cumulus_primitives_core::{AggregateMessageOrigin, ParaId}; use frame_support::{ derive_impl, @@ -53,12 +53,11 @@ use xcm::latest::prelude::BodyId; // Local module imports use super::{ weights::{BlockExecutionWeight, ExtrinsicBaseWeight, RocksDbWeight}, - AccountId, Aura, Balance, Balances, Block, BlockNumber, CollatorSelection, Hash, MessageQueue, - Nonce, PalletInfo, ParachainSystem, Runtime, RuntimeCall, RuntimeEvent, RuntimeFreezeReason, - RuntimeHoldReason, RuntimeOrigin, RuntimeTask, Session, SessionKeys, System, WeightToFee, - XcmpQueue, AVERAGE_ON_INITIALIZE_RATIO, BLOCK_PROCESSING_VELOCITY, EXISTENTIAL_DEPOSIT, HOURS, - MAXIMUM_BLOCK_WEIGHT, MICROUNIT, NORMAL_DISPATCH_RATIO, RELAY_CHAIN_SLOT_DURATION_MILLIS, - SLOT_DURATION, UNINCLUDED_SEGMENT_CAPACITY, VERSION, + AccountId, Aura, Balance, Balances, Block, BlockNumber, CollatorSelection, ConsensusHook, Hash, + MessageQueue, Nonce, PalletInfo, ParachainSystem, Runtime, RuntimeCall, RuntimeEvent, + RuntimeFreezeReason, RuntimeHoldReason, RuntimeOrigin, RuntimeTask, Session, SessionKeys, + System, WeightToFee, XcmpQueue, AVERAGE_ON_INITIALIZE_RATIO, EXISTENTIAL_DEPOSIT, HOURS, + MAXIMUM_BLOCK_WEIGHT, MICROUNIT, NORMAL_DISPATCH_RATIO, SLOT_DURATION, VERSION, }; use xcm_config::{RelayLocation, XcmOriginToTransactDispatchOrigin}; @@ -128,7 +127,7 @@ impl pallet_timestamp::Config for Runtime { /// A timestamp: milliseconds since the unix epoch. type Moment = u64; type OnTimestampSet = Aura; - type MinimumPeriod = ConstU64<{ SLOT_DURATION / 2 }>; + type MinimumPeriod = ConstU64<0>; type WeightInfo = (); } @@ -195,13 +194,8 @@ impl cumulus_pallet_parachain_system::Config for Runtime { type ReservedDmpWeight = ReservedDmpWeight; type XcmpMessageHandler = XcmpQueue; type ReservedXcmpWeight = ReservedXcmpWeight; - type CheckAssociatedRelayNumber = RelayNumberStrictlyIncreases; - type ConsensusHook = cumulus_pallet_aura_ext::FixedVelocityConsensusHook< - Runtime, - RELAY_CHAIN_SLOT_DURATION_MILLIS, - BLOCK_PROCESSING_VELOCITY, - UNINCLUDED_SEGMENT_CAPACITY, - >; + type CheckAssociatedRelayNumber = RelayNumberMonotonicallyIncreases; + type ConsensusHook = ConsensusHook; } impl parachain_info::Config for Runtime {} @@ -227,7 +221,7 @@ impl pallet_message_queue::Config for Runtime { // The XCMP queue pallet is only ever able to handle the `Sibling(ParaId)` origin: type QueueChangeHandler = NarrowOriginToSibling; type QueuePausedQuery = NarrowOriginToSibling; - type HeapSize = sp_core::ConstU32<{ 64 * 1024 }>; + type HeapSize = sp_core::ConstU32<{ 103 * 1024 }>; type MaxStale = sp_core::ConstU32<8>; type ServiceWeight = MessageQueueServiceWeight; type IdleMaxServiceWeight = (); @@ -242,6 +236,8 @@ impl cumulus_pallet_xcmp_queue::Config for Runtime { // Enqueue XCMP messages from siblings for later processing. type XcmpQueue = TransformOrigin; type MaxInboundSuspended = sp_core::ConstU32<1_000>; + type MaxActiveOutboundChannels = ConstU32<128>; + type MaxPageSize = ConstU32<{ 1 << 16 }>; type ControllerOrigin = EnsureRoot; type ControllerOriginConverter = XcmOriginToTransactDispatchOrigin; type WeightInfo = (); @@ -271,8 +267,8 @@ impl pallet_aura::Config for Runtime { type AuthorityId = AuraId; type DisabledValidators = (); type MaxAuthorities = ConstU32<100_000>; - type AllowMultipleBlocksPerSlot = ConstBool; - type SlotDuration = pallet_aura::MinimumPeriodTimesTwo; + type AllowMultipleBlocksPerSlot = ConstBool; + type SlotDuration = ConstU64; } parameter_types! { diff --git a/templates/parachain/runtime/src/configs/xcm_config.rs b/templates/parachain/runtime/src/configs/xcm_config.rs index 13da2363b053467ab02c689dfc14ee67118f543e..e162bcbf88686c00ea10dc9b06c985329faa763b 100644 --- a/templates/parachain/runtime/src/configs/xcm_config.rs +++ b/templates/parachain/runtime/src/configs/xcm_config.rs @@ -26,6 +26,8 @@ parameter_types! { pub const RelayLocation: Location = Location::parent(); pub const RelayNetwork: Option = None; pub RelayChainOrigin: RuntimeOrigin = cumulus_pallet_xcm::Origin::Relay.into(); + // For the real deployment, it is recommended to set `RelayNetwork` according to the relay chain + // and prepend `UniversalLocation` with `GlobalConsensus(RelayNetwork::get())`. pub UniversalLocation: InteriorLocation = Parachain(ParachainInfo::parachain_id().into()).into(); } @@ -140,6 +142,7 @@ impl xcm_executor::Config for XcmConfig { type HrmpNewChannelOpenRequestHandler = (); type HrmpChannelAcceptedHandler = (); type HrmpChannelClosingHandler = (); + type XcmRecorder = PolkadotXcm; } /// No local origins on this chain are allowed to dispatch XCM sends/executions. diff --git a/templates/parachain/runtime/src/lib.rs b/templates/parachain/runtime/src/lib.rs index 5bfd6f290c1b9839f4e19c0c21984f258512dd37..179a425ca04165a53ab3c14caaeeb638adb358b0 100644 --- a/templates/parachain/runtime/src/lib.rs +++ b/templates/parachain/runtime/src/lib.rs @@ -75,6 +75,7 @@ pub type SignedBlock = generic::SignedBlock; pub type BlockId = generic::BlockId; /// The SignedExtension to the basic transaction logic. +#[docify::export(template_signed_extra)] pub type SignedExtra = ( frame_system::CheckNonZeroSender, frame_system::CheckSpecVersion, @@ -173,7 +174,7 @@ pub const VERSION: RuntimeVersion = RuntimeVersion { /// up by `pallet_aura` to implement `fn slot_duration()`. /// /// Change this to adjust the block time. -pub const MILLISECS_PER_BLOCK: u64 = 12000; +pub const MILLISECS_PER_BLOCK: u64 = 6000; // NOTE: Currently it is not possible to change the slot duration after the chain has started. // Attempting to do so will brick block production. @@ -200,21 +201,29 @@ const AVERAGE_ON_INITIALIZE_RATIO: Perbill = Perbill::from_percent(5); /// `Operational` extrinsics. const NORMAL_DISPATCH_RATIO: Perbill = Perbill::from_percent(75); -/// We allow for 0.5 of a second of compute with a 12 second average block time. +/// We allow for 2 seconds of compute with a 6 second average block time. const MAXIMUM_BLOCK_WEIGHT: Weight = Weight::from_parts( - WEIGHT_REF_TIME_PER_SECOND.saturating_div(2), + WEIGHT_REF_TIME_PER_SECOND.saturating_mul(2), cumulus_primitives_core::relay_chain::MAX_POV_SIZE as u64, ); /// Maximum number of blocks simultaneously accepted by the Runtime, not yet included /// into the relay chain. -const UNINCLUDED_SEGMENT_CAPACITY: u32 = 1; +const UNINCLUDED_SEGMENT_CAPACITY: u32 = 3; /// How many parachain blocks are processed by the relay chain per parent. Limits the /// number of blocks authored per slot. const BLOCK_PROCESSING_VELOCITY: u32 = 1; /// Relay chain slot duration, in milliseconds. const RELAY_CHAIN_SLOT_DURATION_MILLIS: u32 = 6000; +/// Aura consensus hook +type ConsensusHook = cumulus_pallet_aura_ext::FixedVelocityConsensusHook< + Runtime, + RELAY_CHAIN_SLOT_DURATION_MILLIS, + BLOCK_PROCESSING_VELOCITY, + UNINCLUDED_SEGMENT_CAPACITY, +>; + /// The version information used to identify this runtime when compiled natively. #[cfg(feature = "std")] pub fn native_version() -> NativeVersion { diff --git a/templates/solochain/README.md b/templates/solochain/README.md index 6390c9524ce185f7cda7679b874f532694d34a0b..37c65797dcb00a8aed0a4f4566eaaacab37c8359 100644 --- a/templates/solochain/README.md +++ b/templates/solochain/README.md @@ -4,10 +4,10 @@ A fresh [Substrate](https://substrate.io/) node, ready for hacking :rocket: A standalone version of this template is available for each release of Polkadot in the [Substrate Developer Hub Parachain -Template](https://github.com/substrate-developer-hub/substrate-parachain-template/) +Template](https://github.com/substrate-developer-hub/substrate-node-template/) repository. The parachain template is generated directly at each Polkadot -release branch from the [Node Template in -Substrate](https://github.com/paritytech/polkadot-sdk/tree/master/substrate/bin/node-template) +release branch from the [Solochain Template in +Substrate](https://github.com/paritytech/polkadot-sdk/tree/master/templates/solochain) upstream It is usually best to use the stand-alone version to start a new project. All diff --git a/templates/solochain/pallets/template/Cargo.toml b/templates/solochain/pallets/template/Cargo.toml index 24519f1d22e0d214e418974de65c7f77588498c4..1a122bd82d40c7f28c468140e842310c2f45f128 100644 --- a/templates/solochain/pallets/template/Cargo.toml +++ b/templates/solochain/pallets/template/Cargo.toml @@ -16,7 +16,7 @@ workspace = true targets = ["x86_64-unknown-linux-gnu"] [dependencies] -codec = { package = "parity-scale-codec", version = "3.6.1", default-features = false, features = [ +codec = { package = "parity-scale-codec", version = "3.6.12", default-features = false, features = [ "derive", ] } scale-info = { version = "2.11.1", default-features = false, features = [ diff --git a/templates/solochain/runtime/Cargo.toml b/templates/solochain/runtime/Cargo.toml index 7a81f192043f5bc516ca774e1cebf8c039f06ceb..b4a543826e793ffe16c0383985b1b8101bab4a01 100644 --- a/templates/solochain/runtime/Cargo.toml +++ b/templates/solochain/runtime/Cargo.toml @@ -16,7 +16,7 @@ workspace = true targets = ["x86_64-unknown-linux-gnu"] [dependencies] -codec = { package = "parity-scale-codec", version = "3.6.1", default-features = false, features = [ +codec = { package = "parity-scale-codec", version = "3.6.12", default-features = false, features = [ "derive", ] } scale-info = { version = "2.11.1", default-features = false, features = [ diff --git a/templates/solochain/runtime/build.rs b/templates/solochain/runtime/build.rs index c03d618535be03e94d4d48aacfedb674847e4646..f262c320393bf29ab0d54151803ca8b91d8e451b 100644 --- a/templates/solochain/runtime/build.rs +++ b/templates/solochain/runtime/build.rs @@ -1,10 +1,6 @@ fn main() { #[cfg(feature = "std")] { - substrate_wasm_builder::WasmBuilder::new() - .with_current_project() - .export_heap_base() - .import_memory() - .build(); + substrate_wasm_builder::WasmBuilder::build_using_defaults(); } }